前排提示:里面内容可能不严谨或者有错误慎看
若发现错误麻烦指出来,不胜感激🌹
[TOC]
spring
@Component 、@Repository、@Service、@Controller
- 用来创建对象,等同于
的功能 - 属性 value 就是对象的名称,也就是bean的id值
- value的值是唯一的,创建的对象在整个spring容器中就一个
- 位置: 在类的上面
@Component(value = "myStudent")
等同于<bean id="someService1" class="com.bjpowernode.ba01"/>
@Repository
(用在持久层类的上面) :放在dao层mapper上面,创建dao对象,dao对象是能访问数据库的,将这个类或者接口标识成持久层。- 如果使用
@Repository
则需要使用@MapperScan("xxx.xxx.xxx.mapper")
进行扫描,然后生成Dao层的Bean才能被注入到Service层中。 @Service
(用在业务层上面):放在service的实现类上面,创建service对象,service对象是做业务处理,可以有事务等功能@Controller
(用在控制器上面) :放在控制器(处理器)类的上面,创建控制器对象,能够接收用户提交的参数,显示请求的处理结果- 在不确定一个类使用在哪个层时,使用@Component注解。
@Repository
: mapper注入依赖就不会报错(虽然报错也没有影响)@Repository
与@Mapper
的区别:@Mapper=@Repository+@MapperScan
@Mapper
一定要有,否则 Mybatis 找不到 mapper。@Repository
可有可无,可以消去依赖注入的报错信息(这四个注解都可以消除依赖注入报错信息,具体看注入那个依赖用哪个)@MapperScan
可以替代 @Mapper。
@Component(value = "myStudent")
@Component("myStudent") // value 可以省略
// 不指定对象名称,有spring提供默认名称 (默认为类名的首字母小写)
@Component
- 声明组件扫描器(component-scan),组件就是java对象
base-package
:指定注解在项目中的包名- 工作方式:spring会扫描base-package指定的包,把包中和子包中的所有类,找到类的注解,按照注解的功能创建对象,或给属性赋值
<!--本包-->
<context:component-scan base-package="com.bjpowernode.ba01"></context:component-scan>
<!--;或,-->
<context:component-scan base-package="com.bjpowernode.ba01;com.bjpowernode.ba02;"></context:component-scan>
<!--指定父包-->
<context:component-scan base-package="com.bjpowernode"></context:component-scan>
@ComponentScan
- 扫描器,扫描指定的包,扫描@Component注解所在包的包名
- 或用于多模块之间扫描包(A模块用B模块,在A模块的springboot启动类上添加)
- 常用在配置类上
@Configuration
@PropertySource(value ="classpath:config.properties")
@ComponentScan(basePackages="com.ssm.vo")
public class springConfig{
}
-----------------------------------------------------------
@SpringBootApplication
@ComponentScan(basePackages = "com.ssm")
public class ServiceVodApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceVodApplication.class, args);
}
}
@PropertySource
- 加载指定的属性文件
(*.properties)
到 Spring 的 Environment 中。可以配合@Value
和@ConfigurationProperties
使用。@PropertySource
和@Value
组合使用,可以将自定义属性文件中的属性变量值注入到当前类的使用@Value注解的成员变量中。@PropertySource
和@ConfigurationProperties
组合使用,可以从全局配置文件application.properties
或者application.yml
中取值,然后为需要的属性赋值
@Configuration
@PropertySource(value ="classpath:config.properties")
@ComponentScan(basePackages="com.ssm.vo")
public class springConfig{
}
当应用比较大的时候,如果所有的内容都当在一个配置文件中,就会显得比较臃肿,同时也不太好理解和维护,此时可以将一个文件拆分为多个,使用
@PropertySource
注解加载指定的配置文件TODO
@Value
- 简单类型的属性赋值
- 属性:value 是string类型的,表示简单类型的属性值,:默认值
- 位置:
- 在属性定义的上面,无需set方法,推荐使用
- 在set方法上面
@Value(value = "张飞")
private String name;
@Value(value = "11")
private Integer age;
@Value("张飞") // value 可以省略
public void setName(String name) {
this.name = name;
}
@Value("${myname}")
private String name;
@Value("${myage}")
private Integer age;
// 读取不到的话用默认值20
@Value("${myage:20}")
private Integer age;
myname=zhangsan
myage=30
@Autowire、@Qualifier、@Primary
引用类型,实现引用类型的赋值
默认使用的是byType自动注入
如果要使用
byName
方式- 在属性上面加入
@Autowired
- 在属性上面加入
@Qualifier(value = "bean的id")
:表示使用指定名称的bean完成赋值
- 在属性上面加入
属性:required,是一个boolean类型的,默认是
true
require=true
: 表示如果引用类型赋值失败,程序报错,并终止执行require=false
:表示如果引用类型赋值失败,程序正常执行,引用类型是null
@Primary
:标注优先使用哪一个实现类。- 让spring进行自动装配的时候,默认使用首选的Bean
- 不能和
@Qualifier
一起使用
位置:
- 在属性定义上面,无需set方法,推荐使用
- 在set方法上面
// 默认:byType require=true
@Autowired(require=true)
private School school;
// byName
@Autowired
@Qualifier("mySchool")
private School school;
@Configuration
@ComponentScan("com.ssm.service")
public class MainConfigOfAutowired {
@Primary
@Bean("bookDao2")
public BookDao bookDao() {
BookDao bookDao = new BookDao();
bookDao.setLable("2");
return bookDao;
}
}
// @Qualifier("bookDao") // 要让首选装配起效果,@Qualifier自然就不能用了
@Autowired(required=false)
private BookDao bookDao;
@PostConstruct
- 加上该注解的方法会在项目启动的时候执行,可以理解为Spring容器在对类自动初始化全局的单一实例的过程中,执行完一个Bean的构造方法后会执行该Bean的
@PostConstruct
方法(如果有),然后初始化下一个Bean。可作为一些数据的常规化加载,比如数据字典之类的。 @PostConstruct
和@Autowired
、构造函数
的执行顺序- 构造方法 > @Autowired > @PostConstruct
- 注意事项
- 被注解方法不得有任何参数;
- 被注解方法返回值为void;
- 被注解方法不得抛出已检查异常;
- 被注解方法需是非静态方法;
- 此方法只会被执行一次;
- 耗时长的逻辑可放到独立线程中执行,减少Spring容器初始化时间
public class MyCallBack implements RabbitTemplate.ConfirmCallback {
@Autowired
private RabbitTemplate rabbitTemplate;
@PostConstruct
public void init() {
rabbitTemplate.setConfirmCallback(this);
}
}
@Lazy
- 懒加载:容器启动不创建对象。第一次使用(获取)Bean创建对象,并初始化
- 单实例bean:默认在容器启动的时候创建对象
@Configuration
public class MainConfig{
@Lazy
@Bean("person")
public Person person(){
System.out.println("给容器中添加Person")
return new Person("张三",22)
}
}
@Scope
- 设置组件作用域
prototype
:多例的singleton
:单例的(默认值)
@Configuration
public class MainConfig{
@Scope("prototype")
@Lazy
@Bean("person")
public Person person(){
System.out.println("给容器中添加Person")
return new Person("张三",22)
}
}
@Resource
- 引用类型
- 来自jdk中的注解,spring框架提供了对该注解的支持
- 默认使用的是byName自动注入
- 先使用byName自定注入,如果byName赋值失败,再使用byType
- 只使用byName,需要增加一个name属性,name的值是bean的id(名称)
- 位置:
- 在属性定义上面,无需set方法,推荐使用
- 在set方法上面
@Resource
private School school;
@Resource(name="myschool")
private School school;
aspectj(spring内置AOP框架)
@Aspectj
- 作用:表示当前类是切面类
- 切面类:用来给业务方法增加功能的类,在这个类中有切面的功能代码
- 位置:在类定义的上面
@Aspect
public class MyAspect {
}
@Before
- 前置通知注解
- 属性value:是切入点表达式,表示切面的功能执行的位置
- 在目标方法之前执行
- 不会改变和影响方法的执行和执行结果
@Before(value ="execution(void *..SomeServiceImpl.doSome(String,Integer))" )
public void myBefore2(JoinPoint joinPoint){
}
@AfterReturning
- 后置通知注解
- 在目标方法之后执行
- 能够获取到目标方法的返回值,可以根据这个返回值做不同的处理功能r
- Object res = doOther
- 可以修改这个返回值
@AfterReturning(value = "execution(* *..SomeServiceImpl.doOther(..))",returning = "res")
public void myAfterReturning(JoinPoint joinPoint,Object res){
}
@Around
- 环绕通知注解
- 在目标方法前后都能增加功能
- 控制目标方法是否被调用执行
- 修改原来目标方法的执行结果,影响最后的调用结果
- 参数:ProceedingJoinPoint 执行目标方法
- 返回值:目标方法的执行结果,可以被修改
- 常用作事务管理
@Around(value = "execution(* *..SomeServiceImpl.doFirst(..))")
public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
}
@AfterThrowing
异常通知注解
参数有一个Exception 和 JoinPoint
属性:value 切入点表达式
throwing 自定义变量,表示方法抛出的异常对象
变量名和方法参数名一样
在目标方法抛出异常时执行
做异常监控程序
@AfterThrowing(value = "execution(* *..SomeServiceImpl.doSecond(..))", throwing = "ex")
public void myAfterException(Exception ex) {
}
@After
- 最终通知注解
- 参数有一个JoinPoint
- 属性:value 切入点表达式
- 总是会在目标方法之后执行
- 一般做资源清除工作
@After(value = "execution(* *..SomeServiceImpl.doThird(..))")
public void myAfter(){
}
@Pointcut
- 定义管理切入点注解
- 多个切入点表达式是重复的,可以复用,可以使用
@Pointcut
- 属性:
value
切入点表达式 - 当使用
@Pointcut
定义在一个方法的上面,此时这个方法名称就是切入点表达式,其他通知中,value属性就可以使用这个方法名称,代替切入点表达式
@After(value = "mypt()")
public void myAfter(){
System.out.println("执行最终通知,总是会执行");
}
@Pointcut(value = "execution(* *..SomeServiceImpl.doThird(..))" )
private void mypt(){
//无需代码
}
@Transactional
@Transactional
的所有可选属性如下所示:
➢ propagation
:用于设置事务传播属性。该属性类型为 Propagation 枚举,默认值为Propagation.REQUIRED。
➢ isolation
:用于设置事务的隔离级别。该属性类型为 Isolation 枚举,默认值为 Isolation.DEFAULT。 ➢ readOnly:用于设置该方法对数据库的操作是否是只读的。该属性为 boolean,默认值 为 false。
➢ timeout
:用于设置本操作与数据库连接的超时时限。单位为秒,类型为 int,默认值为 -1,即没有时限。
➢ rollbackFor
:指定需要回滚的异常类。类型为 Class[],默认值为空数组。当然,若只有 一个异常类时,可以不使用数组。
➢ rollbackForClassName
:指定需要回滚的异常类类名。类型为 String[],默认值为空数组。 当然,若只有一个异常类时,可以不使用数组。
➢ noRollbackFor
:指定不需要回滚的异常类。类型为 Class[],默认值为空数组。当然,若 只有一个异常类时,可以不使用数组。
➢ noRollbackForClassName
:指定不需要回滚的异常类类名。类型为 String[],默认值为空 数组。当然,若只有一个异常类时,可以不使用数组。
➢ 需要注意的是,@Transactional 若用在方法上,只能用于 public 方法上。对于其他非 public 方法,如果加上了注解@Transactional,虽然 Spring 不会报错,但不会将指定事务织入到该 方法中。因为 Spring 会忽略掉所有非 public 方法上的@Transaction 注解。 若@Transaction 注解在类上,则表示该类上所有的方法均将在执行时织入事务。
- 需声明事务管理器对象
<!--使用spring的事务处理-->
<!--声明事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--连接的数据库,指定数据源-->
<property name="dataSource" ref="myDataSource"/>
</bean>
- 开启注解驱动
<!--开启事务注解驱动,告诉spring使用注解驱动管理事务,创建代理驱动-->
<!-- <tx:annotation-driven transaction-manager = "transactionManager"/>-->
<tx:annotation-driven transaction-manager="transactionManager"/>
@Transactional(
propagation = Propagation.REQUIRED,
isolation = Isolation.DEFAULT,
readOnly = false,
rollbackFor = {
NullPointerException.class,
NotEnoughException.class
}
)
// 默认传播行为是REQUIRED,默认隔离级别DEFAULT 抛出运行时异常 回滚事务
@Transactional
SpringMVC
@RequestMapping
- 请求映射,把一个请求地址和一个方法绑定在一起,一个请求指定一个方法处理
- value: 是一个string,表示请求的url地址。value的值必须是唯一的,不能重复。推荐使用以”/“开始
- methd: 表示请求的方式。它的值时枚举类型,常用get和post两种方式。不指定请求方式则没有限制
- produces : 指定编码格式
- 位置:在方法和类的上面
- 在类的上面些代表所有请求的公共部分
- 使用RequestMapping修饰的方法叫做处理器方法或者控制器方法。
@RequestMapping(value = "/some.do")
public ModelAndView doSome(){
}
@RequestMapping(value = {"/some.do","/first.do"})
@RequestMapping(value = "/test")
public class MyController{
}
@RequestMapping(value = "/some.do",method = RequestMethod.GET)
@RequestMapping(value = "/other.do",method = RequestMethod.POST)
@RequestMapping(value = "returnStringData.do",produces = "text/plain;charset=utf-8")
@RequestParam
"rname"
解决请求中参数名和处理器方法的形参名不一样- value:请求中的参数名称
- require:false (这个参数不是必须的)
- 在处理器方法的形参定义前面
@GetMapping("/car")
public Map<String, Object> getCar2(@RequestParam("rage") Integer age,
@RequestParam("inters") List<String> inters,
@RequestParam Map<String, String> params) {
Map<String, Object> map = new HashMap<>();
map.put("age", age);
map.put("inters", inters);
map.put("params", params);
return map;
}
@RequestBody
- 主要用来接收前端表单传递给后端的json字符串中的数据的(请求体中的数据的);
- 一般都用POST方式进行提交
- 在后端的同一个接收方法里,
@RequestBody
与@RequestParam()
可以同时使用,@RequestBody
最多只能有一个,而@RequestParam()
可以有多个。 - 位置:一般放在controller层的具体请求方法的入参中
@RequestBody(required = false)
表示参数可以为空,可以防止出现java.lang.NumberFormatException: For input string: ""
异常
@PostMapping("/save")
public Map postMethod(@RequestBody String content){
Map<String,Object> map = new HashMap<>();
map.put("content",content);
return map;
}
@ResponseBody
- 把处理器的方法返回对象转为json后,通过HttpServletResponse输出给浏览器
- 位置:方法的定义上面。和其他注解没有顺序关系
@RequestMapping(value = "/returnStudentJsonArray.do")
@ResponseBody
public List<Student> doStudentJsonObjectArray(String name, Integer age){
}
@ResponseBody
和ResponseEntity
的区别
ResponseEntity
通常用于返回文件流
@ResponseBody
可以直接返回Json结果,
ResponseEntity
不仅可以返回json
结果,还可以定义返回的HttpHeaders
和HttpStatus
ResponseEntity
的优先级高于@ResponseBody
。在不是ResponseEntity的情况下才去检查有没有@ResponseBody
注解。如果响应类型是ResponseEntity可以不写@ResponseBody
注解,写了也没有关系。
@ControllerAdvice
- 控制器增强(给控制器增加功能–异常处理功能)
- 位置:在类的上面
- 需在springmvc配置文件声明组件扫描器,指定@ControllerAdvice所在的包名
@ControllerAdvice
public class GolbalExceptionHandler {
}
<!--处理异常-->
<context:component-scan base-package="com.bjpowernode.handler"/>
<mvc:annotation-driven/>
@ExceptionHandler
- 形参:Exception 表示 Controller中抛出的异常对象,通过形参可以获取发生的异常信息
- value 表示异常的类型,当发生此异常类型时,有当前方法处理
- 不写value即处理其他异常类
@ExceptionHandler(value = NameException.class)
public ModelAndView doNameExceptio(Exception exception){
}
@ExceptionHandler()
Springboot
@SpringBootApplication
- SpringBoot核心注解,主要用于开启spring自动配置
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
-------------------------------
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
- 默认:主程序所在包及其下面的所有子包里面的组件都会被默认扫描进来
- 指定扫描的包
@SpringBootApplication(scanBasePackages="com.ssm")
- 或者
@ComponentScan
指定扫描路径@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
:不加载数据库等信息
@ConfigurationProperties
- 自定义配置属性前缀
- 属性必须有前缀
- 将整个文件映射成一个对象
@Component
@ConfigurationProperties(prefix = "abc")
public class Abc {
private String name;
private String websit;
}
abc.name=abc
abc.websit=http:www.abc.com
<!--解决使用@ConfigurationProperties 注解出现警告问题-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
@Component + @ConfigurationProperties 联合使用
@EnableConfigurationProperties
- 位置:配置类上
- 开启配置绑定功能
- 把这个类组件自动注册到容器中
mycar.brand=byd
mycar.price=1000
@EnableConfigurationProperties(Car.class)
public class MyConfig {
}
@ConfigurationProperties(prefix = "mycar")
public class Car {
}
@EnableConfigurationProperties + @ConfigurationProperties 联合使用
@MapperScan()
- 开启扫描mapper接口的包以及子目录
- 位置:spring boot启动入口类上添加、或配置类上
basePackages
: 指定所需要扫描的包以及子目录,可以省略- 自动扫描包路径下的所有接口。使用这种方法,接口上不用添加任何注解。
@SpringBootApplication
@MapperScan(basePackages = "com.bjpowernode.springboot.mapper")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@EnableTransactionManagement
- 开启事务,(可选项,在业务方法上添加@Transactional默认就开启事务了)
- 位置:启动类上
@SpringBootApplication
@EnableTransactionManagement //开启事务 可加可不加
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@Transactional
- 为业务方法添加事务,开启事务
- 位置:
Service
方法上
@Transactional
public int updateStudentById(Student student) {
}
@RestController
- 相当于控制层类上加上
@Controller
+方法上加@ResponseBody
,方法上就不用加@ResponseBody
- 位置:控制层类上面
- 意味着当前控制层类中所有方法返还的都是JSON对象
@RestController
public class StudentController {
@RequestMapping(value = "/student")
public Object student(){
Student student = new Student();
student.setId(1001);
student.setName("zhangsan");
return student;
}
@RequestMapping(value = "/queryStudentById",method = {RequestMethod.GET,RequestMethod.POST})
public Object queryStudentById(Integer id){
Student student = new Student();
student.setId(id);
return student;
}
}
@GetMapping
- 只接收GET请求,如果请求方式不对会报405错误
- 该注解通常在查询数据中使用
- 相当于
@RequestMapping(value = "/queryStudentById2",method = RequestMethod.GET)
@GetMapping(value = "/queryStudentById2")
public Object queryStudentById2(){
return "Only GET Method";
}
@PostMapping
- 只接收POST请求,如果请求方式不对会报405错误
- 该注解通常在新增数据中使用
- 相当于 @RequestMapping(value = “/insert”,method = RequestMethod.POST)
@PostMapping(value = "/insert")
public Object insert(){
return "Insert Success";
}
@DeleteMapping
- 只接收DELETE请求,如果请求方式不对会报405错误
- 相当于 @RequestMapping(value = “/delete”,method = RequestMethod.DELETE)
- 该注解通常在删除数据中使用
@DeleteMapping(value = "/delete")
public Object delete(){
return "Delete Success";
}
@PutMapping
- 只接收PUT请求,如果请求方式不对会报405错误
- 相当于
@RequestMapping(value = "/update",method = RequestMethod.PUT)
- 该注解通常在修改数据中使用
@PutMapping(value = "/update")
public Object update(){
return "Update Success";
}
@PathVariable
- 获取 url 中路径变量的数据
- 一定要指定参数名称,否则出错(实验证明不加好像也行?也有可能是接口中的方法一定要指明参数名称)
- 该注解是实现 RESTFul 最主要的一个注解
@GetMapping("/car/{id}/{username}")
public Map<String, Object> getCar(@PathVariable("id") String id,
@PathVariable("username") String username,
@PathVariable Map<String,String> pv) {
Map<String, Object> map = new HashMap<>();
map.put("id",id);
map.put("username",username);
map.put("pv",pv);
return map;
}
@PathVariable Map<String,String> pv
: 获取所有请求参数
@RequestHeader
- 获取请求头信息
@GetMapping("/car")
public Map<String, Object> getCar(@RequestHeader("User-Agent") String userAgent,
@RequestHeader Map<String, String> header) {
Map<String, Object> map = new HashMap<>();
map.put("userAgent",userAgent);
map.put("headers",header);
return map;
}
@RequestHeader Map<String, String> header
:获取所有请求头信息
@CookieValue
- 获取页面请求cookie
@GetMapping("/")
public Map<String, Object> getCar2(@CookieValue("JSESSIONID") String JSESSIONID,
@CookieValue("JSESSIONID") Cookie cookie
) {
Map<String, Object> map = new HashMap<>();
map.put("JSESSIONID", JSESSIONID);
System.out.println(cookie.getName()+"--->"+cookie.getValue());
return map;
}
JSESSIONID:每个浏览器CookieValu都不一样,自行获取
@RequestAttribute
- 获取request域对象
@Controller
public class RequestController {
@GetMapping("/goto")
public String goToPage(HttpServletRequest request){
request.setAttribute("msg","success...");
request.setAttribute("code",200);
return "forward:/success";
}
@ResponseBody
@GetMapping("/success")
public Map success(@RequestAttribute("msg") String msg,
@RequestAttribute("code") Integer code,
HttpServletRequest request){
Object msg1 = request.getAttribute("msg");
HashMap<Object, Object> map = new HashMap<>();
map.put("reqMethod",msg1);
map.put("annotation",msg);
return map;
}
{"annotation":"success...","reqMethod":"success..."}
@MatrixVariable
- 语法: 请求路径:/cars/sell;low=34;brand=byd,audi,yd
- SpringBoot默认是禁用了矩阵变量的功能
- 手动开启:原理。对于路径的处理。UrlPathHelper进行解析。
- removeSemicolonContent(移除分号内容)支持矩阵变量的
- 矩阵变量必须有url路径变量才能被解析
/**
* 手动开启矩阵变量:两种方式第一种:
*/
@Configuration(proxyBeanMethods = false)
public class WebConfig implements WebMvcConfigurer {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
UrlPathHelper urlPathHelper = new UrlPathHelper();
// 不移除;后面的内容。矩阵变量功能就可以生效
urlPathHelper.setRemoveSemicolonContent(false);
configurer.setUrlPathHelper(urlPathHelper);
}
}
/**
* 手动开启矩阵变量:两种方式第二种:
*/
@Configuration(proxyBeanMethods = false)
public class WebConfig2{
@Bean
public WebMvcConfigurer webMvcConfigurer(){
return new WebMvcConfigurer() {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
UrlPathHelper urlPathHelper = new UrlPathHelper();
// 不移除;后面的内容。矩阵变量功能就可以生效
urlPathHelper.setRemoveSemicolonContent(false);
configurer.setUrlPathHelper(urlPathHelper);
}
};
}
}
@GetMapping("/cars/{path}")
public Map carsSell(@MatrixVariable("low") Integer low,
@MatrixVariable("brand") List<String> brand,
@PathVariable("path") String path){
Map<String,Object> map = new HashMap<>();
map.put("low",low);
map.put("brand",brand);
map.put("path",path);
return map;
}
// /boss/1;age=20/2;age=10
@GetMapping("/boss/{bossId}/{empId}")
public Map boss(@MatrixVariable(value = "age",pathVar = "bossId") Integer bossAge,
@MatrixVariable(value = "age",pathVar = "empId") Integer empAge){
Map<String,Object> map = new HashMap<>();
map.put("bossAge",bossAge);
map.put("empAge",empAge);
return map;
}
http://localhost:8080/cars/sell;low=34;brand=byd,audi,yd
{"path":"sell","low":34,"brand":["byd","audi","yd"]}
http://localhost:8080/boss/1;age=20/2;age=10
{"bossAge":20,"empAge":10}
@RequestPart
@RequestPart
这个注解用在multipart/form-data
表单提交请求的方法上。- 支持的请求方法的方式
MultipartFile
,属于Spring的MultipartResolver
类。这个请求是通过http协议
传输的
@PostMapping("/upload")
public String upload(@RequestPart("headerImg") MultipartFile headerImg,
@RequestPart("photos") MultipartFile[] photos) throws IOException {
}
详情请查看springboot文件上传
@EnableWebMvc
- 全面接管
@EnableWebMvc
+WebMvcConfigurer
——@Bean
可以全面接管SpringMVC
,所有规则全部自己重新配置; 实现定制和扩展功能
大大大大大大佬的专属注解
@Configuration
- 定义此类为配置类,相当于xml文件
- 位置:类的上面
- 常常与
@MapperScan("com.ssm.ggkt.order.mapper")
一起使用
@Configuration
@MapperScan("com.ssm.ggkt.order.mapper")
public class OrderConfig {
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
详解
#############################Configuration使用示例######################################################
@Configuration(proxyBeanMethods = false)
public class MyConfig {
/**
* Full:外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册容器中的单实例对象
* @return
*/
@Bean
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");
}
}
################################@Configuration测试代码如下########################################
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.atguigu.boot")
public class MainApplication {
public static void main(String[] args) {
//1、返回我们IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
//3、从容器中获取组件
Pet tom01 = run.getBean("tom", Pet.class);
Pet tom02 = run.getBean("tom", Pet.class);
// 组件:true
System.out.println("组件:"+(tom01 == tom02));
//4、com.ssm.config.MyConfig$$EnhancerBySpringCGLIB$$51f1e1ca@1654a892
MyConfig bean = run.getBean(MyConfig.class);
System.out.println(bean);
//如果@Configuration(proxyBeanMethods = true)代理对象调用方法。SpringBoot总会检查这个组件是否在容器中有。
//保持组件单实例
User user = bean.user01();
User user1 = bean.user01();
System.out.println(user == user1);
User user01 = run.getBean("user01", User.class);
Pet tom = run.getBean("tom", Pet.class);
// proxyBeanMethods = false false
// proxyBeanMethods = true true
System.out.println("用户的宠物:"+(user01.getPet() == tom));
}
}
- 配置类里面使用
@Bean
标注在方法上给容器注册组件,默认也是单实例的- 配置类本身也是组件
proxyBeanMethods
:代理bean
的方法`Full(proxyBeanMethods = true)`、【保证每个@Bean方法被调用多少次返回的组件都是单实例的】
`Lite(proxyBeanMethods = false)`【每个@Bean方法被调用多少次返回的组件都是新创建的】
组件依赖必须使用Full模式默认。其他默认是否Lite模式
@Import
- 给容器中自动创建出这两个类型的组件、默认组件的名字就是全类名
- 位置:任何容器上方
@Import({User.class, DBHelper.class})
public class test {
}
@Conditional
- 条件装配:满足Conditional指定的条件,则进行组件注入
- 位置:类和方法上,不同的位置作用域也不同
=====================测试条件装配==========================
@Configuration(proxyBeanMethods = false)
//@ConditionalOnBean(name = "tom")
@ConditionalOnMissingBean(name = "tom")
public class MyConfig {
@Bean
public User user01(){
User zhangsan = new User("zhangsan", 18);
//user组件依赖了Pet组件
zhangsan.setPet(tomcatPet());
return zhangsan;
}
@Bean("tom22")
public Pet tomcatPet(){
return new Pet("tomcat");
}
}
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
boolean tom = run.containsBean("tom");
System.out.println("容器中Tom组件:"+tom);
boolean user01 = run.containsBean("user01");
System.out.println("容器中user01组件:"+user01);
boolean tom22 = run.containsBean("tom22");
System.out.println("容器中tom22组件:"+tom22);
}
-----------------------------------
@ConditionalOnBean(name = "tom")
容器中Tom组件:false
容器中user01组件:false
容器中tom22组件:false
@ConditionalOnMissingBean(name = "tom")
容器中Tom组件:false
容器中user01组件:true
容器中tom22组件:true
其他条件注解举一反三同理
@Bean
- 给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例
- 位置:方法上面,主要用在配置类里
- 相当于一个
@Configuration
public class ServletConfig {
@Bean
public ServletRegistrationBean myServletRegistrationBean(){
ServletRegistrationBean<Servlet> servletServletRegistrationBean = new ServletRegistrationBean<>(new MyServlet(),"/myServlet");
return servletServletRegistrationBean;
}
}
指定组件名称:
@Bean(“tom”)
@WebServlet
- servlet请求映射浏览器地址
- 位置:类(继承servlet)的上面
- urlPatterns:映射地址
@WebServlet(urlPatterns = "/myServlet")
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().println("MySpringBoot Servlet-1");
resp.getWriter().flush();
resp.getWriter().close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
记得在启动类上加
@ServletComponentScan(basePackages = "com.bjpowernode.springboot.servlet")
@ServletComponentScan
- 开启扫描指定包下的servlet类、filter类
- 位置:springboot启动类上
- basePackages:指定扫描的包
@SpringBootApplication
@ServletComponentScan(basePackages = "com.bjpowernode.springboot.servlet")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@WebFilter
- filter过滤器浏览器地址
- 位置:类(实现Filter)的上面
- URLPattern:过滤地址
@WebFilter(urlPatterns = "/myfilter")
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("--------------过滤器---------------");
filterChain.doFilter(servletRequest, servletResponse);
}
}
记得在启动类上加
@ServletComponentScan(basePackages = "com.bjpowernode.springboot.servlet")
@WebListener
- 监听器
- 位置:类(实现Listener)的上面
@Slf4j
@WebListener
public class MyServletContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
log.info("监听到项目初始化");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
log.info("监听到项目销毁");
}
}
@ImportResource
- 导入xml配置,等同于xml文件的resources
- 常用在配置类上面
@Configuration
@ImportResource(value ={"classpath:applicationContext.xml","classpath:beans.xml"})
public class springConfig{
}
@properttSource
- 读取properties属性配置文件
- 需指定properties文件的位置
- 常用在配置类上面
@Configuration
@PropertySource(value ="classpath:config.properties")
@ComponentScan(basePackages="com.ssm.vo")
public class springConfig{
}
@Endpoint、@ReadOperation、@WriteOperation
@Endpoint
:定制endpoint端点名称@ReadOperation
:读操作@WriteOperation
:写操作
@Component
@Endpoint(id = "container")
public class DockerEndpoint {
@ReadOperation
public Map getDockerInfo(){
return Collections.singletonMap("info","docker started...");
}
@WriteOperation
private void restartDocker(){
System.out.println("docker restarted....");
}
}
@EnableAdminServer
- 开启springboot可视化
@EnableAdminServer
@SpringBootApplication
public class BootAdminserverApplication {
public static void main(String[] args) {
SpringApplication.run(BootAdminserverApplication.class, args);
}
}
@Profile
- 位置:类、方法上,不同的位置作用域不同
- value:指定环境
- default:使用默认环境
@Profile("prod")
@Configuration
public class MyConfig {
...
}
----------------------------
@Configuration
public class MyConfig {
@Profile("test")
@Bean
public Color green(){
return new Color();
}
}
class Color {
}
@Profile(value = {"prod","default"})
@Component
@ConfigurationProperties("person")
@Data
public class Boss implements Person {
private String name;
private Integer age;
}
@CrossOrgin
- 用于解决前后端跨域问题(跨域问题是指前后端浏览器访问协议、ip地址、端口号这三个地方只要有一个不同就会产生跨域问题)
- 用于controller层上
@RestController
@RequestMapping("/admin/vod/user")
@CrossOrigin
public class UserLoginController {
}
@EnableScheduling
- 开启定时任务,用在springboot启动类上
- 具体用法参考文章springboot整合定时任务
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@ComponentScan(basePackages = {"com.ssm"})
@MapperScan("com.ssm.staservice.mapper")
@EnableScheduling
public class StaApplication {
public static void main(String[] args) {
SpringApplication.run(StaApplication.class,args);
}
}
@RefreshScope
- 设置nacos配置中心配置实时刷新
@RefreshScope
@RestController
@RequestMapping("c")
public class CController{
@value("${c.user.name}")
private String name;
}
Mybatis
@Param
- 作用是用于传递参数,从而可以与SQL中的的字段名相对应,一般在2=<参数数<=5时使用最佳。
- 当 Dao 接口方法多个参数,需要通过名称使用参数。在方法形参前面加入@Param(“自定义参数名”),
- 如果你的dao层的方法只需要一个参数,那么用不用**@Param**注解都可以
@Mapper
public interface PaymentDao {
public int create(Payment payment);
public Payment getPaymentById(@Param("idsss") Long id);
}
<select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap" >
SELECT * FROM payment WHERE id=#{idsss};
</select>
#:占位符,告诉 mybatis 使用实际的参数值代替。并使用 PrepareStatement
对象执行 sql 语句, #{…}代替
sql 语句的“?”。这样做更安全,更迅速,通常也是首选做法。
$ 字符串替换,告诉 mybatis 使用$包含的“字符串”替换所在位置。使用 Statement 把 sql 语句和${}的
内容连接起来。主要用在替换表名,列名,不同列排序等操作。(sql注入问题)
@Select、@Insert、@Update、@Delete、@Options
- 数据库增删改查注解
- 直接将sql语句写在Mapper接口方法上,不用在Mapper.xml上写
@Options
:设置主键自增
@Mapper
public interface StudentMapper {
@Select("select * from t_student where id=#{id}")
public City getById(Long id);
@Insert("insert into t_student(`name`) values(#{name})")
@Options(useGeneratedKeys = true, keyProperty = "id")
public void insert(City city);
}
用的不多唉,适用于简单数据库操作
@Mapper
- 扫描dao接口到spring容器
- 位置:doa层接口上面
- @Mapper=@Repository+@MapperScan
@Mapper
public interface StudentMapper {
}
dubbo
@Service
- com.alibaba.dubbo.config.annotation.Service;
- 位置:服务提供者实现类上
@Service(interfaceClass = StudentService.class,version = "1.0.0",timeout = 15000)
public class StudentServiceImpl implements StudentService {
}
@Reference
注入的是分布式中的远程服务对象
位置:在属性定义上面
@Reference(interfaceClass = StudentService.class,version = "1.0.0",check = false)
private StudentService studentService;
@EnableDubboConfiguration
- 开启dubbo配置
- 位置:springboot启动类上
@SpringBootApplication
@EnableDubboConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
lombok
@Slf4j
- lombok日志注解
- 用于获取日志信息
- 位置:类的上面
@Controller
@Slf4j
public class StudentController {
log.info("查询当前学生的总人数!");
}
}
@Data
- 自动生成get,get,toString,equals等方法
- 位置:类的上面
@Data
public class User {
private Integer id;
private String nick;
}
@AllArgsConstructor
- 实体类全部参数的构造
- 位置:实体类的上面
@AllArgsConstructor
public class Payment implements Serializable {
}
@NoArgsConstructor
- 实体类的无参构造
- 位置:实体类的上面
@NoArgsConstructor
public class Payment implements Serializable {
}
@SneakyThrows
- 抛出异常注解,相当于try…catch
@SneakyThrows
public void pushPayMessage(long orderId) {
...
wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage);
...
}
SpringCloud
@EnableEurekaServer
- 启动Eureka服务注册中心
- 位置:springboot启动类上
@SpringBootApplication
@EnableEurekaServer
public class EurekaMain7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaMain7001.class,args);
}
}
@EnableEurekaClient
- 启动Eureka客户端注册中心
- 位置:springboot启动类上
@SpringBootApplication
@EnableEurekaClient
public class PaymentMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8001.class,args);
}
}
@LoadBalanced
- 赋予RestTemplate负载均衡的能力
- 位置:RestTemplate配置类的方法上
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced
public RestTemplate getResTemplate() {
return new RestTemplate();
}
}
@EnableDiscoveryClient
- 让注册中心能够发现,扫描到服务
- 用于使用consul或者zookeeper作为注册中心时注册服务
- 位置:springboot启动类上
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
public class PaymentMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8001.class,args);
}
}
@RibbonClient
- 配置Ribbon负载均衡策略
name
:服务提供者名称configuration
:负载均衡配置类- 位置:springboot启动类上
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MySelfRule.class)
public class OrderMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderMain80.class,args);
}
}
@EnableFeignClients
- 使用Feign,激活并开启
- 位置:springboot启动类上
@SpringBootApplication
@EnableFeignClients
public class OrderFeignMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderFeignMain80.class,args);
}
}
@FeignClient
- value:服务提供者名称
- 位置:服务消费者接口类上
@Component
@FeignClient(value = "Cloud-PAYMENT-SERVICE")
public interface PaymentService {
}
@EnableHystrix、@HystrixCommand、@HystrixPropert
@EnableHystrix
启动熔断降级服务- 位置:启动类上
@HystrixCommand
- 属性
fallbackMethod
:指定兜底的方法 - 位置:controller方法上
- 属性
@HystrixProperty
:name
: 设置超时时间- 位置:controller方法上
@SpringBootApplication
@EnableFeignClients
@EnableHystrix//添加到此处
public class OrderHystrixMain80
{
public static void main(String[] args)
{
SpringApplication.run(OrderHystrixMain80.class,args);
}
}
@GetMapping("/consumer/payment/hystrix/timeout/{id}")
@HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod",commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1500")
})
public String paymentInfo_TimeOut(@PathVariable("id") Integer id){
// int age = 10/0;
String result = paymentHystrixService.paymentInfo_TimeOut(id);
return result;
}
//兜底方法
public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id){
return "我是消费者80,对付支付系统繁忙请10秒钟后再试或者自己运行出错请检查自己,(┬_┬)";
}
@HystrixCommand(fallbackMethod = "fallbackMethod",
groupKey = "strGroupCommand",
commandKey = "strCommand",
threadPoolKey = "strThreadPool",
commandProperties = {
// 设置隔离策略,THREAD 表示线程池 SEMAPHORE:信号池隔离
@HystrixProperty(name = "execution.isolation.strategy", value = "THREAD"),
// 当隔离策略选择信号池隔离的时候,用来设置信号池的大小(最大并发数)
@HystrixProperty(name = "execution.isolation.semaphore.maxConcurrentRequests", value = "10"),
// 配置命令执行的超时时间
@HystrixProperty(name = "execution.isolation.thread.timeoutinMilliseconds", value = "10"),
// 是否启用超时时间
@HystrixProperty(name = "execution.timeout.enabled", value = "true"),
// 执行超时的时候是否中断
@HystrixProperty(name = "execution.isolation.thread.interruptOnTimeout", value = "true"),
// 执行被取消的时候是否中断
@HystrixProperty(name = "execution.isolation.thread.interruptOnCancel", value = "true"),
// 允许回调方法执行的最大并发数
@HystrixProperty(name = "fallback.isolation.semaphore.maxConcurrentRequests", value = "10"),
// 服务降级是否启用,是否执行回调函数
@HystrixProperty(name = "fallback.enabled", value = "true"),
// 是否启用断路器
@HystrixProperty(name = "circuitBreaker.enabled", value = "true"),
// 该属性用来设置在滚动时间窗中,断路器熔断的最小请求数。例如,默认该值为 20 的时候,如果滚动时间窗(默认10秒)内仅收到了19个请求, 即使这19个请求都失败了,断路器也不会打开。
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "20"),
// 该属性用来设置在滚动时间窗中,表示在滚动时间窗中,在请求数量超过 circuitBreaker.requestVolumeThreshold 的情况下,如果错误请求数的百分比超过50, 就把断路器设置为 "打开" 状态,否则就设置为 "关闭" 状态。
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50"),
// 该属性用来设置当断路器打开之后的休眠时间窗。 休眠时间窗结束之后,会将断路器置为 "半开" 状态,尝试熔断的请求命令,如果依然失败就将断路器继续设置为 "打开" 状态,如果成功就设置为 "关闭" 状态。
@HystrixProperty(name = "circuitBreaker.sleepWindowinMilliseconds", value = "5000"),
// 断路器强制打开
@HystrixProperty(name = "circuitBreaker.forceOpen", value = "false"),
// 断路器强制关闭
@HystrixProperty(name = "circuitBreaker.forceClosed", value = "false"),
// 滚动时间窗设置,该时间用于断路器判断健康度时需要收集信息的持续时间
@HystrixProperty(name = "metrics.rollingStats.timeinMilliseconds", value = "10000"),
// 该属性用来设置滚动时间窗统计指标信息时划分"桶"的数量,断路器在收集指标信息的时候会根据设置的时间窗长度拆分成多个 "桶" 来累计各度量值,每个"桶"记录了一段时间内的采集指标。
// 比如 10 秒内拆分成 10 个"桶"收集这样,所以 timeinMilliseconds 必须能被 numBuckets 整除。否则会抛异常
@HystrixProperty(name = "metrics.rollingStats.numBuckets", value = "10"),
// 该属性用来设置对命令执行的延迟是否使用百分位数来跟踪和计算。如果设置为 false, 那么所有的概要统计都将返回 -1。
@HystrixProperty(name = "metrics.rollingPercentile.enabled", value = "false"),
// 该属性用来设置百分位统计的滚动窗口的持续时间,单位为毫秒。
@HystrixProperty(name = "metrics.rollingPercentile.timeInMilliseconds", value = "60000"),
// 该属性用来设置百分位统计滚动窗口中使用 “ 桶 ”的数量。
@HystrixProperty(name = "metrics.rollingPercentile.numBuckets", value = "60000"),
// 该属性用来设置在执行过程中每个 “桶” 中保留的最大执行次数。如果在滚动时间窗内发生超过该设定值的执行次数,
// 就从最初的位置开始重写。例如,将该值设置为100, 滚动窗口为10秒,若在10秒内一个 “桶 ”中发生了500次执行,
// 那么该 “桶” 中只保留 最后的100次执行的统计。另外,增加该值的大小将会增加内存量的消耗,并增加排序百分位数所需的计算时间。
@HystrixProperty(name = "metrics.rollingPercentile.bucketSize", value = "100"),
// 该属性用来设置采集影响断路器状态的健康快照(请求的成功、 错误百分比)的间隔等待时间。
@HystrixProperty(name = "metrics.healthSnapshot.intervalinMilliseconds", value = "500"),
// 是否开启请求缓存
@HystrixProperty(name = "requestCache.enabled", value = "true"),
// HystrixCommand的执行和事件是否打印日志到 HystrixRequestLog 中
@HystrixProperty(name = "requestLog.enabled", value = "true"),
},
threadPoolProperties = {
// 该参数用来设置执行命令线程池的核心线程数,该值也就是命令执行的最大并发量
@HystrixProperty(name = "coreSize", value = "10"),
// 该参数用来设置线程池的最大队列大小。当设置为 -1 时,线程池将使用 SynchronousQueue 实现的队列,否则将使用 LinkedBlockingQueue 实现的队列。
@HystrixProperty(name = "maxQueueSize", value = "-1"),
// 该参数用来为队列设置拒绝阈值。 通过该参数, 即使队列没有达到最大值也能拒绝请求。
// 该参数主要是对 LinkedBlockingQueue 队列的补充,因为 LinkedBlockingQueue 队列不能动态修改它的对象大小,而通过该属性就可以调整拒绝请求的队列大小了。
@HystrixProperty(name = "queueSizeRejectionThreshold", value = "5"),
}
)
public String doSomething() {
...
}
@EnableHystrixDashboard
- 开启hystrixdashboard可视化界面
- 位置:springboot启动类上
@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashboadrMain9001 {
public static void main(String[] args) {
SpringApplication.run(HystrixDashboadrMain9001.class,args);
}
}
@EnableConfigServer
- 激活config配置中心
- 位置:springboot启动类上
@SpringBootApplication
@EnableConfigServer
public class ConfigCenterMain3344 {
public static void main(String[] args) {
SpringApplication.run(ConfigCenterMain3344.class, args);
}
}
@RefreshScope
- 配置类注解
- 实现客户端访问服务端实时刷新
- 支持nacos的动态刷新功能
- 位置:类的上面
@RestController
@RefreshScope
public class ConfigClientController{
}
@EnableBinding
- 定义一个消息生产者的发送管道
- 指信道channel和exchange绑定在一起
- 位置:类的上面
@EnableBinding(Source.class) //定义消息的推送管道
public class MessageProviderImpl implements IMessageProvider{
}
@StreamListener(Sink.INPUT)
- 监听队列,用于消费者的队列的消息接收
- 位置:方法上
@Component
@EnableBinding(Sink.class)
public class ReceiveMessageListenerController
{
...
@StreamListener(Sink.INPUT)
public void input(Message<String> message)
{
...
}
}
@SentinelResource
- value:资源名
- fallback:java业务异常指定兜底方法
- blockHandlerClass:指定兜底的类
- blockHandler:指定兜底类中的指定方法或指定方法
- exceptionsToIgnore:忽略特定异常
@RequestMapping("/consumer/fallback/{id}")
@SentinelResource(value = "fallback", fallback = "handlerFallback", blockHandler = "blockHandler", exceptionsToIgnore = {IllegalArgumentException.class})
public CommonResult<Payment> fallback(@PathVariable Long id) {
CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/" + id, CommonResult.class, id);
if (id == 4) {
throw new IllegalArgumentException("IllegalArgumentException,非法参数异常....");
} else if (result.getData() == null) {
throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常");
}
return result;
}
// 本例是fallback
public CommonResult handlerFallback(@PathVariable Long id, Throwable e) {
Payment payment = new Payment(id, "null");
return new CommonResult<>(444, "兜底异常handlerFallback,exception内容 " + e.getMessage(), payment);
}
//本例是blockHandler
public CommonResult blockHandler(@PathVariable Long id, BlockException blockException) {
Payment payment = new Payment(id, "null");
return new CommonResult<>(445, "blockHandler-sentinel限流,无此流水: blockException " + blockException.getMessage(), payment);
}
@SentinelResource
注解注意:注解方式埋点不支持
private
方法。
@SentinelResource
用于定义资源,并提供可选的异常处理和 fallback 配置项。@SentinelResource
注解包含以下属性:
value
:资源名称,必需项(不能为空)entryType
:entry 类型,可选项(默认为 EntryType.OUT)blockHandler / blockHandlerClass
:blockHandler
对应处理BlockException
的函数名称,可选项。blockHandler
函数访问范围需要是public
,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为BlockException
。blockHandler
函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定blockHandlerClass
为对应的类的Class
对象,注意对应的函数必需为static
函数,否则无法解析。fallback /fallbackClass
:fallback
函数名称,可选项,用于在抛出异常的时候提供fallback
处理逻辑。fallback 函数可以针对所有类型的异常(除了exceptionsToIgnore
里面排除掉的异常类型)进行处理。fallback
函数签名和位置要求:
- 返回值类型必须与原函数返回值类型一致;
- 方法参数列表需要和原函数一致,或者可以额外多一个
Throwable
类型的参数用于接收对应的异常。fallback
函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定fallbackClass
为对应的类的Class
对象,注意对应的函数必需为 static 函数,否则无法解析。defaultFallback(since 1.6.0)
:默认的fallback
函数名称,可选项,通常用于通用的fallback
逻辑(即可以用于很多服务或方法)。默认fallback
函数可以针对所有类型的异常(除了exceptionsToIgnore
里面排除掉的异常类型)进行处理。若同时配置了fallback
和defaultFallback
,则只有fallback
会生效。defaultFallback
函数签名要求:
- 返回值类型必须与原函数返回值类型一致;
- 方法参数列表需要为空,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。
defaultFallback
函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定fallbackClass
为对应的类的Class
对象,注意对应的函数必需为 static 函数,否则无法解析。exceptionsToIgnore(since 1.6.0)
:用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入fallback
逻辑中,而是会原样抛出。
link
@GlobalTransactional
- 实现分布式事务
- name:
// TODO 待补充
@GlobalTransactional(name = "fsp-create-order", rollbackFor = Exception.class)
public class test(){
...
}
Swagger
@EnableSwagger2
- 开启Swagger
- 位置:用在配置类上
@Configuration
@EnableSwagger2
public class SwaggerConfig {
...
}
Swagger注解 | 简单说明 |
---|---|
@Api(tags = “xxx模块说明”) | 作用在模块类上 |
@ApiOperation(“xxx接口说明”) | 作用在接口、方法上 |
@ApiModel(“xxxPOJO说明”) | 作用在模型类上:如VO、BO |
@ApiModelProperty(value = “xxx属性说明”,hidden = true) | 作用在类方法和属性上,hidden设置为true可以隐藏该属性 |
@ApiParam(“xxx参数说明”) | 作用在参数、方法和字段上,类似@ApiModelProperty,详解参考下面 |
@Api(description = "helloSwagger类")
@RestController
public class HelloSwagger {
@ApiOperation("Hello控制类")
@GetMapping(value = "/hello2")
public String hello2(@ApiParam("用户名") String username) {
...
}
}
@ApiOperation("批量删除讲师")
@DeleteMapping("batchRemove")
public Result batchRemove(@ApiParam(name = "List", value = "IDList集合", required = true)
@RequestBody List<Long> idList){
teacherService.removeByIds(idList);
return Result.ok(null);
}
@ApiModel("用户实体类")
public class User {
@ApiModelProperty("用户名")
private String username;
@ApiModelProperty("密码")
private String password;
}
@ApiParam
- 此注解对代码的侵入性挺大的
public Result findQueryPage(@ApiParam(name = "current", value = "当前页码", required = true)
@PathVariable long current,
@ApiParam(name = "teacherVo", value = "查询对象", required = false)
@RequestBody(required = false) TeacherQueryVo teacherQueryVo)
- 这里的
@ApiParam(name = "current")
的name必须和@PathVariable long current
里面的current相同,不然在swagger2上测试会报错- 但如果注释的对象是对象的话
@ApiParam(name = "teacherVo", value = "查询对象", required = false)
中name参数就可以随便写,不会报错- 这个参数对代码的侵入性还是挺大的,不过注意使用问题还是能避免的
Mybatis-Plus
@TableId
- 将属性所对应的字段指定为主键,默认id为主键
- value:指定字段名与数据库主键字段名相同,用在字段名与数据库主键字段名不相同时
- type:设置字段主键增长策略
- 位置:实体类字段上
public class User {
@TableId(value = uid,type = IdType.AUTO)
private Long id;
}
@TableName
- 设置实体类所对应的表明
- 当实体类与表名不相同时使用
- 位置:实体类上
@TableName("t_user")
public class User {
}
@TableField(fill = FieldFill.INSERT)
- 指定属性所对应的字段名
- 当属性与字段名不相同时使用,单纯的为了这样的话不写也可以,因为mp会自动识别
- 位置:实体类属性字段上
exist = false
:指数据库没这个字段,但我们需要这个属性
@TableField(value = "create_time",fill = FieldFill.INSERT)
private Date createTime;
@TableField(exist = false)
private Map<String,Object> param = new HashMap<>();
@TableLogic
- 逻辑删除注解
- 位置:实体类上
@TableLogic
private Integer isDeleted;
@Version
- 表示乐观锁版本号字段
- 位置:实体类version字段上
public class Product {
@Version
private Integer version;
}
@EnumValue
- 将注解所标识的属性的值存储到数据库中
- 位置:枚举类属性字段上
public enum SexEnum {
MALE(1, "男"),
FEMALE(2, "女");
@EnumValue
private Integer sex;
private String sexName;
}
@DS
使用 @DS 切换数据源。
可以注解在方法上或类上,同时存在就近原则 方法上注解 优先于 类上注解。
注解 | 结果 |
---|---|
没有@DS | 默认数据源 |
@DS(“dsName”) | dsName可以为组名也可以为具体某个库的名称 |
@Service
@DS("slave")
public class UserServiceImpl implements UserService {
@Autowired
private JdbcTemplate jdbcTemplate;
public List selectAll() {
return jdbcTemplate.queryForList("select * from user");
}
@Override
@DS("slave_1")
public List selectByCondition() {
return jdbcTemplate.queryForList("select * from user where age >10");
}
}
lambda
@FunctionalInterface
- 修饰函数式接口的,接口中的抽象方法只有一个
@FunctionalInterface
interface Comparator {
int compare(int a, int b);
}
JUnit5
@SpringBootTest、@Test
- 指定当前类为测试类、指定当前方法为测试方法,可直接运行
@SpringBootTest
class Boot05WebAdminApplicationTests {
@Test
void contextLoads() {
}
}
@DisplayName
- 为测试类或者测试方法设置展示名称
@DisplayName("junit5功能测试类")
public class JUnit5Test {
@DisplayName("junit5功能测试类")
@Test
void testDisplayName() {
System.out.println(1);
}
}
@BeforeEach
- 表示在每个单元测试之前执行
public class JUnit5Test {
...
@BeforeEach
void testBeforeEach() {
System.out.println("测试方法要开始了");
}
}
@AfterEach
- 表示在每个单元测试之后执行
public class JUnit5Test {
...
@AfterEach
void testAfterEach() {
System.out.println("测试方法要结束了");
}
}
@BeforeAll
- 表示在所有单元测试之前执行
@AfterAll
- 表示在所有单元测试之后执行
@DisplayName("junit5功能测试类")
public class JUnit5Test {
@DisplayName("junit5功能测试类")
@Test
public void testDisplayName() {
System.out.println(1);
}
@DisplayName("junit5功能测试类2")
@Test
public void testDisplayName2() {
System.out.println(2);
}
@BeforeEach
void testBeforeEach() {
System.out.println("测试方法要开始了");
}
@AfterEach
void testAfterEach() {
System.out.println("测试方法要结束了");
}
@BeforeAll
static void testBeforeAll() {
System.out.println("所有测试方法要开始了");
}
}
注意:
@BeforeAll
和@AfterAll
所修饰的方法必须是static
@Tag
- 表示单元测试类别,类似于JUnit4中的@Categories
@Tag(value = "aa")
@DisplayName("junit5功能测试类")
@Test
void testDisplayName() {
System.out.println(1);
}
@Disabled
- 表示测试类或测试方法不执行,类似于JUnit4中的@Ignore
@Disabled
@Test
void testDisplayName2() {
System.out.println(2);
}
@Timeout
- 表示测试方法运行如果超过了指定时间将会返回错误
- value:时间,默认是秒
- unit:设置时间格式
@Test
@Timeout(value = 500,unit = TimeUnit.MILLISECONDS)
void testTimeout() throws InterruptedException {
Thread.sleep(600);
}
@ExtendWith
- 为测试类或测试方法提供扩展类引用
@BootstrapWith(SpringBootTestContextBootstrapper.class)
@ExtendWith(SpringExtension.class)
public @interface SpringBootTest {
}
@RepeatedTest
- 重复对测试类进行单元测试
@SpringBootTest
public class JUnit5Test {
@RepeatedTest(5)
@Test
public void testRepeat(){
System.out.println(1);
}
}
@ValueSource、@NullSource、@EnumSource、 @MethodSource、@CsvFileSource
@ValueSource
: 为参数化测试指定入参来源,支持八大基础类以及String类型,Class类型@NullSource
: 表示为参数化测试提供一个null的入参@EnumSource
: 表示为参数化测试提供一个枚举入参
public enum Season {
SPRING("春天","春暖花开"),
SUMMER("夏天","夏日炎炎"),
AUTUMN("秋天","秋高气爽"),
WINTER("冬天","白雪皑皑");
private final String seasonName;
private final String seasonDesc;
private Season(String seasonName, String seasonDesc) {
this.seasonName = seasonName;
this.seasonDesc = seasonDesc;
}
public String getSeasonName() {
return seasonName;
}
public String getSeasonDesc() {
return seasonDesc;
}
@Override
public String toString() {
return "Season{" +
"seasonName='" + seasonName + '\'' +
", seasonDesc='" + seasonDesc + '\'' +
'}';
}
}
@MethodSource
:表示读取指定方法的返回值作为参数化测试入参(注意方法返回需要是一个流)
package com.ssm;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.NullSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.junit.platform.commons.util.StringUtils;
import java.util.stream.Stream;
public class ParameterizedTest01 {
@ParameterizedTest
@ValueSource(strings = {"one", "two", "three"})
@DisplayName("参数化测试1")
public void parameterizedTest1(String string) {
System.out.println(string);
Assertions.assertTrue(StringUtils.isNotBlank(string));
}
@ParameterizedTest
@NullSource
@DisplayName("参数化测试1")
public void parameterizedTest2(String a) {
if (a == null) {
System.out.println("aaa");
} else {
System.out.println("bbb");
}
}
@ParameterizedTest
@EnumSource
@DisplayName("参数化测试1")
public void parameterizedTest3(Season season) {
Season chu = Season.SPRING;
System.out.println(chu.toString());
System.out.println(season.getSeasonName());
System.out.println(season.getSeasonDesc());
}
@ParameterizedTest
@MethodSource("method") //指定方法名
@DisplayName("方法来源参数")
public void testWithExplicitLocalMethodSource(String name) {
System.out.println(name);
Assertions.assertNotNull(name);
}
static Stream<String> method() {
return Stream.of("apple", "banana");
}
}
@CsvFileSource
:表示读取指定CSV文件内容作为参数化测试入参
Insurance
public class Insurance {
private static final int Basic_PREMIUM_RATE = 1000;
private static final int[][] SETTING = {{0,0,0},{28,11,50},{18,9,100},{10,7,150},{8,5,200},{15,7,250}};
public static int[] calcSetting(int age){
if (age < 16 || age >80){
return SETTING[0];
}else if(age < 25){
return SETTING[1];
}else if(age < 35){
return SETTING[2];
}else if (age <45){
return SETTING[3];
}else if (age < 60){
return SETTING[4];
}else {
return SETTING[5];
}
}
public int calcInsurance(int age,int score){
int insuranceMoney = -1;
if(score > 0 && score<13){
int[] setting = calcSetting(age);
if (setting!=SETTING[0]){
int safeDrivingDiscount = 0;
int ageCoeffcient = setting[0];
int scoreThreshold = setting[1];
if (score>scoreThreshold){
safeDrivingDiscount = setting[2];
}
insuranceMoney = (int)(Basic_PREMIUM_RATE/10*ageCoeffcient)-safeDrivingDiscount;
}
}
return insuranceMoney;
}
}
按住ctrl + shift + T,自动生成测试类如下:
InsuranceTest
package com.ssm;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvFileSource;
import static org.junit.jupiter.api.Assertions.*;
class InsuranceTest {
Insurance insurance = new Insurance();
@ParameterizedTest
@CsvFileSource(resources = "/test.csv")
void calcInsurance(int age,int score,int money) {
assertEquals(money,insurance.calcInsurance(age,score));
}
}
resources-test.csv
20,12,2750
20,6,2800
30,11,1700
30,5,1800
40,10,850
40,4,1000
52,9,600
52,3,800
70,10,1250
70,4,1500
参考文章:https://blog.csdn.net/Zheng_lan/article/details/115223343
EasyExcel
@ExcelProperty
@ExcelProperty(value = "学生编号",index = 0)
value
:设置表头名称-
index
:设置列对应的属性
@Data
public class Stu {
@ExcelProperty(value = "学生编号",index = 0)
private int sno;
@ExcelProperty(value = "学生姓名",index = 1)
private String sname;
}
日志
@log4j
jsr303
@NotBlank、@NotNull、@NotEmpty、@Valid、@Validated
- @NotBlank:字符串,用在
String
上面属性的注解,不能为 null 和空字符串 “ ” ,而且调用trim()
后,长度必须大于0 - 注意在使用@NotBlank等注解时,一定要和@valid一起使用,不然@NotBlank不起作用,即参数必须添加@Valid或@Validated注解,不可以缺少 (两者区别自行查资料)
- @NotNull:字符串, 不能为 null
- @NotEmpty:集合类型,集合长度不能为0
- 可以看此文章:https://blog.csdn.net/Aku_2020/article/details/125413830
@Data
public class UserCheckParam {
@NotBlank
private String userName;
}
package org.ssm.user.controller;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.ssm.pojo.param.UserCheckParam;
import org.ssm.utils.R;
@RestController
@RequestMapping("/user")
public class UserController {
@PostMapping("check")
public R check(@RequestBody @Validated UserCheckParam userCheckParam) {
}
}
jackSon
@JsonInclude
@JsonInclude(JsonInclude.Include.NON_NULL)
:- 指如果没有这个值会忽略字段属性为null的字段,使其为null字段不显示。若注解的字段为 null时,则不序列化
- 当这个值不为null的时候生成json,为null不生成
- 不影响接收json
private String code;
@JsonInclude(JsonInclude.Include.NON_NULL)
private String msg;
@JsonInclude(JsonInclude.Include.NON_NULL)
private Object data;
@JsonInclude(JsonInclude.Include.NON_NULL)
private Long total;
@JsonIgnore
- 不生成Json,不接收Json数据
@JsonIgnore
private String code;
@JsonProperty
- 属性格式化,常用于解决返回的字段与实体类不相同的情况
@Data
@TableName("user")
public class User implements Serializable {
@JsonProperty("user_id") // 属性格式化,可以相互转换
@TableId(type = IdType.AUTO)
private Integer userID;
}
需要返回的json是{"user_id":""}
@JsonIgnoreProperties
@JsonIgnoreProperties(ignoreUnknown = true)
:在做json转换时没有的属性忽略不转换- 常用在实体类上
@JsonIgnoreProperties(ignoreUnknown = true)
RabbitMQ
@RabbitListener
- 监听器注解
/**
* 插入数据
*/
@RabbitListener(bindings = @QueueBinding(
value = @Queue(name = "insert.queue"),
exchange = @Exchange("topic.ex"),
key = "insert.product"
))
public void insert(Product product){
}
/**
* 删除数据
*/
@RabbitListener(bindings = @QueueBinding(
value = @Queue(name = "delete.queue"),
exchange = @Exchange("topic.ex"),
key = "delete.product"
))
public void remove() {
}
SpringCache
均参考尚硅谷毕设文档
@EnableCaching
- 添加到启动类,开启缓存支持!
@EnableCaching //开启缓存支持
public class ProductApplication {
public static void main(String[] args) {
SpringApplication.run(ProductApplication.class,args);
}
}
@Cacheable、@CachePut、@CacheEvict
- 位置:添加到方法和类上,实现类的方法
- 作用:调用方法,查询是否有缓存,有直接走缓存,没有走方法,将方法的返回值进行缓存!
- 参数:
value = String{}
配置缓存的 配置缓存‘分区’,相当于缓存的标示!key = String
配置缓存的 ‘分区’下的具体表示,此处支持SpringEL表达式,动态命名cacheManager = String
选择配置类中的缓存配置对象beanname,不选走默认!string = 方法名condition = String
注解生效条件, 支持SpringEl表达式 例如: “#result != null”结果不为null,进行缓存!
@Cacheable(value = "product",key = "#root.methodName+" +
"'-'+#productParamInteger.categoryID+" +
"'-'+#productParamInteger.currentPage+" +
"'-'+#productParamInteger.pageSize",cacheManager = "cacheManagerbean")
@CachePut(key = "#id", condition = "#result != null"),
//单一失效
@CacheEvict(value = "student", key = "'saveCache01'")
//allEntries = true 删除分区所有的数据
@CacheEvict(value = "list.product",allEntries = true)
//多点失效
@Caching(evict = {
@CacheEvict(value = "student", key = "'saveCache01'"),
@CacheEvict(value = "student", key = "'saveCache02'")
})
1
SpringEL表达式简单了解:
#开头 #root.method 被调用的方法 #root.methodName 被调用的方法名称 #root.target 调用方法的对象 #root.args 方法的参数对象数组 支持[index]获取具体参数 #result 方法执行后的结果 #形参名 直接获取行参数名称 支持ognl向下继续读取
注意:
缓存也分为curd
所以,设计缓存value和key的时候,多思考,后期还需要进行删除和替换动作!
@Primary
- 位置:缓存配置类的方法上
- 作用:同类型,多个bean,默认生效! 默认缓存时间1小时! 可以选择!,如果
cacheManager
不写就用这个默认的,写了就用写的那个
/**
* @author shaoshao
* @Date 2022/11/29 20:59
* @Description: 缓存配置类 放置配置的方法,子模板继承和复用
*/
public class CacheConfiguration {
//配置缓存manager
@Bean
@Primary //同类型,多个bean,默认生效! 默认缓存时间1小时! 可以选择!
public RedisCacheManager cacheManagerHour(RedisConnectionFactory redisConnectionFactory) {
RedisCacheConfiguration instanceConfig = instanceConfig(1 * 3600L);//缓存时间1小时
//构建缓存对象
return RedisCacheManager.builder(redisConnectionFactory)
.cacheDefaults(instanceConfig)
.transactionAware()
.build();
}
//缓存一天配置
@Bean
public RedisCacheManager cacheManagerDay(RedisConnectionFactory redisConnectionFactory) {
RedisCacheConfiguration instanceConfig = instanceConfig(24 * 3600L);//缓存时间1小时
//构建缓存对象
return RedisCacheManager.builder(redisConnectionFactory)
.cacheDefaults(instanceConfig)
.transactionAware()
.build();
}
/**
* 实例化具体的缓存配置!
* 设置缓存方式JSON
* 设置缓存时间 单位秒
*
* @param ttl
* @return
*/
private RedisCacheConfiguration instanceConfig(Long ttl) {
//设置jackson序列化工具
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer
= new Jackson2JsonRedisSerializer<Object>(Object.class);
//常见jackson的对象映射器,并设置一些基本属性
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
objectMapper.registerModule(new JavaTimeModule());
objectMapper.configure(MapperFeature.USE_ANNOTATIONS, false);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,
ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
return RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(ttl)) //设置缓存时间
.disableCachingNullValues()
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer));
}
}