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

Validated 注解完成 Spring Boot 参数校验的更多相关文章

  1. Spring Boot 参数校验

    1.背景介绍 开发过程中,后台的参数校验是必不可少的,所以经常会看到类似下面这样的代码 这样写并没有什么错,还挺工整的,只是看起来不是很优雅而已. 接下来,用Validation来改写这段 2.Spr ...

  2. Spring Boot参数校验

    1. 概述 作为接口服务提供方,非常有必要在项目中加入参数校验,比如字段非空,字段长度限制,邮箱格式验证等等,数据校验常用到概念:JSR303/JSR-349: JSR303是一项标准,只提供规范不提 ...

  3. spring boot输入数据校验(validation)

    Spring Boot 集成教程 Spring Boot 介绍 Spring Boot 开发环境搭建(Eclipse) Spring Boot Hello World (restful接口)例子 sp ...

  4. spring mvc注解和spring boot注解

    1 spring mvc和spring boot之间的关系 spring boot包含spring mvc.所以,spring mvc的注解在spring boot总都是可以用的吗? spring b ...

  5. spring boot 参数传递(spring boot 参数传数 arg0 每一个参数 arg0#{arg0},arg1 #{arg1})

    spring boot 参数传数 arg0 每一个参数 arg0#{arg0},arg1  #{arg1} @Select("select * from sys_user where nam ...

  6. 使用AOP+自定义注解完成spring boot的接口权限校验

    记使用AOP+自定义注解完成接口的权限校验,代码如下: pom文件添加所需依赖: 1 <dependency> 2 <groupId>org.aspectj</group ...

  7. Spring boot validation校验

    使用 Hibernate validator 的步骤:1. 在 Pojo 类的字段上, 加上 Hibernate validator 注解2. 在Controller 函数的形参前加上 @Valid ...

  8. spring boot参数验证

    必须要知道 简述 JSR303/JSR-349,hibernate validation,spring validation 之间的关系 JSR303 是一项标准,JSR-349 是其的升级版本,添加 ...

  9. Spring Boot (一) 校验表单重复提交

    一.前言 在某些情况下,由于网速慢,用户操作有误(连续点击两下提交按钮),页面卡顿等原因,可能会出现表单数据重复提交造成数据库保存多条重复数据. 存在如上问题可以交给前端解决,判断多长时间内不能再次点 ...

随机推荐

  1. 5、Spring Boot缓存

    1.JSR107 Java Caching定义了5个核心接口,分别是CachingProvider.CacheManager.Cache.Entry.Expiry. CachingProvider:定 ...

  2. android下vulkan与opengles纹理互通

    先放demo源码地址:https://github.com/xxxzhou/aoce 06_mediaplayer 效果图: 主要几个点: 用ffmpeg打开rtmp流. 使用vulkan Compu ...

  3. python-网络安全编程第十天(web目录扫描&&fake_useragent模块&&optionParser模块)

    前言 昨天的内容没有完成今天花了点时间继续完成了 感觉自己的学习效率太低了!想办法提高学习效率吧 嗯 ,再制定下今天的目标 开始健身. python fake_useragent模块 1.UserAg ...

  4. Guitar Pro教程之理解记谱法

    前面的章节我们讲解了很多关于Guitar Pro'的功能使用,今天小编还是采用图文结合的方式为大家讲解它的理解记谱法,对于很多新人来说,在我们看谱之前,我们肯定要先熟悉他的一些功能如何使用以及一些关于 ...

  5. 理解与使用Treiber Stack

    目录 背景 名称由来 CompletableFuture源码实现 FutureTask实现 Treiber Stack抽象实现 入栈 出栈 示例 参考 背景 最近在很多JDK源码中都看到了Treibe ...

  6. Java之 循环(三)

    1. switch语句 1.1 分支语句switch语句 格式 switch (表达式) { case 1: 语句体1; break; case 2: 语句体2; break; ... default ...

  7. CENTOS 7平滑升级PHP到最新版7.3

    安装Remi和EPEL数据源(仓库) rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm r ...

  8. linux(cemtos7.x)安装docker

    卸载旧版本 yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest ...

  9. Java中的接口与抽象类的区别

    由于随着jdk版本的更新,在jdk1.8时,接口也增强了,所以我们分别来说明一下. (1)jdk1.8之前 在jdk1.8之前,接口里面只能定义抽象方法和常量:而抽象类比普通类有一点不同,就是抽象类里 ...

  10. 经历与感想丨第15届CSUST-ACM程序大赛

    这算是我的第一次较正式的\(ACM\)团队比赛吧,真的感谢@dj.@qc两位大佬. 开局就选了最后一题(因为哈希是他们集训队的猫),但三人无啥思路,于是溜回A题(发现有不少人已经过了).dj很快进入状 ...