文章目录
1、@Valid 和 @Validated 的区别
@Validated
对@Valid 进行了二次封装,在使用上并没有区别。推荐使用 @Validated。但在分组、注解位置、嵌套验证等功能上有所不同,这里主要就这几种情况进行说明。
不同点 | @Valid | @Validated |
---|---|---|
来源 | 是Hibernate validation 的 校验注解 | 是 Spring Validator 的校验注解,是 Hibernate validation 基础上的增加版 |
注解位置 | 用在 构造函数、方法、方法参数 和 成员属性上 | 用在 类、方法和方法参数上。 但不能用于成员属性 |
嵌套验证 | 用在级联对象的成员属性上面 | 不支持 |
分组 | 无此功能 | 提供分组功能,可以在入参验证时,根据不同的分组采用不同的验证机制 |
2、 对象校验 (最普通)
这是最普通的校验。
public class User implements Serializable {
@NotNull(message = "uid不能为空")
@Min(value = 1, message = "pid必须为正整数")
private Long uid;
@NotBlank(message = "userName不能为空")
private String userName;
@NotBlank(message = "address 不能为空")
private String address;
// getter/setter
}
@RequestMapping("/user/saveUser")
public void saveUser(@Valid User user, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
for (ObjectError error : bindingResult.getAllErrors()) {
System.out.println(error.getDefaultMessage());
}
}
}
测试:
运行结果:
address 不能为空
userName不能为空
3、多个对象的校验
User 对象:
上面已经有了,本处省略。
Student 对象:
public class Student implements Serializable {
@NotNull(message = "sid不能为空")
@Min(value = 1, message = "pid必须为正整数")
private Long sid;
@NotBlank(message = "sUserName不能为空")
private String sUserName;
@NotBlank(message = "sAddress 不能为空")
private String sAddress;
//getter/setter
}
Controller:
定义 user、student 两个对象和对应的 bindingResult、bindingResult2 异常对象。
/**
* 多个对象校验
* @param user
* @param bindingResult
*/
@RequestMapping("/user/saveAll")
public void saveAll(@Validated User user, BindingResult bindingResult,@Validated Student student, BindingResult bindingResult2) {
if (bindingResult.hasErrors()) {
for (ObjectError error : bindingResult.getAllErrors()) {
System.out.println(error.getDefaultMessage());
}
}
System.out.println("-----------");
if (bindingResult2.hasErrors()) {
for (ObjectError error : bindingResult2.getAllErrors()) {
System.out.println(error.getDefaultMessage());
}
}
}
测试数据:
uid=1111
userName=xxxx
pid=2222
sAddress=bbbbb
测试结果:
address 不能为空
-----------
sid不能为空
sUserName不能为空
4、对象级联校验
与对象校验 的唯一区别是 在关联对象的的 users 属性上加 @Valid
。
4.1、配置:
Item 对象:
关联的 users 属性上,必须加上 @Valid
public class Item implements Serializable {
@NotNull(message = "id不能为空")
@Min(value = 1, message = "id必须为正整数")
private Long id;
@Valid
@NotNull(message = "users 不能为空")
@Size(min = 1, message = "users 至少要有一个属性")
private List<User> users;
}
User 对象:
User 上面已经有,本处省略。
Controller:
此处 ,既可以使用 @Valid
,也可以使用 @Validated
。如果使用分组,则只能使用 @Validated
。
@RequestMapping("/user/saveItem")
public void saveItem(@RequestBody @Validated Item item, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
for (ObjectError error : bindingResult.getAllErrors()) {
System.out.println(error.getDefaultMessage());
}
}
}
4.2、测试:
测试数据:
地址: http://127.0.0.1/user/saveItem
{
"id": 0,
"users": [
{
"uid": 11111,
"userName": "北京时"
}
]
}
测试结果:
address 不能为空
id必须为正整数
4.3、分析:
从测试结果中可以看出,已经开校验 User 中 address 属性值不能为空。说明级联校验起作用了。
正确的数据:
{
"id":3333,
"users": [
{
"uid": 11111,
"userName": "北京时",
"address":"bbbb"
}
]
}
5、方法级别的单个参数校验
1、在方法所在的类上添加 @Validated
。注意,此处 只能使用 @Validated
注解 ,@Valid
无效 ,因为 @Valid
不能用在类上。
2、为方法的每个参数上加上需要的验证注解,如 @Rang
, @Max
,@Min
等注解 ;
3、定义 ConstraintViolationException 的异常拦截器 (不加此步骤时,无法捕获异常)。
5.1、配置:
Controller :
@Validated //第1步,告诉MethodValidationPostProcessor此Bean需要开启方法级别验证支持
@RestController
public class ValidationController {
@RequestMapping(value = "/validation/demo")
public void demo1(
@Range(min = 1, max = 9, message = "年级只能从1-9") //第2步
@RequestParam(name = "grade", required = true) int grade, //
@Min(value = 1, message = "班级最小只能1") @Max(value = 99, message = "班级最大只能99") //第2步
@RequestParam(name = "classroom", required = true) int classroom) { //
System.out.println(grade + "," + classroom);
}
}
5.2、全局异常捕获:
@ControllerAdvice:
@ControllerAdvice
@Component
public class GlobalExceptionHandler {
/**
* 拦截捕捉 MissingServletRequestParameterException 异常
*/
@ResponseBody
@ExceptionHandler(value = MissingServletRequestParameterException.class)
public String doMissingServletRequestParameterHandler(MissingServletRequestParameterException exception) {
MissingServletRequestParameterException exs = (MissingServletRequestParameterException) exception;
System.err.println(exs.getMessage());
return "bad request, ";
}
/**
* 拦截捕捉 ConstraintViolationException 异常
*/
@ResponseBody
@ExceptionHandler(value = ConstraintViolationException.class)
public Map ConstraintViolationExceptionHandler(ConstraintViolationException ex) {
Map map = new HashMap();
Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations();
Iterator<ConstraintViolation<?>> iterator = constraintViolations.iterator();
List<String> msgList = new ArrayList<>();
while (iterator.hasNext()) {
ConstraintViolation<?> cvl = iterator.next();
System.err.println(cvl.getMessageTemplate());
msgList.add(cvl.getMessageTemplate());
}
map.put("status", 500);
map.put("msg", msgList);
return map;
}
}
5.3、测试:
测试数据:
grade=0
classroom=0
测试结果:
班级最小只能1
年级只能从1-9
6、分组校验
略
7、组序列 @GroupSequence
略