他是一个合成注解,等同于:@Component, @SpringbootConfiguration, @EnableAutoConfiguration
package com.meimeixia.boot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
/**
* @author liayun
* @create 2021-04-19 4:02
*/
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.meimeixia.boot")
public class MainApplication {
public static void main(String[] args) {
// 1. 返回IoC容器,IoC容器里面就包含了当前应用的所有组件
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args); // 这是固定写法哟
// 2. 我们可以来查看下IoC容器里面所有的组件,只要能查找到某一个组件,就说明这个组件是能工作的,至于怎么工作,这就是我们后来要阐述的原理了
String[] names = run.getBeanDefinitionNames(); // 获取所有组件定义的名字
for (String name : names) {
System.out.println(name);
}
}
}
springboot默认会扫描主程序类所在的包, 如果想要修改扫描包的路径,可以通过@SpringbootApplication(scanBasePacage=" ")来修改;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MN0Yg3No-1682653973354)(C:\Users\coder\AppData\Roaming\Typora\typora-user-images\1660924829635.png)]
1、这个注解是用来代替以前的配置文件的,被这个注解标注的类,这个类是一个配置类。同时由这个注解标注的该类本身也是一个组件
package com.meimeixia.boot.config;
import org.springframework.context.annotation.Configuration;
/**
* @author liayun
* @create 2021-04-23 19:42
*
*/
@Configuration // 告诉Spring Boot这是一个配置类 == 配置文件
public class MyConfig {
}
2、这个注解有一个很重要的属性:proxyBeanMethods
这个属性默认配置为true:表示当我们在外面调用该方法的时候,spring会先去容器中检查是否已经存在了该组件,如果存在了,直接取出来,如果不存在,则执行该方法新创一个组件放入容器中。
这个属性如果配置为false:则我们在外面调用这个方法的时候,spring就不会去检查容器中是否已经存在了这个组件,会直接重新新建一个。所以配置为false的时候速度快。
这个注解是用来给容器中注册第三方的组件的(也就是实例化的对象),
一般和@Configuration注解组合使用
package com.meimeixia.boot.config;
import com.meimeixia.boot.bean.Pet;
import com.meimeixia.boot.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author liayun
* @create 2021-04-23 19:42
*。
*/
@Configuration // 告诉Spring Boot这是一个配置类 == 配置文件
public class MyConfig {
@Bean // @Bean注解是给容器中添加组件的。添加什么组件呢?以方法名作为组件的id,返回类型就是组件类型,返回的值就是组件在容器中的实例
public User user01() {
User zhangsan = new User("zhangsan", 18);
return zhangsan;
}
@Bean
public Pet tomcatPet() {
return new Pet("tomcat");
}
}
该注解也是用来给容器中注入某一个特定的组件的,里面属性放的都类所对应的class对象。放入到容器中的组件的名字默认是全类名。
package com.meimeixia.boot.config;
import ch.qos.logback.core.db.DBHelper;
import com.meimeixia.boot.bean.Pet;
import com.meimeixia.boot.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* @author liayun
* @create 2021-04-23 19:42
*
*/
@Import({User.class, DBHelper.class}) // 这时,就会给容器中自动创建出这两个类型的组件了
@Configuration(proxyBeanMethods = true) // 告诉Spring Boot这是一个配置类 == 配置文件
public class MyConfig {
@Bean // @Bean注解是给容器中添加组件的。添加什么组件呢?以方法名作为组件的id,返回类型就是组件类型,返回的值就是组件在容器中的实例
public User user01() {
User zhangsan = new User("zhangsan", 18);
// User类型的组件依赖了Pet类型的组件
zhangsan.setPet(tomcatPet());
return zhangsan;
}
@Bean("tom")
public Pet tomcatPet() {
return new Pet("tomcat");
}
}
该注解表示:当满足什么条件的时候,才会往容器中注入组件。
package com.meimeixia.boot.config;
import ch.qos.logback.core.db.DBHelper;
import com.meimeixia.boot.bean.Pet;
import com.meimeixia.boot.bean.User;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* @author liayun
* @create 2021-04-23 19:42
*
*/
@Import({User.class, DBHelper.class}) // 这时,就会给容器中自动创建出这两个类型的组件了
@Configuration(proxyBeanMethods = true) // 告诉Spring Boot这是一个配置类 == 配置文件
//@ConditionalOnBean(name = "tom")------>表示满足条件的时候,这个类下面的所有配置才会生效
public class MyConfig {
@ConditionalOnBean(name = "tom")
@Bean // @Bean注解是给容器中添加组件的。添加什么组件呢?以方法名作为组件的id,返回类型就是组件类型,返回的值就是组件在容器中的实例
public User user01() {
User zhangsan = new User("zhangsan", 18);
// User类型的组件依赖了Pet类型的组件
zhangsan.setPet(tomcatPet());
return zhangsan;
}
// @Bean("tom")
public Pet tomcatPet() {
return new Pet("tomcat");
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MFeZ3PUA-1682653973355)(C:\Users\coder\AppData\Roaming\Typora\typora-user-images\1660926486960.png)]
这个注解是用来导入一个配置文件的,属性里放的是配置文件的绝对路径
package com.meimeixia.boot.config;
import ch.qos.logback.core.db.DBHelper;
import com.meimeixia.boot.bean.Pet;
import com.meimeixia.boot.bean.User;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportResource;
/**
* @author liayun
* @create 2021-04-23 19:42
*
*/
@Import({User.class, DBHelper.class}) // 这时,就会给容器中自动创建出这两个类型的组件了
@Configuration(proxyBeanMethods = true) // 告诉Spring Boot这是一个配置类 == 配置文件
//@ConditionalOnBean(name = "tom")
@ConditionalOnMissingBean(name = "tom")
@ImportResource("classpath:beans.xml")
public class MyConfig {
@Bean // @Bean注解是给容器中添加组件的。添加什么组件呢?以方法名作为组件的id,返回类型就是组件类型,返回的值就是组件在容器中的实例
public User user01() {
User zhangsan = new User("zhangsan", 18);
// User类型的组件依赖了Pet类型的组件
zhangsan.setPet(tomcatPet());
return zhangsan;
}
// @Bean("tom")
@Bean("tom666")
public Pet tomcatPet() {
return new Pet("tomcat");
}
}
这个注解是用来指定该类的所有方法的返回值全部以json字符串的形式返回。
@RestController注解相当于@ResponseBody + @Controller合在一起的作用;
如果只是使用@RestController注解Controller控制器,则Controller中的方法无法返回jsp页面,配置的视图解析器InternalResourceViewResolver不起作用,返回的内容就是Return 里的内容。例如:本来应该到success.jsp页面的,则其显示success;
如果需要返回到指定页面,则需要用 @Controller配合视图解析器InternalResourceViewResolver才行;
如果需要返回JSON、XML或自定义mediaType内容到页面,则需要在对应的方法上加上@ResponseBody注解。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WBs9En3x-1682653973355)(C:\Users\coder\AppData\Roaming\Typora\typora-user-images\1660965727555.png)]
这个注解用于标注在方法上,让这个方法的返回值以json字符串的形式返回,表示当前处理器响应内容为当前返回值,无需解析器解析。凡是该方法上没有标注这个注解的,则该处理器的响应(即返回值),会被视图解析器解析,跳转到页面。
这个注解标注在类上,表示会自动提供类的get, set, equals, hashcode, toString方法。
这个注解标注在类上,表示提供类的全参构造
这个注解标注在类上,表示会提供类的无参构造
这两个注解标注在属性上,表示分别会提供对应的get, set方法
这两个注解标注在类上, 表示自动提供Logger对象,变量名为log。默认的日志级别是Info。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iTlB2TPN-1682653973355)(C:\Users\coder\AppData\Roaming\Typora\typora-user-images\1660966778642.png)]
该方法有对应的日志输出方法:
log.debug(“debug”);
log.info(“info”);
log.err(“error”);
log.warn(“warn”);
标注在组件类上使用,一定要有组件注解!
@Data //get/set方法
@AllArgsConstructor //全参构造
@NoArgsConstructor //无参构造
@Component("car") //组件注册, 必须有组件注册手段
@ConfigurationProperties(prefix = "mycar")
public class Car {
private String brand; //品牌
}
**标注在方法上使用 **
@Configuration
public class MyConfig {
@Bean("deepSkyBlue")
@ConfigurationProperties(prefix = "color")
public DeepSkyBlue deepSkyBlue(){
return new DeepSkyBlue();
}
}
可以看到上面的配置绑定@ConfigurationProperties注解需要使用@Component组件注解进行注册才能进行绑定,如果是写好的第三方包呢?那么没有办法给第三方包加入的时候可以使用使用方法标记进行配置绑定或者@EnableConfigurationProperties注解进行自动注册
@Data //get/set方法
@AllArgsConstructor //全参构造
@NoArgsConstructor //无参构造
@ConfigurationProperties(prefix = "mycar")
public class Car {
private String price;
private String brand;
}
@Configuration
@EnableConfigurationProperties(value = {Car.class}) //自动配置绑定
public class MyConfig {
@Bean("deepSkyBlue")
@ConfigurationProperties(prefix = "color")
public DeepSkyBlue deepSkyBlue(){
return new DeepSkyBlue();
}
}
注意:
这个注解是告诉spring这是一个异步方法
//告诉Spring这是一个异步方法
@Async
public void hello(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("业务进行中....");
}
SpringBoot就会自己开一个线程池,进行调用!但是要让这个注解生效,我们还需要在主程序上添加一个注解@EnableAsync ,开启异步注解功能;
@EnableAsync //开启异步注解功能
@SpringBootApplication
public class SpringbootTaskApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootTaskApplication.class, args);
}
}
@Service
public class ScheduledService {
//秒 分 时 日 月 周几
//0 * * * * MON-FRI
//注意cron表达式的用法;
@Scheduled(cron = "0 * * * * 0-7")
public void hello(){
System.out.println("hello.....");
}
}
这里写完定时任务之后,我们需要在主程序上增加@EnableScheduling 开启定时任务功能
@EnableAsync //开启异步注解功能
@EnableScheduling //开启基于注解的定时任务
@SpringBootApplication
public class SpringbootTaskApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootTaskApplication.class, args);
}
}
该注解是一个用来标注属性的注解。
它包含以下属性:
name-重写属性名
value-属性的中文描述
dataType-重写属性类型
required-是否必须
example-举例说明
hidden-隐藏
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AGiSrryE-1682653973355)(C:\Users\coder\AppData\Roaming\Typora\typora-user-images\1661091802225.png)]
SpringBoot中使用事务非常简单,首先使用注解@EnableTransactionManagemen开启事务支持后, 然后在访问数据库的service方法上添加注解@Transaction注解即可。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jtYncAab-1682653973356)(C:\Users\coder\AppData\Roaming\Typora\typora-user-images\1661092430037.png)]
这个注解的作用是:对该方法或者该接口所有的实现类,加上Spring事务, 表示一旦出现异常,就要么全部执行,要么回滚全部不执行。
@Transactional
的作用范围方法 :推荐将注解使用于方法上,不过需要注意的是:该注解只能应用到 public 方法上,否则不生效。
类 :如果这个注解使用在接口(类也可以,但一般都加在接口上)上的话,表明该注解对该类中所有的 public 方法都生效。
接口 :不推荐在接口上使用。
@Transactional 的常用配置参数总结(只列出了 5 个我平时比较常用的):
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S4II44ax-1682653973356)(C:\Users\coder\AppData\Roaming\Typora\typora-user-images\1661093517978.png)]
/*@Transactional 事务注解原理
面试中在问 AOP 的时候可能会被问到的一个问题。简单说下吧!
我们知道,@Transactional 的工作机制是基于 AOP 实现的,AOP 又是使用动态代理实现的。如果目标对象实现了接口,默认情况下会采用 JDK 的动态代理,如果目标对象没有实现了接口,会使用 CGLIB 动态代理。
如果一个类或者一个类中的 public 方法上被标注@Transactional 注解的话,Spring 容器就会在启动的时候为其创建一个代理类,在调用被@Transactional 注解的 public 方法的时候,实际调用的是,TransactionInterceptor 类中的 invoke()方法。这个方法的作用就是在目标方法之前开启事务,方法执行过程中如果遇到异常的时候回滚事务,方法调用完成之后提交事务。
TransactionInterceptor 类中的 invoke()方法内部实际调用的是 TransactionAspectSupport 类的 invokeWithinTransaction()方法。*/
@Transactional 的使用注意事项总结
@Transactional 注解只有作用到 public 方法上事务才生效,不推荐在接口上使用;
避免同一个类中调用 @Transactional 注解的方法,这样会导致事务失效;
正确的设置 @Transactional 的 rollbackFor 和 propagation 属性,否则事务可能会回滚失败;
@Transactional 注解的方法所在的类必须被 Spring 管理,否则不生效;
底层使用的数据库必须支持事务机制,否则不生效;
这是一个增强的 Controller。使用这个 Controller ,可以实现三个方面的功能:
1.全局异常处理:@ExceptionHandler(Exception.class):设置指定异常的处理方案,功能等同于控制器方法,出现异常后终止原控制器执行,并转入该方法执行;
2.全局数据绑定: @ModelAttribute(name = “md”)
3.全局数据预处理
1.全局异常处理
使用 @ControllerAdvice 实现全局异常处理,只需要定义类,添加该注解即可定义方式如下:
@ControllerAdvice
public class MyGlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ModelAndView customException(Exception e) {
ModelAndView mv = new ModelAndView();
mv.addObject("message", e.getMessage());
mv.setViewName("myerror");
return mv;
}
}
@ExceptionHandler 注解用来指明异常的处理类型,即如果这里指定为 NullpointerException,则数组越界异常就不会进到这个方法中来。
2.全局数据绑定
全局数据绑定功能可以用来做一些初始化的数据操作,我们可以将一些公共的数据定义在添加了 @ControllerAdvice 注解的类中,这样,在每一个 Controller 的接口中,就都能够访问导致这些数据。
@ControllerAdvice
public class MyGlobalExceptionHandler {
@ModelAttribute(name = "md")
public Mapmydata() {
HashMapmap = new HashMap<>();
map.put("age", 99);
map.put("gender", "男");
return map;
}
}
使用 @ModelAttribute 注解标记该方法的返回数据是一个全局数据,默认情况下,这个全局数据的 key 就是返回的变量名,value 就是方法返回值,当然开发者可以通过 @ModelAttribute 注解的 name 属性去重新指定 key。
定义完成后,在任何一个Controller 的接口中,都可以获取到这里定义的数据:
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello(Model model) {
Mapmap = model.asMap();
System.out.println(map);
}
}
3.全局数据预处理
考虑我有两个实体类,Book 和 Author,分别定义如下:
public class Book {
private String name;
private Long price;
//getter/setter
}
public class Author {
private String name;
private Integer age;
//getter/setter
}
此时,如果我定义一个数据添加接口,如下:
@PostMapping("/book")
public void addBook(Book book, Author author) {
System.out.println(book);
System.out.println(author);
}
这个时候,添加操作就会有问题,因为两个实体类都有一个 name 属性,从前端传递时 ,无法区分。此时,通过 @ControllerAdvice 的全局数据预处理可以解决这个问题
解决步骤如下:
1.给接口中的变量取别名
@PostMapping("/book")
public void addBook(@ModelAttribute("b") Book book, @ModelAttribute("a") Author author) {
System.out.println(book);
System.out.println(author);
}
2.进行请求数据预处理
在 @ControllerAdvice 标记的类中添加如下代码:
@InitBinder("b")
public void b(WebDataBinder binder) {
binder.setFieldDefaultPrefix("b.");
}
@InitBinder("a")
public void a(WebDataBinder binder) {
binder.setFieldDefaultPrefix("a.");
}
@InitBinder(“b”) 注解表示该方法用来处理和Book和相关的参数,在方法中,给参数添加一个 b 前缀,即请求参数要有b前缀.
一 简介
首先@ApiOperation注解不是Spring自带的,它是是swagger里的
注解@ApiOperation是用来构建Api文档的
@ApiOperation(value = “接口说明”, httpMethod = “接口请求方式”, response =
“接口返回参数类型”, notes = “接口发布说明”;其他参数可参考源码;
用来把自己实现的组件放入到容器里面去。
@Scope(“singleton”) :表示该类是采用单例模式
@Scope(“prototype”):表示该类不是单例模式
表示该方法是在构造方法后执行
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XwHLYHze-1682653973356)(C:\Users\coder\AppData\Roaming\Typora\typora-user-images\1661159859559.png)]
表示该方法实在销毁方法前执行
该注解表示按照类型自动装配类对象,放在属性上面。自动注入的一个注解。
自动装配默认使用无参构造方法来创建对象
该注解表示,如果自动注入的时候,不止匹配到了一个类,则采用这个注解来指定名称:@Qualifier(“bookDao”)
该注解用来简单类型的值注入,放在属性上面:@Value(“100”),这个注解和@ConfigurationProperities注解结合使用。
这个注解的真正作用是,它可以从配置文件中取值,然后赋予这个属性,通过EL表达式:@Value(“${name}”)
这个注解用来加载配置文件:@PropertySource(“classpath:jdbc.properties”)
如果要加载多个配置文件,用数组(也即是加上花括号):@PropertySource( {“classpath:jdbc.properties”})
该注解用于定义切入点:也就是告诉spring,拿些方法需要被增强。
例如:@PointCut(“execution(public void com.itheima.dao.BookDao.update() )”)
private void pt() {}
这样一写以后, pt()以后就代表这个切入点。
@Before(“pt()”)
这个注解标注在类上,是为了告诉Spring, 这个类是一个做AOP的类,因为Spring底层并未有单独为AOP做设置, 如果不加这个注解, Spring不知到这个类专门用来做AOP的,那就会把这个类当作一个普通bean类。一般被@Aspect注解标注了的这个类里面就是的方法就是被@PointCut和通知@Before, @After, @Around等等注解标注的方法。
这个注解一般写在配置类上,告诉Spring,我这里是用注解来开发AOP的,不然Spring不知道,那Spring就识别不出来@Aspect注解。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
//引入AspectJAutoProxyRegistrar
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
/**
* 表明该类采用CGLIB代理还是使用JDK的动态代理
*/
boolean proxyTargetClass() default false;
/**
* 解决内部调用不能使用代理的场景 默认为false表示不处理
* true则表示这个代理对象的副本就可以通过AopContext.currentProxy()获得(ThreadLocal里面),
* 从而我们可以很方便得在Spring框架上下文中拿到当前代理对象(处理事务时很方便)
*/
boolean exposeProxy() default false;
}
这四个注解用于Aop里面做方法增强,注解里面的属性放的是切点:例如:@Before(“pt()”)
这个注解写在方法上,用来设置当前控制器方法的请求访问路径: 如@RequestMapping(“/save”)
该注解是用来告诉Spring, 我们是用注解来开发事务驱动的,只有在配置文件上加上了这个注解, Spring才能识别@Transactional注解。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T9xyRmnd-1682653973356)(C:\Users\coder\AppData\Roaming\Typora\typora-user-images\1661145881411.png)]
这个注解接收的参数是来自于requestHeader中的,即请求头。如果前端使用非json格式数据请求的时候,后端就用这个注解接收参数。
当前端url送给过来的参数名和处理器方法形参名不一致的时候,比如@RequestParam(“name”),我们可以用这个注解放在形参前,表示告诉SpringMVC这个形参对应的是URL中名字为name的参数。
这个注解接收的参数是来自于requestBody中的,即请求体中的。如果前端使用json格式数据请求的时候,后端就用这个注解接收参数。
一般,前端以post格式发送的数据的话,就是以json格式传递的数据。
该注解用于接收前端送过来的日期格式的数据,将前端的数据格式转化为我们需要的格式。
前端:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xZYvZiXB-1682653973356)(C:\Users\coder\AppData\Roaming\Typora\typora-user-images\1661153008769.png)]
后端:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mo6YA2xG-1682653973356)(C:\Users\coder\AppData\Roaming\Typora\typora-user-images\1661153035185.png)]
这个注解用于接收RESTFUL风格(就是前端不再传问号,不再有key-value键值对,全部以斜杠/来划分)的前端参数, 这个注解写在形参前面
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-212pOfzJ-1682653973357)(C:\Users\coder\AppData\Roaming\Typora\typora-user-images\1661156052585.png)]
这四个注解写在方法上, 等同于@RequestMapping(method=“POST/GET/PUT/DELETE”)
这个注解写在配置类上,是用来扫描mapper接口所在的包,例如: @MapperScan(“com.atguigu.mybatisplus.mapper”)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p4EbAfft-1682653973357)(C:\Users\coder\AppData\Roaming\Typora\typora-user-images\1661166178095.png)]
@ApiModel
注解用于实体类,表示对类进行说明,用于参数用实体类接收。
@ApiModelProperty
注解用于类中属性,表示对 model
属性的说明或者数据操作更改。
@Api
注解用于类上,表示标识这个类是 swagger 的资源。
@ApiOperation
注解用于方法,表示一个 http 请求的操作。
@ApiParam
注解用于参数上,用来标明参数信息。
这个注解是来标识mapper接口中的方法参数,比如User getUserById(@Param(“id”) int id), 它会将这些参数放在map集合里,以@Param注解的value属性为键,以参数为值, 只需要在map.xml里通过#{}来访问map集合里面的键就可以获取到相应的值
(1):导入依赖··
org.springframework.boot
spring-boot-starter-data-redis
(2):在配置文件中配置redist连接
#指定redis信息 (如 host, ip, password)
spring.redis.host=localhost
spring.redis.port=6379
#没有密码可以不用配置这个
#spring.redis.password=123456
(3):使用redisTemplate操作redis服务器
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
public class RedisController {
/**
* 需要注入redis模板
*
* 对于RedisTemplate的泛型情况,
* 可以使用
*
@Resource
private RedisTemplate redisTemplate;
@Resource
private StringRedisTemplate stringRedisTemplate;
// 添加数据到redis
@PostMapping("/redis/addstring")
public String addToRedis(String name, String value) {
// 操作Redis中的string类型的数据,先获取ValueOperation
ValueOperations valueOperations = redisTemplate.opsForValue();
// 添加数据到redis
valueOperations.set(name, value);
return "向redis添加string类型的数据";
}
// 从redis获取数据
@GetMapping("/redis/getk")
public String getData(String key) {
ValueOperations valueOperations = redisTemplate.opsForValue();
Object v = valueOperations.get(key);
return "key是" + key + ",它的值是:" + v;
}
@PostMapping("/redis/{k}/{v}")
public String addStringKV(@PathVariable String k,
@PathVariable String v) {
// 使用StringRedisTemplate对象
stringRedisTemplate.opsForValue().set(k,v);
return "使用StringRedisTemplate对象添加";
}
@GetMapping("/redis/{k}")
public String getStringValue(@PathVariable String k) {
// 获取String类型的value
String v = stringRedisTemplate.opsForValue().get(k);
return "从redis中通过" + k + "获取到string类型的v=" + v;
}
}
redisTemplate对象有好几种,上面代码中给了两种:
一种为RedisTemplate,这种是有泛型的,泛型类型为
当我们使用StringRedisTemplate对象存取String类型的数据时,是没有乱码的。
StringRedisTemplate和RedisTemplate
上面说到了这两者在存取中的差异
StringRedisTemplate : 这个类将key和value都做String处理,使用的是String的序列化,可读性好
RedisTemplate : 把key和value经过了序列化,key和value都是序列化的内容,不能直接识别,默认使用的是JDK的序列化,可以修改为其他的序列化。
1、序列化的方式可以改变
/** 设置RedisTemplate序列化机制
* 可以设置 key 的序列化,也可以设置 value 的序列化
* 也可以同时设置
*/
@PostMapping("/redis/addstr")
public String addString(String k, String v) {
// 设置RedisTemplate的序列化机制
// 设置key为string类型的序列化
redisTemplate.setKeySerializer(new StringRedisSerializer());
// 设置value的序列化
redisTemplate.setValueSerializer(new StringRedisSerializer());
redisTemplate.opsForValue().set(k, v);
return "添加了k和v";
}
2、在方法中设置序列化方式
/**
* 使用json序列化
*/
@PostMapping("/redis/addjson")
public String addJson() {
Student student = new Student();
student.setName("zhangsan");
student.setAge(20);
student.setId(1);
// 设置key为string的序列化方式
redisTemplate.setKeySerializer(new StringRedisSerializer());
// 设置value为json的序列化方式,json为Student类型的方式组织,所以需要传入Student.class
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer(Student.class));
redisTemplate.opsForValue().set("myStudent", student);
return "存入json类型的数据student";
}
3、在方法中取出redis数据
常见的mp文件,和mybatis一样,要包括mapper文件夹,实体类文件夹dao/entity,然后要包括服务层文件夹service,然后这个service文件夹里面要包括服务层的接口,然后还要有impl实现接口的文件夹,每一个接口都要一个实现类。这是对于springboot的项目来说。
针对于mp来说,很特殊:首先服务层的接口必须要继承自mp提供的一个类:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZyIB2Eji-1682653973357)(C:\Users\coder\AppData\Roaming\Typora\typora-user-images\1681446959727.png)]
其次就是,这个接口的实现类,不仅要实现这个接口,还需要继承一个mp实现好的类:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DK5X5caL-1682653973357)(C:\Users\coder\AppData\Roaming\Typora\typora-user-images\1681447006019.png)]
然后就是mapper,映射类要继承自一个mp提供好的类:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-euMBsRBh-1682653973357)(C:\Users\coder\AppData\Roaming\Typora\typora-user-images\1681447059800.png)]
简单地解释:
@Bean
告诉Spring’这是此类的一个实例,请保留该类,并在我询问时将其还给我’。
@Autowired
说“请给我一个该类的实例,例如,我@Bean之前用注释创建的一个实例”。、
@Autowired会去spring容器里先按byType去找,如果没找到,则会按照byName去找
@Resource会先按byName去找,如果没找到则会byType去找。如果设置了name属性,则只会按byName去找,找不到就报错。
1、实现原理不同
拦截器是基于java的反射机制的,而过滤器是基于函数回调。
2、使用范围不同
过滤器 实现的是 javax.servlet.Filter 接口,而这个接口是在Servlet规范中定义的,也就是说过滤器Filter 的使用要依赖于Tomcat等容器,导致它只能在web程序中使用。
拦截器(Interceptor) 它是一个Spring组件,并由Spring容器管理,并不依赖Tomcat等容器,是可以单独使用的。不仅能应用在web程序中,也可以用于Application、Swing等程序中。
3、触发时机不同
过滤器Filter是在请求进入容器后,但在进入servlet之前进行预处理,请求结束是在servlet处理完以后。
拦截器 Interceptor 是在请求进入servlet后,在进入Controller之前进行预处理的,Controller 中渲染了对应的视图之后请求结束。
4、拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
5、在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
6、拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。拦截器可以获取ioc中的service bean实现业务逻辑。
在启动类加入@ServletComponentScan注解
使用@ServletComponentScan注解后,Servlet、Filter、Listener可以直接通过@WebServlet、@WebFilter、@WebListener注解自动注册。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eRnhsj9H-1682653973357)(C:\Users\coder\AppData\Roaming\Typora\typora-user-images\1681456867956.png)]
这个注解里面的annotation值放的是,这个全局处理器要处理写了哪些注解的controller层的异常。
1、@TableField(exist=false)
注解加载bean属性上,表示当前属性不是数据库的字段,但在项目中必须使用,这样在新增等使用bean的时候,mybatis-plus就会忽略这个,不会报错。
**2、 如果实体类的普通属性名,和数据库非主键的字段名不一致; 通常在需求需要往实体类加入与数据库不一致的时候,我们用@TableField去让MyBatisPlus不扫描该字段。 **
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("t_user")
public class User {
@TableId
private Long id;
@TableField("username")
private String name;
}
3、在进行插入或者更新操作时,实现能够自动填充字段的功能
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bfbt96a3-1682653973358)(C:\Users\coder\AppData\Roaming\Typora\typora-user-images\1681467882736.png)]
除了要在属性上增加这个注解,还需要手动实现一个接口MetaObjectHandler
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eIyifHdc-1682653973358)(C:\Users\coder\AppData\Roaming\Typora\typora-user-images\1681467956157.png)]
操作数据库表时,Mapper接口继承BaseMapper<>,泛型名和数据库表名对应,如果数据表名为t_users,而BaseMapper的泛型为实体类User,导致找不到数据库的表。 实体类使用@TableName注解,value值指定对应的表名。我们推荐规范value值指定对应的表名和实体类的命名保持一致,增加程序的可读性
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("t_user")
public class User {
private Long id;
private String name;
}
MyBatisPlus在实现CRUD默认会将Id作为主键,在插入数据时,使用雪花算法生成Id,如果主键不叫Id则添加功能会失败
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("t_user")
public class User {
@TableId
private Long id;
private String name;
}
另外我们可以全局配置主键生成策略
mybatis-plus: #mybatis-plus日志
global-config: #MyBatisPlus全局配置
db-config: #配置数据库
id-type: auto #统一设置主键策略
https://blog.csdn.net/m0_47743175/article/details/128051458
请求路径上的区别:很明显一个是 https:url ?键值对,一个是https:url /参数,区别很明显
@PathVariable主要用于接收http://host:port/path/{参数值}数据。
@RequestParam主要用于接收http://host:port/path?参数名=参数值数据,这里后面也可以不跟参数值。
@RequestParam用于获取参数,可获取?username="20"这种?后面的参数值
使用@PathVariable接收参数,参数值需要在url进行占位, 前端传参的URL:url = “/main/mm/am/ I d / {Id}/ Id/{name}”
如:http://localhost:8080/billing/pay/shareOfficialHistory/111/83