Validated 注解完成 Spring Boot 参数校验

1.  @Valid 和 @Validated

  @Valid 注解,是 Bean Validation 所定义,可以添加在普通方法、构造方法、方法参数、方法返回、成员变量上,表示它们需要进行约束校验。
  @Validated 注解,是 Spring Validation 所定义,可以添加在类、方法参数、普通方法上,表示它们需要进行约束校验。并且,@Validated 具有 value 属性,支持分组校验。
  • 声明式校验
    @Validated
  • 分组检验
    @Validated
  • 嵌套校验
    @Valid

2.  常用注解


3. 快速入门

  • 创建Maven项目
  • 修改pom.xml
 1 <project xmlns="http://maven.apache.org/POM/4.0.0"
 2     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 4     <modelVersion>4.0.0</modelVersion>
 5     <groupId>com.c3stones</groupId>
 6     <artifactId>spring-boot-validated-demo</artifactId>
 7     <version>0.0.1-SNAPSHOT</version>
 8     <name>spring-boot-validated-demo</name>
 9     <description>Spring Boot Validated Demo</description>
10 
11     <parent>
12         <groupId>org.springframework.boot</groupId>
13         <artifactId>spring-boot-starter-parent</artifactId>
14         <version>2.1.4.RELEASE</version>
15     </parent>
16 
17     <properties>
18         <java.version>1.8</java.version>
19     </properties>
20 
21     <dependencies>
22            <dependency>
23             <groupId>org.projectlombok</groupId>
24             <artifactId>lombok</artifactId>
25         </dependency>
26         <dependency>
27             <groupId>org.springframework.boot</groupId>
28             <artifactId>spring-boot-starter-web</artifactId>
29         </dependency>
30         <dependency>
31             <groupId>org.springframework.boot</groupId>
32             <artifactId>spring-boot-starter-test</artifactId>
33             <scope>test</scope>
34         </dependency>
35     </dependencies>
36 
37 </project>
  • 创建启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
  •  创建DTO
 1 import javax.validation.constraints.NotEmpty;
 2 import javax.validation.constraints.Pattern;
 3 
 4 import org.hibernate.validator.constraints.Length;
 5 
 6 import lombok.Data;
 7 
 8 /**
 9  * 用户保存DTO
10  *
11  */
12 @Data
13 public class UserSaveDto {
14 
15     /**
16      * 用户名称
17      */
18     @NotEmpty(message = "用户名称不能为空")
19     @Length(min = 6, max = 12, message = "账号长度为 6-12 位")
20     @Pattern(regexp = "^[A-Za-z0-9]+$", message = "用户名称格式为数字或字母")
21     private String username;
22 
23     /**
24      * 密码
25      */
26     @NotEmpty(message = "密码不能为空")
27     @Length(min = 6, max = 18, message = "密码长度为 6-18 位")
28     private String password;
29 }
  •  创建Controller
 1 import javax.validation.Valid;
 2 import javax.validation.constraints.Min;
 3 
 4 import org.slf4j.Logger;
 5 import org.slf4j.LoggerFactory;
 6 import org.springframework.validation.annotation.Validated;
 7 import org.springframework.web.bind.annotation.GetMapping;
 8 import org.springframework.web.bind.annotation.PostMapping;
 9 import org.springframework.web.bind.annotation.RequestMapping;
10 import org.springframework.web.bind.annotation.RequestParam;
11 import org.springframework.web.bind.annotation.RestController;
12 
13 import com.c3stones.dto.UserSaveDto;
14 
15 @RestController
16 @RequestMapping("/user")
17 @Validated
18 public class UserController {
19 
20     private Logger logger = LoggerFactory.getLogger(getClass());
21 
22     @GetMapping("/get")
23     public String get(@RequestParam("id") @Min(value = 1L, message = "id必须大于0") Integer id) {
24         logger.info("获取用户信息,id:" + id);
25         return "get success";
26     }
27 
28     @PostMapping("/save")
29     public String save(@Valid UserSaveDto saveDto) {
30         logger.info("保存用户信息:", saveDto.toString());
31         return "save success";
32     }
33 
34 }
  • 启动项目
  • 测试get方法
 1 curl -X GET "http://localhost:8080/user/get?id=0"
 2 #返回:
 3 {
 4     "timestamp": "2020-05-20T03:27:23.667+0000",
 5     "status": 500,
 6     "error": "Internal Server Error",
 7     "message": "get.id: id必须大于0",
 8     "path": "/user/get"
 9 }
10 
11 curl -X GET "http://localhost:8080/user/get?id=1"
12 #返回:
13 get success
  • 测试save方法
 1 curl -X POST "http://localhost:8080/user/save?username=test&password=123"
 2 #返回:
 3 {
 4     "timestamp": "2020-05-20T03:29:46.684+0000",
 5     "status": 400,
 6     "error": "Bad Request",
 7     "errors": [
 8         {
 9             "codes": [
10                 "Length.userSaveDto.username",
11                 "Length.username",
12                 "Length.java.lang.String",
13                 "Length"
14             ],
15             "arguments": [
16                 {
17                     "codes": [
18                         "userSaveDto.username",
19                         "username"
20                     ],
21                     "arguments": null,
22                     "defaultMessage": "username",
23                     "code": "username"
24                 },
25                 12,
26                 6
27             ],
28             "defaultMessage": "账号长度为 6-12 位",
29             "objectName": "userSaveDto",
30             "field": "username",
31             "rejectedValue": "test",
32             "bindingFailure": false,
33             "code": "Length"
34         },
35         {
36             "codes": [
37                 "Length.userSaveDto.password",
38                 "Length.password",
39                 "Length.java.lang.String",
40                 "Length"
41             ],
42             "arguments": [
43                 {
44                     "codes": [
45                         "userSaveDto.password",
46                         "password"
47                     ],
48                     "arguments": null,
49                     "defaultMessage": "password",
50                     "code": "password"
51                 },
52                 18,
53                 6
54             ],
55             "defaultMessage": "密码长度为 6-18 位",
56             "objectName": "userSaveDto",
57             "field": "password",
58             "rejectedValue": "123",
59             "bindingFailure": false,
60             "code": "Length"
61         }
62     ],
63     "message": "Validation failed for object='userSaveDto'. Error count: 2",
64     "path": "/user/save"
65 }
66 
67 curl -X POST "http://localhost:8080/user/save?username=test001&password=123456"
68 #返回:
69 save success

4. 分组校验

  • 编写实体类
 1 import javax.validation.constraints.NotEmpty;
 2 import javax.validation.constraints.NotNull;
 3 
 4 import lombok.AllArgsConstructor;
 5 import lombok.Data;
 6 import lombok.NoArgsConstructor;
 7 
 8 /**
 9  * 用户
10  * 
11  */
12 @Data
13 @NoArgsConstructor
14 @AllArgsConstructor
15 public class User {
16 
17     /**
18      * 用户保存分组
19      * 
20      */
21     public interface UserSaveGroup {
22     }
23 
24     /**
25      * 用户更新分组
26      * 
27      */
28     public interface UserUpdateGroup {
29     }
30 
31     /**
32      * ID
33      */
34     @NotNull(message = "ID不能为空", groups = { UserUpdateGroup.class })
35     private Integer id;
36 
37     /**
38      * 用户名称
39      */
40     @NotEmpty(message = "用户名称不能为空", groups = { UserSaveGroup.class, UserUpdateGroup.class })
41     private String username;
42 
43     /**
44      * 密码
45      */
46     @NotEmpty(message = "密码不能为空", groups = { UserSaveGroup.class, UserUpdateGroup.class })
47     private String password;
48 }
  • Controller添加方法
 1 @PostMapping("/saveUser")
 2 public String saveUser(@Validated({ UserSaveGroup.class }) User user) {
 3     logger.info("保存用户信息:", user.toString());
 4     return "saveUser success";
 5 }
 6 
 7 @PutMapping("/updateUser")
 8 public String updateUser(@Validated({ UserUpdateGroup.class }) User user) {
 9     logger.info("更新用户信息:", user.toString());
10     return "updateUser success";
11 }
  •  测试UserSaveGroup分组
 1 curl -X POST "http://localhost:8080/user/saveUser"
 2 #返回:
 3 {
 4     "timestamp": "2020-05-20T03:45:15.357+0000",
 5     "status": 400,
 6     "error": "Bad Request",
 7     "errors": [
 8         {
 9             "codes": [
10                 "NotEmpty.user.password",
11                 "NotEmpty.password",
12                 "NotEmpty.java.lang.String",
13                 "NotEmpty"
14             ],
15             "arguments": [
16                 {
17                     "codes": [
18                         "user.password",
19                         "password"
20                     ],
21                     "arguments": null,
22                     "defaultMessage": "password",
23                     "code": "password"
24                 }
25             ],
26             "defaultMessage": "密码不能为空",
27             "objectName": "user",
28             "field": "password",
29             "rejectedValue": null,
30             "bindingFailure": false,
31             "code": "NotEmpty"
32         },
33         {
34             "codes": [
35                 "NotEmpty.user.username",
36                 "NotEmpty.username",
37                 "NotEmpty.java.lang.String",
38                 "NotEmpty"
39             ],
40             "arguments": [
41                 {
42                     "codes": [
43                         "user.username",
44                         "username"
45                     ],
46                     "arguments": null,
47                     "defaultMessage": "username",
48                     "code": "username"
49                 }
50             ],
51             "defaultMessage": "用户名称不能为空",
52             "objectName": "user",
53             "field": "username",
54             "rejectedValue": null,
55             "bindingFailure": false,
56             "code": "NotEmpty"
57         }
58     ],
59     "message": "Validation failed for object='user'. Error count: 2",
60     "path": "/user/saveUser"
61 }
62 
63 curl -X POST "http://localhost:8080/user/saveUser?username=zhangsan&password=123456"
64 #返回:
65 saveUser success
  •  测试UserUpdateGroup分组
 1 curl -X PUT "http://localhost:8080/user/updateUser"
 2 #返回:
 3 {
 4     "timestamp": "2020-05-20T03:52:01.350+0000",
 5     "status": 400,
 6     "error": "Bad Request",
 7     "errors": [
 8         {
 9             "codes": [
10                 "NotEmpty.user.username",
11                 "NotEmpty.username",
12                 "NotEmpty.java.lang.String",
13                 "NotEmpty"
14             ],
15             "arguments": [
16                 {
17                     "codes": [
18                         "user.username",
19                         "username"
20                     ],
21                     "arguments": null,
22                     "defaultMessage": "username",
23                     "code": "username"
24                 }
25             ],
26             "defaultMessage": "用户名称不能为空",
27             "objectName": "user",
28             "field": "username",
29             "rejectedValue": null,
30             "bindingFailure": false,
31             "code": "NotEmpty"
32         },
33         {
34             "codes": [
35                 "NotNull.user.id",
36                 "NotNull.id",
37                 "NotNull.java.lang.Integer",
38                 "NotNull"
39             ],
40             "arguments": [
41                 {
42                     "codes": [
43                         "user.id",
44                         "id"
45                     ],
46                     "arguments": null,
47                     "defaultMessage": "id",
48                     "code": "id"
49                 }
50             ],
51             "defaultMessage": "ID不能为空",
52             "objectName": "user",
53             "field": "id",
54             "rejectedValue": null,
55             "bindingFailure": false,
56             "code": "NotNull"
57         },
58         {
59             "codes": [
60                 "NotEmpty.user.password",
61                 "NotEmpty.password",
62                 "NotEmpty.java.lang.String",
63                 "NotEmpty"
64             ],
65             "arguments": [
66                 {
67                     "codes": [
68                         "user.password",
69                         "password"
70                     ],
71                     "arguments": null,
72                     "defaultMessage": "password",
73                     "code": "password"
74                 }
75             ],
76             "defaultMessage": "密码不能为空",
77             "objectName": "user",
78             "field": "password",
79             "rejectedValue": null,
80             "bindingFailure": false,
81             "code": "NotEmpty"
82         }
83     ],
84     "message": "Validation failed for object='user'. Error count: 3",
85     "path": "/user/updateUser"
86 }
87 
88 curl -X PUT "http://localhost:8080/user/updateUser?id=1001&username=zhangsan&password=123123"
89 #返回:
90 updateUser success

5. 国际化配置

  • 配置文件中添加
1 spring:
2 # i18 message 配置,对应 MessageSourceProperties 配置类
3    messages:
4       basename: i18n/messages # 文件路径基础名
5       encoding: UTF-8 # 使用 UTF-8 编码
  • 在项目resource目录下创建i18n文件夹
  • 在i18n中添加国际化配置文件

messages.properties

1 Goods.id.NotNull=商品ID不能为空

messages_en.properties

1 Goods.id.NotNull=Goods id cannot be empty

messages_ja.properties

1 Goods.id.NotNull=商品IDは空にできません
  • 创建实体
 1 import javax.validation.constraints.NotNull;
 2 
 3 import lombok.AllArgsConstructor;
 4 import lombok.Data;
 5 import lombok.NoArgsConstructor;
 6 
 7 /**
 8  * 商品
 9  * 
10  */
11 @Data
12 @NoArgsConstructor
13 @AllArgsConstructor
14 public class Goods {
15 
16     /**
17      * 商品ID
18      */
19     @NotNull(message = "{Goods.id.NotNull}")
20     private Integer id;
21 
22     /**
23      * 商品名称
24      */
25     private String name;
26 }
  • 创建Controller
 1 import javax.validation.Valid;
 2 
 3 import org.slf4j.Logger;
 4 import org.slf4j.LoggerFactory;
 5 import org.springframework.validation.annotation.Validated;
 6 import org.springframework.web.bind.annotation.PostMapping;
 7 import org.springframework.web.bind.annotation.RequestMapping;
 8 import org.springframework.web.bind.annotation.RestController;
 9 
10 import com.c3stones.entity.Goods;
11 12 @RestController 13 @RequestMapping("/goods") 14 @Validated 15 public class GoodsController { 16 17 private Logger logger = LoggerFactory.getLogger(getClass()); 18 19 @PostMapping("/save") 20 public String save(@Valid Goods goods) { 21 logger.info("保存商品信息:", goods.toString()); 22 return "save success"; 23 } 24 25 }
  • 测试(通过头部指定 Accept-Language 参数)
  1 #测试默认中文
  2 curl -X POST "http://localhost:8080/goods/save"
  3 #返回:
  4 {
  5     "timestamp": "2020-05-20T04:15:59.417+0000",
  6     "status": 400,
  7     "error": "Bad Request",
  8     "errors": [
  9         {
 10             "codes": [
 11                 "NotNull.goods.id",
 12                 "NotNull.id",
 13                 "NotNull.java.lang.Integer",
 14                 "NotNull"
 15             ],
 16             "arguments": [
 17                 {
 18                     "codes": [
 19                         "goods.id",
 20                         "id"
 21                     ],
 22                     "arguments": null,
 23                     "defaultMessage": "id",
 24                     "code": "id"
 25                 }
 26             ],
 27             "defaultMessage": "商品ID不能为空",
 28             "objectName": "goods",
 29             "field": "id",
 30             "rejectedValue": null,
 31             "bindingFailure": false,
 32             "code": "NotNull"
 33         }
 34     ],
 35     "message": "Validation failed for object='goods'. Error count: 1",
 36     "path": "/goods/save"
 37 }
 38 
 39 #测试英文
 40 curl -X POST -H "Accept-Language:en" "http://localhost:8080/goods/save"
 41 #返回:
 42 {
 43     "timestamp": "2020-05-20T04:16:15.078+0000",
 44     "status": 400,
 45     "error": "Bad Request",
 46     "errors": [
 47         {
 48             "codes": [
 49                 "NotNull.goods.id",
 50                 "NotNull.id",
 51                 "NotNull.java.lang.Integer",
 52                 "NotNull"
 53             ],
 54             "arguments": [
 55                 {
 56                     "codes": [
 57                         "goods.id",
 58                         "id"
 59                     ],
 60                     "arguments": null,
 61                     "defaultMessage": "id",
 62                     "code": "id"
 63                 }
 64             ],
 65             "defaultMessage": "Goods id cannot be empty",
 66             "objectName": "goods",
 67             "field": "id",
 68             "rejectedValue": null,
 69             "bindingFailure": false,
 70             "code": "NotNull"
 71         }
 72     ],
 73     "message": "Validation failed for object='goods'. Error count: 1",
 74     "path": "/goods/save"
 75 }
 76 
 77 #测试日文
 78 curl -X POST -H "Accept-Language:ja" "http://localhost:8080/goods/save"
 79 #返回:
 80 {
 81     "timestamp": "2020-05-20T04:16:35.011+0000",
 82     "status": 400,
 83     "error": "Bad Request",
 84     "errors": [
 85         {
 86             "codes": [
 87                 "NotNull.goods.id",
 88                 "NotNull.id",
 89                 "NotNull.java.lang.Integer",
 90                 "NotNull"
 91             ],
 92             "arguments": [
 93                 {
 94                     "codes": [
 95                         "goods.id",
 96                         "id"
 97                     ],
 98                     "arguments": null,
 99                     "defaultMessage": "id",
100                     "code": "id"
101                 }
102             ],
103             "defaultMessage": "商品IDは空にできません",
104             "objectName": "goods",
105             "field": "id",
106             "rejectedValue": null,
107             "bindingFailure": false,
108             "code": "NotNull"
109         }
110     ],
111     "message": "Validation failed for object='goods'. Error count: 1",
112     "path": "/goods/save"
113 }

6. 项目地址

  https://github.com/C3Stones/blog

posted @ 2020-05-20 23:58  C3Stones  阅读(1618)  评论(0编辑  收藏  举报