@Validated 对@Valid 进行了二次封装,在使用上并没有区别。推荐使用 @Validated。但在分组、注解位置、嵌套验证等功能上有所不同,这里主要就这几种情况进行说明。
不同点@Valid@Validated来源是Hibernate validation 的 校验注解是 Spring Validator 的校验注解,是 Hibernate validation 基础上的增加版注解位置用在 构造函数、方法、方法参数 和 成员属性上用在 类、方法和方法参数上。但不能用于成员属性嵌套验证用在级联对象的成员属性上面不支持分组无此功能提供分组功能,可以在入参验证时,根据不同的分组采用不同的验证机制这是最普通的校验。
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 String saveUser(@Valid User user, BindingResult bindingResult) { if (bindingResult.hasErrors()) { // 打印全部的错误信息 for (ObjectError error : bindingResult.getAllErrors()) { System.out.println(error.getDefaultMessage()); } } // 返回第一条的错误信息 if (bindingResult.hasErrors()) { String msg=bindingResult.getAllErrors().get(0).getDefaultMessage(); return msg; } }测试:
运行结果:
address 不能为空 userName不能为空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不能为空与对象校验 的唯一区别是 在关联对象的的 users 属性上加 @Valid 。
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()); } } }测试数据:
地址: http://127.0.0.1/user/saveItem
{ "id": 0, "users": [ { "uid": 11111, "userName": "北京时" } ] }测试结果:
address 不能为空 id必须为正整数从测试结果中可以看出,已经开校验 User 中 address 属性值不能为空。说明级联校验起作用了。
正确的数据:
{ "id":3333, "users": [ { "uid": 11111, "userName": "北京时", "address":"bbbb" } ] }1、在方法所在的类上添加 @Validated 。注意,此处 只能使用 @Validated 注解 ,@Valid 无效 ,因为 @Valid 不能用在类上。
2、对方法中的每个参数上加上所需的验证注解,如 @Rang, @Max,@Min、自定义注解 等注解 ;
3、定义 ConstraintViolationException 的异常拦截器 (这是系统全局 捕获异常。也可以使用BindingResult 捕获取异常,只是太繁琐了,不推荐使用)
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); } }@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; } /** * 拦截捕捉 MethodArgumentNotValidException 异常 */ @ExceptionHandler(MethodArgumentNotValidException.class) public Map doMethodArgumentNotValidException2(MethodArgumentNotValidException ex){ Map map = new HashMap(); map.put("status", 500); map.put("msg", "请求异常"); BindingResult result = ex.getBindingResult(); List<String> msgList = new ArrayList<String>(); if (result.hasErrors()) { List<ObjectError> errors = result.getAllErrors(); ObjectError error=errors.get(0); msgList.add(error.getDefaultMessage()); String firstMsg=msgList.get(0); map.put("msg", msgList); return map ; } return map ; } /** * 拦截捕捉 BindException 异常 */ @ExceptionHandler(BindException.class) @ResponseBody public R handleBindException(BindException ex) { List<FieldError> bindingResult = ex.getBindingResult().getFieldErrors(); List<String> msgList = new ArrayList<String>(); for (FieldError fieldError : bindingResult) { System.err.println(fieldError.getField() + " " + fieldError.getDefaultMessage()); msgList.add(fieldError.getDefaultMessage()); } String firstMsg = msgList.get(0); return R.error(firstMsg); } }测试数据:
grade=0 classroom=0测试结果:
班级最小只能1 年级只能从1-9略
略