技术栈:
spring boot 2.3.
hibernate-validator
文末附项目源代码
目录
简述
项目依赖
全局异常处理类
基础参数校验
实体类
控制类
测试
嵌套参数验证
实体类
控制类
测试
分组参数验证
接口类
实体类
控制类
测试
@Valid和@Validated 区别
简述
@Validation是一套帮助我们继续对传输的参数进行数据校验的注解,通过配置Validation可以很轻松的完成对数据的约束。
@Validated作用在类、方法和参数上
@Target({, , }) @Retention() @Documented public @interface Validated { Class<?>[] value() default {}; }
错误的状态码
返回的响应码推荐使用400 bad request.
所有参数注解含义
项目依赖
Maven 依赖坐标:
说明:在演示项目中所有实体类均在包entity,控制层均在包controller。
全局异常处理类
说明:若不做异常处理,@Validated注解的默认异常消息如下(示例):
2020-09-05 21:48:38.106 WARN 9796 --- [nio-8080-exec-3] . : Resolved [: Validation failed for argument [0] in public .validatedDemo1(): [Field error in object 'useDto' on field 'username': rejected value [null]; codes [,,,NotBlank]; arguments [: codes [,username]; arguments []; default message [username]]; default message [用户名不能为空!]] ]
因此我们在这里做了一个全局的异常处理类,用于处理参数校验失败后抛出的异常,同时进行日志输出。
package ;
import ;
import ;
import ;
import .slf4j.Slf4j;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
/**
* @author He Changjie on 2020/9/5
*/
@Slf4j
@ControllerAdvice
public class ValidatedExceptionHandler {
/**
* 处理@Validated参数校验失败异常
* @param exception 异常类
* @return 响应
*/
@ResponseBody
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler()
public Result exceptionHandler(MethodArgumentNotValidException exception){
BindingResult result = ();
StringBuilder stringBuilder = new StringBuilder();
if (()) {
List<ObjectError> errors = ();
if (errors != null) {
(p -> {
FieldError fieldError = (FieldError) p;
("Bad Request Parameters: dto entity [{}],field [{}],message [{}]",(), (), ());
(());
});
}
}
return (());
}
}
基础参数校验
实体类
package ;
import ;
import ;
import .*;
/**
* 用户实体
* 数据传输对象
* @author He Changjie on 2020/9/5
*/
@Data
public class User1Dto {
/**
* 用户名
*/
@NotBlank(message = "用户名不能为空!")
private String username;
/**
* 性别
*/
@NotBlank(message = "性别不能为空!")
private String gender;
/**
* 年龄
*/
@Min(value = 1, message = "年龄有误!")
@Max(value = 120, message = "年龄有误!")
private int age;
/**
* 地址
*/
@NotBlank(message = "地址不能为空!")
private String address;
/**
* 邮箱
*/
@Email(message = "邮箱有误!")
private String email;
/**
* 手机号码
*/
@Pattern(regexp = "^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\\d{8}$",message = "手机号码有误!")
private String mobile;
}
控制类
package ;
import .Use1Dto;
import ;
import ;
import ;
import ;
import ;
/**
* @author He Changjie on 2020/9/5
*/
@RestController
@RequestMapping("/api/v1")
public class Demo1Controller {
@PostMapping("/insert")
public String validatedDemo1(@Validated @RequestBody Use1Dto use1Dto){
(use1Dto);
return "success";
}
}
测试
1、参数校验通过:
2、参数校验不通过:
嵌套参数验证
验证实体中的其他需要被验证的对象集合或其他对象
实体类
package ;
import ;
import ;
import ;
import ;
import ;
/**
* 队伍实体
* 数据传输对象
* @author He Changjie on 2020/9/5
*/
@Data
public class Team1Dto {
/**
* 队伍名称
*/
@NotBlank(message = "队伍名称不能为空!")
private String name;
/**
* 队伍人员
*/
@NotNull(message = "队伍人员不能为空!")
@Valid
private List<User1Dto> userList;
/**
* 队伍负责人
*/
@NotNull(message = "队伍负责人不能为空!")
@Valid
private User1Dto user;
}
控制类
package ;
import ;
import .Team1Dto;
import .Use1Dto;
import ;
import ;
import ;
import ;
import ;
import ;
/**
* @author He Changjie on 2020/9/5
*/
@RestController
@RequestMapping("/api/v1")
public class Demo1Controller {
@PostMapping("/insert")
public Result validatedDemo1(@Validated @RequestBody Use1Dto use1Dto){
return (use1Dto);
}
@PostMapping("/insert2")
public Result validatedDemo2(@Validated @RequestBody Team1Dto team1Dto){
return (team1Dto);
}
}
测试
1、参数验证通过:
2、参数验证不通过:
分组参数验证
将不同的校验规则分给不同的组,在使用时,指定不同的校验规则
接口类
package ;
/**
* 校验分组1
* @author He Changjie on 2020/9/5
*/
public interface Group1 {
}
package ;
/**
* 校验分组2
* @author He Changjie on 2020/9/5
*/
public interface Group2 {
}
实体类
package ;
import .Group1;
import .Group2;
import ;
import .*;
/**
* @author He Changjie on 2020/9/5
*/
@Data
public class User2Dto {
/**
* 用户名
*/
@NotBlank(message = "用户名不能为空!", groups = {})
private String username;
/**
* 性别
*/
@NotBlank(message = "性别不能为空!")
private String gender;
/**
* 年龄
*/
@Min(value = 1, message = "年龄有误!", groups = {})
@Max(value = 120, message = "年龄有误!", groups = {})
private int age;
/**
* 地址
*/
@NotBlank(message = "地址不能为空!")
private String address;
/**
* 邮箱
*/
@Email(message = "邮箱有误!", groups = {})
private String email;
/**
* 手机号码
*/
@Pattern(regexp = "^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\\d{8}$",message = "手机号码有误!", groups = {})
private String mobile;
}
控制类
package ;
import ;
import .Team1Dto;
import .User1Dto;
import .User2Dto;
import .Group1;
import .Group2;
import ;
import ;
import ;
import ;
import ;
import ;
/**
* @author He Changjie on 2020/9/5
*/
@RestController
@RequestMapping("/api/v1")
public class Demo1Controller {
@PostMapping("/insert")
public Result validatedDemo1(@Validated @RequestBody User1Dto user1Dto){
return (user1Dto);
}
@PostMapping("/insert2")
public Result validatedDemo2(@Validated @RequestBody Team1Dto team1Dto){
return (team1Dto);
}
@PostMapping("/insert3")
public Result validatedDemo3(@Validated @RequestBody User2Dto user2Dto){
return (user2Dto);
}
@PostMapping("/insert4")
public Result validatedDemo4(@Validated() @RequestBody User2Dto user2Dto){
return (user2Dto);
}
@PostMapping("/insert5")
public Result validatedDemo5(@Validated() @RequestBody User2Dto user2Dto){
return (user2Dto);
}
}
测试
1、未分组校验通过:
2、未分组参数校验不通过:
3、分组1参数校验通过
4、分组1参数校验不通过
5、分组2参数校验通过
6、分组2参数校验不通过
7、使用默认分组,参数校验通过:
说明:将控制层/insert3接口调整如下后测试
@PostMapping("/insert3")
public Result validatedDemo3(@Validated() @RequestBody User2Dto user2Dto){
return (user2Dto);
}
为Validated依赖中含有的接口类,非自定义接口类
8、使用默认分组,参数校验不通过:
说明:同第7点相同操作
@Valid和@Validated 区别
通过源码分析:
@Target({, , , , ElementType.TYPE_USE})
@Retention()
@Documented
public @interface Valid {
}
@Target({, , })
@Retention()
@Documented
public @interface Validated {
Class<?>[] value() default {};
}
@Valid:没有分组的功能。
@Valid:可以用在方法、构造函数、方法参数和成员属性(字段)上
@Validated:提供了一个分组功能,可以在入参验证时,根据不同的分组采用不同的验证机制
@Validated:可以用在类型、方法和方法参数上。但是不能用在成员属性(字段)上
两者是否能用于成员属性(字段)上直接影响能否提供嵌套验证的功能
码云地址:/jie_harris/
手编不易,转载请注明来源
谢谢!