常用注解

Mybatis

@Param

在Mybatis代理模式的时候,用于传递各种参数的时候,给参数起别名

例子:

接口:

1
2
3
4
5
6
public interface EmpMapper {

List<Emp> findByDeptnoAndSal(@Param("deptno") int deptno,@Param("sal") double sal);

List<Emp> findByDeptnoAndSal4(@Param("empa") Emp empa,@Param("empb") Emp empb);
}

mapper映射文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.msb.mapper.EmpMapper">

<!--
多个基本数据类型作为方法参数
List<Emp> findByDeptnoAndSal(@Param("detpno") int deptno,@Param("sal") double sal);
方式1 arg* arg0 arg1 arg2 数字是索引,从0开始
方式2 param* param1 param2 param3 数字是编号,从1开始
使用别名
List<Emp> findByDeptnoAndSal(@Param("detpno") int deptno,@Param("sal") double sal);
通过@Param注解使用别名之后,就不能再使用arg* 但是可以继续使用param*
-->
<select id="findByDeptnoAndSal" resultType="emp">
<!--select * from emp where deptno =#{arg0} and sal >= #{arg1}-->
<!-- select * from emp where deptno =#{param1} and sal >= #{param2}-->
<!-- select * from emp where deptno =#{deptno} and sal >= #{sal}-->
</select>
<!--
多个引用类型作为方法参数
List<Emp> findByDeptnoAndSal4(@Param("empa") Emp empa,@Param("empb") Emp empb);
如果用@Param定义了别名,那么就不能使用arg*.属性名,但是可以使用param*.属性名和别名.属性名
-->
<select id="findByDeptnoAndSal4" resultType="emp" >
<!-- select * from emp where deptno =#{arg0.deptno} and sal >= #{arg1.sal} -->
select * from emp where deptno =#{param1.deptno} and sal >= #{param2.sal}
<!-- select * from emp where deptno =#{empa.deptno} and sal >= #{empb.sal}-->
</select>
</mapper>

测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class Test1 {
public static void main(String[] args) {
SqlSession sqlSession = SqlSessionUtil.getSqlSession(true);
//传递给 getSqlSession 方法的参数 true 表示自动提交模式(auto-commit mode)。这意味着每次执行 SQL 语句后都会自动提交事务,不需要显式调用 commit() 方法。如果设置为 false 或不指定此参数,则需要手动管理事务(即调用 commit() 或 rollback())。
/* * 帮助我们生成一个接口下的实现类对象的* */
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);

// 1单个基本数据类型作为方法参数
Emp emp = mapper.getByEmpno(7902);
System.out.println(emp);
// 2多个基本数据类型作为方法参数
List<Emp> emps2 = mapper.getByDeptnoAndSal(10, 1500);
for(Emp em:emps2) {
System.out.println(em);
}
// 3单个引用类型作为方法参数
Emp condition=new Emp();
condition.setDeptno(10);
condition.setSal(1500.0);
List<Emp> emps3 = mapper.getByDeptnoAndSal2(condition);
for(Emp em:emps3) {
System.out.println(em);
}
// 4多个引用类型作为方法参数
Emp condition1=new Emp();
condition1.setDeptno(10);
Emp condition2=new Emp();
condition2.setSal(1500.0);
List<Emp> emps4 = mapper.getByDeptnoAndSal3(condition1,condition2);
for(Emp em:emps4) {
System.out.println(em);
}

sqlSession.close();
}
}

@Select ,@Update ,@Insert,@Delete

1
2
3
4
5
6
7
8
9
10
11
public interface DeptMapper {
Dept findDeptByDeptno(int deptno);
@Select("select * from dept where deptno =#{deptno}")
Dept findByDeptno(int deptno);
@Update("update dept set dname =#{dname}, loc =#{loc} where deptno =#{deptno}")
int updateDept(Dept dept);
@Insert("insert into dept values(DEFAULT,#{dname},#{loc})")
int addDept(Dept dept);
@Delete("delete from dept where deptno =#{deptno}")
int removeDept(int deptno);
}

Spring

@Component

@Component注解的作用:简化了applicationContext.xml中对这个创建对象的配置 ,而创建对象这件事还是spring来管理。

帮我们构建对象,默认的名字就是类名的首字母小写: UserServiceImpl —-》 userServiceImpl

我们也可以指定对象的名字:通过传入参数的形式:@Component(“usi”)

需要注意的是,任何注解想要生效,必须对这个注解进行扫描:

注解在哪个包下?要想找到这些注解,需要将注解所在的包进行扫描:设置需要扫描的包,如果需要扫描多个包,包路径之间使用逗号分隔。并且需要在applicationContext.xml中添加context命名空间(每个命名空间需要添加三行)。顺序不能乱,中间不能间隔。context命名空间去spring文档中找,随便粘贴一个过来改一改就行

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">

<!-- 多个包使用逗号分隔,下面也可以只写com.msb -->
<context:component-scan base-package="com.msb.service,com.msb.mapper"></context:component-scan>

</beans>

@Component注解的子注解

下面@Repository、@Service、@Controller、@Configuration都是@Component注解的子注解,作用相同:创建对象。主要的区别是语义上的区别,不同的注解放在不同层的类中。但是不按照语义去做,非把@Service用在持久层,也是有效果的。但是这样却是不规范的。

注解名称 解释
@Component 实例化Bean,默认名称为类名收字母变小写。支持自定义名称
@Repository @Component子标签。作用和@Component一样。用在持久层
@Service @Component子标签。作用和@Component一样。用在业务层
@Controller @Component子标签。作用和@Component一样。用在控制器层
@Configuration @Component子标签。作用和@Component一样。用在配置类上,以后结合SpringBoot使用。

属性注入相关的注解

注解名称 解释
@Autowired 自动注入。默认byType,如果多个同类型bean,使用byName。spring的注解。
@Resource 非Spring注解。默认byName,如果没找到,使用byType。JDK中javax包的注解,一般不用,用spring的注解
@Value 给普通数据类型(八种基本数据类型+String)属性赋值。spring的注解。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Service("usi")
public class UserServiceImpl implements UserService {
/*
* 加入@Autowired注解的作用:帮我们在创建对象以后完成属性的注入,此时我们不需要提供setter方法
* 注入形式:先按照类型从spring容器中去找匹配的对象注入进来。
* 如果容器中存在多个相同类型的对象,那么就按照名字去找。
* 比如容器中UserMapper实现类对象1 :um1 还有UserMapper实现类对象2:um2
* 此时就需要搭配另一个注解:@Qualifier("um1") 来指定你需要的那个对象
* 使用了 @Qualifier("um1")注解后@Autowired是不能省略的,因为@Autowired帮我们完成属性注入,
* @Qualifier只是定位到你需要注入的对象,必须搭配使用
* */
@Autowired
/*@Qualifier("um1")*/
private UserMapper userMapper;
/*加入@Autowired注解以后,底层会自动帮我们定义setter方法,无需我们自己创建这个方法*/
/*public void setUserMapper(UserMapper userMapper) {
this.userMapper = userMapper;
}*/
}

普通数据类型的属性的赋值 @Value注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Component
public class Person {
@Value("18")
private int age;
@Value("lili")
private String name;

@Override
public String toString() {
return "Person{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}

在applicationContext.xml中配置扫描注解所在的包:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd" >

<!--加入扫描注解所在的包:多个包用逗号分隔开-->
<context:component-scan base-package="com.msb.test"></context:component-scan>

</beans>

但是上面的写法,将属性值写死了,我们一般不这样用,我们都是配合属性文件来使用,@Value最大的作用就是读取配置文件,后续配合配置中心(如Nacos)来使用,现在先学习用法即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd" >


<!--加入扫描注解所在的包:多个包用逗号分隔开-->
<context:component-scan base-package="com.msb.service,com.msb.mapper,com.msb.test"></context:component-scan>
<!--加入properties文件的扫描,扫描以后,spring容器中就会有一处专门存放a.properties中的键值对-->
<context:property-placeholder location="classpath:a.properties"></context:property-placeholder>
</beans>

@RunWith()

// RunWith、ContextConfiguration这些注解不用扫描,@RunWith就会自动去构建测试类对象
@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration()

// 启动时加载的配置文件,里面要包含classpath

@ContextConfiguration(locations = “classpath:applicationContext.xml”)

@Transactional()

可以通过参数配置注解。

1
Transactional(propagation=Propagation.REQUIRED)

Service 方法上在需要添加事务的方法上加入事务注解,如需配置属性在参数位置设置即可

PS:如果很多方法都需要事务处理,那么可以直接将这个注解放在类上,代表这个类的所有方法都被事务管控。

@CrossOrigin

Spring Framework 4.2 GA为CORS提供了第一类支持,使您比通常的基于过滤器的解决方案更容易和更强大地配置它。所以springMVC的版本要在4.2或以上版本才支持@CrossOrigin

你可以向@RequestMapping注解处理程序方法添加一个@CrossOrigin注解,以便启用CORS(默认情况下,@CrossOrigin允许在@RequestMapping注解中指定的所有源和HTTP方法):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RestController
@RequestMapping("/account")
public class AccountController {
@CrossOrigin
@GetMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}

@DeleteMapping("/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}

其中@CrossOrigin中的2个参数:origins: 允许可访问的域列表、maxAge:准备响应前的缓存持续的最大时间(以秒为单位)。
为整个controller启用@CrossOrigin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@CrossOrigin(origins = "http://domain2.com", maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {
@GetMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}

@DeleteMapping("/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}

在这个例子中,对于retrieve()和remove()处理方法都启用了跨域支持,还可以看到如何使用@CrossOrigin属性定制CORS配置。

SpringMVC

@Controller

放入到Spring MVC容器中

@RequestMapping()

@RequestMapping(value={“/first2”,”/first02”})

在Spring MVC中支持Ant风格的映射路径写法。所谓的Ant风格就是支持三种特殊的符号:

符号 解释
? 匹配任意单字符
* 匹配0或者任意数量的字符
** 匹配0或者更多数量的目录

简写方式

Spring MVC 框架针对不同请求方式提供了5个专门请求方式的注解

@PostMapping(“/first”) 等效于 @RequestMapping(value = “/first”,method = RequestMethod.POST)
@GetMapping(“/first”) 等效于 @RequestMapping(value = “/first”,method = RequestMethod.GET)
@DeleteMapping(“/first”) 等效于 @RequestMapping(value = “/first”,method = RequestMethod.DELETE)
@PutMapping(“/first”) 等效于 @RequestMapping(value = “/first”,method = RequestMethod.PUT)
@PatchMapping(“/first”) 等效于 @RequestMapping(value = “/first”,method = RequestMethod.PATCH)

params属性

params属性类型是String[],表示请求中必须包含指定名称的请求参数。

1
2
3
4
@RequestMapping(value="/testParam",params = {"name"})
public String testParam(){
return "/first.jsp";
}

headers属性

headers属性类型是String[],表示请求头中必须包含指定的请求头参数。

1
2
3
4
@RequestMapping(value="/testHeaders",headers = "Cookie11")
public String testHeaders(){
return "/first.jsp";
}

@RequestParam 注解的使用

1)name:当请求参数名和控制单元参数名不对应时,可以使用name指定请求参数名。这样方法参数就可以不与请求参数对应了。

1
2
3
4
5
6
7
8
9
@Controller// 放入到Spring MVC容器中
public class MyController {
@RequestMapping("/testParam1")
public String testParam1(@RequestParam(name="name") String username){
System.out.println(username);
return "/index.jsp";
}
}

含义:接收前台名字为name的参数的值赋值给username参数。

如访问: http://localhost:8080/demo01/testParam1?name=zs后台即可接受到。

(2)value:是name属性的别名。功能和name属性相同。之所以再次设置一个和name属性相同的value,是因为在Java注解中,当需要设置value属性,且只需要设置value属性时可以省略value属性名,这样写起来更加简单。

下面代码和上面(1)中的代码完全相同

1
2
3
4
5
6
7
8
@Controller// 放入到Spring MVC容器中
public class MyController {
@RequestMapping("/testParam1")
public String testParam1(@RequestParam("name") String username){
System.out.println(username);
return "/index.jsp";
}
}

(3)defaultValue:默认值。表示当请求参数中没有这个参数时给与的默认值。

1
2
3
4
5
@RequestMapping("/testParam2")
public String testParam2(@RequestParam(defaultValue="lili") String name,@RequestParam(defaultValue = "18")Integer age){
System.out.println(name + "----" + age);
return "/index.jsp";
}

在浏览器地址栏输入:http://localhost:8080/demo01/testParam2 会在控制台打印:

(4)required:boolean类型,表示请求中是否必须包含参数。

1
2
3
4
5
@RequestMapping("/testParam3")
public String testParam3(@RequestParam(required = true) String name){
System.out.println(name);
return "/index.jsp";
}

(2)在使用List进行接收时,必须在参数前面添加@RequestParam注解,注解中内容就是请求参数名

1
2
3
4
5
@RequestMapping("/testParam5")
public String testParam5(@RequestParam("hobby") List hobbies){
System.out.println(hobbies);
return "/index.jsp";
}

@DateTimeFormat

使用@DateTimeFormat自定义时间格式,定义前端要传过来的格式。

控制单元:

1
2
3
4
5
@RequestMapping("/test7")
public String test7(@DateTimeFormat(pattern = "yyyy-MM-dd")java.util.Date date){
System.out.println(date);
return "/index.jsp";
}

访问:http://localhost:8080/demo01/test7?date=2022-5-6即可。

小提示:

​ 需要注意的是,当使用了@DateTimeFormat以后默认的时间格式就不能使用了。

如果你传过来的Date是要给对象的,那么@DateTimeFormat也可以写在JavaBean的属性上面。

@RequestHeader

在HTTP协议中,请求头参数会有很多。如果希望接收请求头数据可以使用@RequestHeader进行接收。

1
2
3
4
5
@RequestMapping("/test10")
public String test10(@RequestHeader String Accept){
System.out.println(Accept);
return "/index.jsp";
}

@ResponseBody注解

该注解用于将 控制单元 的方法返回的对象,通过适当的 转换器转换为指定格式后,写入到 Response 对象的 body 数据区。

返回的数据不是 html 标签的页面,而是其他某种格式的数据时(如普通文本、 json、xml 等)使用(通常用于ajax 请求)。

@ResponseBody注解是类或方法级注解。

直接在方法上添加上@ResponseBody,Spring MVC会把返回值设置到响应流中。

1
2
3
4
5
@RequestMapping("/demo1")
@ResponseBody
public String demo1(){
return "msbyjx";
}

很明显text/html;charset=ISO-8859-1中编码是不支持中文的。所以返回值中包含中文,打印在浏览器中会出现乱码。

想要改变@ResonseBody注解的响应内容类型(Content-Type)只能通过@RequestMapping的produces属性进行设置。

1
2
3
4
5
@RequestMapping(value="/demo1",produces = "text/html;charset=utf-8")
@ResponseBody
public String demo1(){
return "作为msbyjx";
}

响应json数据

@ResponseBody注解可以把控制单元返回值自动转换为json格式的数据(json对象)。

主要完成下面几个事情:

(1)判断返回值是否为JavaBean、JavaBean数组、List、Map等满足键值对的类型。

(2)如果满足键值对类型,会使用Jackson把对象转换为JSON数据,设置到响应流中。同时会设置响应内容类型(Content-Type)为application/json;charset=utf-8

因为Spring MVC默认使用Jackson作为JSON转换工具,把java对象进行json转化,所以必须保证项目中存在Jackson的依赖,在pom.xml中加入下面依赖:

1
2
3
4
5
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
</dependency>

案例:返回值是否为JavaBean类型,会使用Jackson把对象转换为JSON数据

编写javabean:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package com.msb.pojo;

import java.util.Date;

/**
* @Author: zhaoss
*/
public class Student {
private int id;
private String name;
private Date date;

public Student() {
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Date getDate() {
return date;
}

public void setDate(Date date) {
this.date = date;
}
}

在控制类中编写控制单元。

1
2
3
4
5
6
7
8
9
@RequestMapping(value="/demo2")
@ResponseBody
public Student demo2(){
Student s = new Student();
s.setId(17);
s.setName("丽丽");
s.setDate(new Date());
return s;// 直接return这个对象,前端就会直接得到json对象,不用自己进行任何转化(都是json帮我们处理的)
}

@RestController

@RestController = @Controller + @ResponseBody

当类上使用的是@RestController而不是@Controller时,控制单元方法不再需要写@ResponseBody(也不能写@ResponseBody),Spring MVC在解析控制单元方法时会自动带有@ResponseBody注解。

所以:@RestController写起来更加简单了。

但是需要注意:

​ 一旦类上使用了@RestController,所有控制单元返回都是普通文本或XML或JSON数据,而无法实现页面跳转功能了。

所以:只要类中有一个方法是希望实现页面跳转功能,类上就不能使用@RestController。只有类中所有的方法都是返回普通文本或JSON或XML的情况才能使用@RestController注解。

@RequestBody注解

@RequestBody注解底层依赖的依然是Jackson工具包,其作用是把客户端传递过来的请求体中JSON或XML数据转换为Map、类、List<类>、List等类型。或者我们需要的参数是对象就在对象前加入这个注解。

使用@RequestBody注解需要导入依赖:

1
2
3
4
5
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
</dependency>

@PathVariable

1
2
3
4
5
6
7
8
9
10
11
@Controller
public class MyController5 {
@RequestMapping(value="/user/{id}") // 前端传过来的参数就会给id
public User selectOneUser(@PathVariable Integer id){
//想要在方法中使用id,就需要将参数id指定为上面的id,此时需要@PathVariable注解,这样传过来的参数才会被方法的参数接收到
// 方法的参数名字必须和路径中名称保持一致
// 下面这句代码,是模拟从业务层获取到User对象:
User user = new User();
return user;
}
}

HTTP协议中支持很多种请求方式,除了GET和POST还有PUT和DELETE等,restful中要求使用不同的请求方式来标记对资源的操作方式,达到调用不同的后台功能方法来处理请求的目的。

具体的请求方式根据接口对资源的操作决定,增post 删delete 改put 查get

1
2
3
4
5
6
在 Restful 风格中,现有规定如下:
GET(SELECT):从服务器查询,可以在服务器通过请求的参数区分查询的方式。
POST(CREATE):在服务器端新建一个资源,调用 insert 操作。
PUT(UPDATE):在服务器端更新资源,调用 update 操作。
PATCH(UPDATE):在服务器端更新资源(客户端提供改变的属性)。(目前 jdk7 未实现,tomcat7不支持)。
DELETE(DELETE):从服务器端删除资源,调用 delete 语句。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* @RequestMapping注解可以接收任意请求方式的请求
* @GetMapping("地址"):接收GET请求,一般用在查询方法上
* @DeleteMapping("地址"):接收DELETE请求,一般用在删除方法上
* @PostMapping("地址"):接收POST请求,一般用户在新增上
* @PutMapping("地址"):接收PUT请求,一般用在修改上
*/
//查询用户信息
@GetMapping("/user/{id}")
public String selUser(@PathVariable Integer id){
System.out.println("用户ID为:"+id);
return "/success.jsp";
}
//删除用户信息
@DeleteMapping("/user/{id}")
public String delUser(@PathVariable Integer id){
System.out.println("用户ID为:"+id);
return "/success.jsp";
}
//新增用户信息
@PostMapping("/user/{id}/{name}/{age}")
public String addUser(@PathVariable Integer id,@PathVariable String name,@PathVariable Integer age){
System.out.println("id = " + id + ", name = " + name + ", age = " + age);
return "/success.jsp";
}
//修改用户信息
@PutMapping("/user/{id}/{name}")
public String updateUser(@PathVariable Integer id,@PathVariable String name){
System.out.println("id = " + id + ", name = " + name);
return "/success.jsp";
}

这样请求方式+路径参数即可确定要访问的具体的控制单元。

@ExceptionHandler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Controller
public class MyController9 {
@RequestMapping(value="/testexcep")
public String testexcep() throws IOException {
System.out.println("进入控制单元testexcep");
int num = 10 / 0;
return "/index.jsp";
}


// 加入下面方法(异常处理器),如果出现该异常,就走入error.jsp页面
@ExceptionHandler(value = {ArithmeticException.class, NullPointerException.class})
public String myexception(){
return "redirect:/error.jsp";
}
}

上面的方式,配置在控制器类中,只有当前这个控制器类的控制单元出现异常时才能执行,其他类的控制单元出现异常不能执行。

每个控制器类中可以有多个处理异常的方法,每个方法上面只需要有@ExceptionHandler,千万别添加了@RequestMapping注解。

@ControllerAdvice

全局配置方式,对所有控制单元的所有方法都生效。因为@ControllerAdvice已经继承了@Component注解,所以类上只添加这个注解就可以了。

不需要在添加@Controller注解了。

1
2
3
4
5
6
7
@ControllerAdvice
public class MyExceptionController {
@ExceptionHandler(value = ArithmeticException.class)
public String myexception(){
return "/error.jsp";
}
}

小提示:

​ 如果配置了局部异常处理器和全局异常处理器,优先匹配局部异常处理器。

SpringDoc

@Tag

1
2
@Tag:作用-用在请求的类上,说明该类的作用
配置参数name="该类对应的模块名字 "tags="说明该类的作用,对模块进行描述"
1
@Tag(name = "用户模块管理", description = "用户接口")

@Operation

1
2
@Operation:作用-用在请求的方法上,说明方法的作用
配置参数summary="说明方法的作用"
1
@Operation(summary="用户模块-根据用户id查询用户信息")

@Parameters

1
2
3
4
5
6
@Parameters:作用-用在请求的方法上,对请求的参数(方法的形参)进行说明,是一个复合注解,里面包含了多个@Parameter子注解。
@Parameter:用在 @Parameters 注解中,指定一个请求参数的配置信息
注解的属性介绍:(配置参数)
name:参数名
value:参数的汉字说明、解释
required:参数是否必须传

如果方法是一个参数,可以直接使用@Parameter注解:

1
2
3
4
@Parameter(name="uid",description ="查询参数用户id",required = true)
public User select(@PathVariable Integer uid){
return userService.findOneUser(uid);
}

如果多个参数,可以使用@Parameters,如:

1
2
3
4
5
@Parameters({
@Parameter(name="mobile",description="手机号",required=true),
@Parameter(name="password",description="密码",required=true),
@Parameter(name="age",description="年龄",required=true)
})

@ApiResponses

1
2
3
4
5
@ApiResponses:用于请求的方法上,表示一组响应,,是一个复合注解,里面包含了多个@ApiResponse子注解。
@ApiResponse:用在@ApiResponses中,一般用于表达一个错误的响应信息
code:数字,例如400
message:信息,例如"请求参数没填好"
response:抛出异常的类
1
2
3
4
@ApiResponses({
@ApiResponse(code=400, message="请求参数没填好"),
@ApiResponse(code=404, message="请求路径没有或页面跳转路径不对")
})

@Schema

用在模型类上,对模型类做注释; 用在属性上,对属性做注释 ;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.msb.pojo;


import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
* @Author: zhaoss
*/
@NoArgsConstructor
@AllArgsConstructor
@Data
@Schema(description = "用户实体类")
public class User {
@Schema(description = "用户id主键")
private Integer uid;
@Schema(description = "用户名字")
private String uname;
@Schema(description = "账户密码")
private String pwd;
@Schema(description = "真实名字")
private String realname;
@Schema(description = "身份标识")
private Integer identity;
}

SpringBoot事务控制

@Transactional(propagation= Propagation.REQUIRED)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;



@Override
@Transactional(propagation= Propagation.REQUIRED)
public int deleteUserById(Integer uid) {
int num = userMapper.delete(uid);
int a = 1/0;
return num;
}

}

启动服务器,测试,发现程序报错,数据库数据没有被删除,证明事务加入成功,非常简单的操作!在service层每个增删改方法前都加入@Transactional(propagation = Propagation.REQUIRED)注解即可。

SpringBoot异常处理

@ExceptionHandler 实现局部异常处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Controller
public class MyController {
@RequestMapping("/test1")
@ResponseBody
public String test01(){
System.out.println("test1---");
int a = 1/0;
return "test01";
}

// 出现算术异常,跳转到如下方法解决:
@ExceptionHandler(value = {java.lang.ArithmeticException.class})
public String myexceptionhandler(){
System.out.println("异常处理逻辑代码。。");
return "myerror";
}
}

上面这种处理方式属于局部处理方式,只对当前MyController控制单元中的异常生效,所以我们需要加入全局异常处理:

@ControllerAdvice、@ExceptionHandler实现全局异常处理

创建com.msb.exceptionhandler包,加入异常处理类,使用@ControllerAdvice、@ExceptionHandler注解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.msb.exceptionhandler;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

/**
* @Author: zhaoss
*/
@ControllerAdvice // 代表当前类为异常处理类
public class GlobalExceptionHandler {
// 出现算术异常,跳转到如下方法解决:
@ExceptionHandler(value = {java.lang.ArithmeticException.class})
public String myexceptionhandler(){
System.out.println("异常处理逻辑代码。。");
return "myerror";
}
}

重启服务器访问发现:这样不同的控制单元都可以处理异常了

@Configuration,@Bean

1
2
3
4
5
6
7
8
9
10
11
@Configuration
public class GlobalExceptionHandler2 {
@Bean
public SimpleMappingExceptionResolver getSME(){
SimpleMappingExceptionResolver sme = new SimpleMappingExceptionResolver();
Properties p = new Properties();
p.put("java.lang.ArithmeticException","myerror");
sme.setExceptionMappings(p);
return sme;
}
}

上面的配置类等效之前的xml配置:

image-20250320160108091

SpringBoot数据校验validation

validation校验相关的注解

注解 功能
@AssertFalse 可以为null,如果不为null的话必须为false
@AssertTrue 可以为null,如果不为null的话必须为true
@DecimalMax 设置不能超过最大值
@DecimalMin 设置不能超过最小值
@Digits 设置必须是数字且数字整数的位数和小数的位数必须在指定范围内
@Future 日期必须在当前日期的未来
@Past 日期必须在当前日期的过去
@Max 最大不得超过此最大值
@Min 最大不得小于此最小值
@NotNull 不能为null,可以是空
@Min 最大不得小于此最小值
@Pattern 必须满足指定的正则表达式
@Size 集合、数组、map等的size()值必须在指定范围内
@Email 必须是email格式
@Length 长度必须在指定范围内
@NotBlank 字符串不能为null,字符串trim()后也不能等于“”
@NotEmpty 不能为null,集合、数组、map等size()不能为0;字符串trim()后可以等于“”
@Range 值必须在指定范围内
@URL 必须是一个URL

校验注解的使用

  • User 实体类参数校验注解

    如对用户进行删除或者更新操作的时候,对用户的属性值进行一些基本校验:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class User{

@NotBlank(message = "用户名不能为空!")
private String userName;

@NotBlank(message = "用户密码不能为空!")
@Length(min = 6, max = 10,message = "密码长度至少6位但不超过10位!")
private String userPwd;

/*
省略get set 方法
*/
}

校验注解配置好了,如何在校验环境生效呢?需要结合下面的接口方法:

  • 接口方法形参 @Valid 注解添加

    @Valid 代表对当前客户端提交的表单参数进行校验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.msb.controller;

import com.msb.pojo.User;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.*;

/**
* @Author: zhaoss
*/
@RestController
public class MyController {
@PostMapping("/user")
public int save(@RequestBody @Valid User user){
System.out.println("进入save方法");
// 这里有访问service层的代码,省略...模拟return 0 ,主要为了测试参数部分的校验
return 0;
}

}

SpringBoot的Bean管理

@Configuration和@Bean

1
2
3
4
5
6
7
8
9
10
11
12
13
@Configuration  // 加入这个注解,代表当前为配置类,可以替代xml
public class MyConfig {
// 相当于以前的bean标签,s相当于以前的id
// 如果括号中s没有写,那么id相当于方法名:getStudent
@Bean("s")
public Student getStudent(){
Student s = new Student();
s.setId(1);
s.setName("zs"); //这个过程就相当于之前给对象注入属性的过程
return s;
}

}

@Qualifier

1
2
3
4
5
6
7
8
9
10
11
12
@SpringBootTest
class SpringBootM10ApplicationTests {
@Autowired
@Qualifier("s2") // Spring容器中存在同类型的Bean通过Bean的名称获取到Bean对象,需要@Autowired、@Qualifier结合使用
private Student stu;

@Test
void contextLoads() {
System.out.println(stu);
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Configuration  
public class MyConfig {

@Bean("s2")
public Student getStudent2(Clazz c){// 在参数中加入Clazz c,通过参数传递的形式完成注入,会优先找容器中同类型的Clazz对象,如果多个Clazz对象,可以使用:(@Qualifier("cla") Clazz c),这个位置不需要使用@AutoWire注解,因为在这里默认就是利用参数注入对象
Student s = new Student();
s.setId(2);
s.setName("ls");
//s.setC(getCla());// 这种调用方法的形式也可以,但不是注入的形式
s.setC(c);
return s;
}

@Bean("cla")
public Clazz getCla(){
Clazz c = new Clazz();
c.setId(1);
c.setName("java406班");
return c;
}

@Bean("cla2")
public Clazz getCla(){
Clazz c = new Clazz();
c.setId(1001);
c.setName("java班级");
return c;
}

}

MyBatis-Plus

@TableName(),@TableField()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@NoArgsConstructor
@AllArgsConstructor
@Data
@TableName("t_user") // 对应的数据库中表为t_user,如果数据库中表和实体类名字一致,可以不指定
public class User {

@TableField(exist = false) // 如果数据库表中没有这个字段,这个字段与数据库表字段对不上,加了这个属性,就不会报错
private Integer a;

@TableField("uid") // 指定数据库表中字段名字,如果数据库表字段和属性名字一致,可以不指定
private Integer id;

private String uname;

private String pwd;

private String realname;

private Integer identity;
}

SpringBoot实现SpringAOP

1、aop切面

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2、在主类上加上

1
@EnableAspectJAutoProxy(exposeProxy = true)

加上之后可以获取当前类的代理对象

  1. 开启Spring AOP代理的创建:使得Spring容器中的所有bean都能被AOP代理。

  2. @RestControllerAdvice 是一个复合注解,它是 @ControllerAdvice 和 @ResponseBody 的结合体。

    @ControllerAdvice:该注解的作用是为所有的 @RequestMapping 处理方法提供通用的异常处理和数据绑定等增强功能。
    @ResponseBody:该注解的作用是将响应格式从对象转换为JSON格式返回。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

@ExceptionHandler(BusinessException.class)
public BaseResponse<?> businessExceptionHandler(BusinessException e) {
log.error("business error:{}", e.getMessage());
// 捕捉到异常后,以通用格式返回
return ResultUtils.error(e.getCode(), e.getMessage());
}
// 兜底
@ExceptionHandler(RuntimeException.class)
public BaseResponse<?> runtimeExceptionHandler(RuntimeException e) {
log.error("RuntimeException", e);
return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "系统错误");
}
}

Dubbo-Cloud

@Refrence

@Reference 是 Dubbo 框架中的一个注解,用于注入远程服务的引用。在分布式系统中,服务消费者通过 RPC(远程过程调用)方式与服务提供者进行通信。@Reference 注解可以帮助服务消费者获取服务提供者的实例,并调用其方法。

@EnableDiscoveryClient

@EnableDiscoveryClient和@EnableEurekaClient共同点就是:都是能够让注册中心能够发现,扫描到改服务。

记得配置扫包路径

不同点:@EnableEurekaClient只适用于Eureka作为注册中心,@EnableDiscoveryClient 可以是其他注册中心。

SpringSecurity

@Secured

通常用于放在控制器方法上,专门用于判断是否具有角色的,参数要以ROLE_开头

理解 @PreAuthorize 和 @PostAuthorize 注解

@PreAuthorize@PostAuthorize 是 Spring Security 提供的两种方法级安全注解,用于在方法调用前后进行权限验证。

@PreAuthorize 详解

@PreAuthorize 表示在方法执行前进行权限检查,只有通过检查的方法才会被执行。这是最常用的安全注解。

特点:

  1. 执行时机:方法调用前进行权限验证
  2. 常用性:大多数情况下使用这个注解就足够了
  3. 参数:接受一个 SpEL (Spring Expression Language) 表达式

表达式示例:

1
2
3
4
5
6
7
8
@PreAuthorize("hasRole('ADMIN')") // 必须有ADMIN角色才能访问
public void adminMethod() {...}

@PreAuthorize("hasPermission(#id, 'read')") // 必须有对指定ID的read权限
public void readData(Long id) {...}

@PreAuthorize("#user.name == authentication.name") // 只能操作自己的用户数据
public void updateUser(User user) {...}

@PostAuthorize 详解

@PostAuthorize 表示在方法执行后进行权限检查,可以基于方法返回值进行验证。

特点:

  1. 执行时机:方法执行后进行权限验证
  2. 使用场景:需要基于返回结果进行验证的情况
  3. 参数:同样接受 SpEL 表达式,可以引用返回值

表达式示例:

1
2
@PostAuthorize("returnObject.owner == authentication.name") // 只能返回属于自己的对象
public Data getData() {...}

与 access() 方法的关系

在 Spring Security 配置中,access() 方法也用于权限控制,如:

1
.antMatchers("/admin/**").access("hasRole('ADMIN')")

@PreAuthorize@PostAuthorize 的参数与 access() 方法参数取值相同,都是使用 SpEL 表达式,支持相同的安全表达式如:

  • hasRole('ROLE')
  • hasAuthority('AUTH')
  • hasPermission(target, permission)
  • principal, authentication 等内置对象

启用方法安全

要使用这些注解,需要在配置类上添加 @EnableGlobalMethodSecurity

1
2
3
4
5
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// ...
}

SpringCloud

Euraka

@EnableDiscoveryClient

代表我当前这个微服务是一个服务的消费者 调用别的服务

@EnableEurekaServer

代表我们当前这个springboot的项目 作为一个服务注册中心

@EnableEurekaClient

代表我们这个项目是作为服务的提供者,根据配置会注册到注册中心上

Feign

@EnableFeignClients

代表这个项目是可以通过Feign来调用远端的服务的项目

@FeignClient

这个在接口上添加注解,代表这个接口调用的远端的服务的地址

@FeignClient(name = “ldx-order”,fallback = OrderApiClientFallBack.class)