- @NotBlank(message = "品牌名必须提交",groups ={AddGroup.class,UpdateGroup.class})
- @Validated({AddGroup.class}),给校验注解标注什么情况需要进行校验
- 默认没有指定分组的字段校验使用注解@Valid,在分组校验情况下,只会在@Validated({AddGroup.class})生效;
- @Constraint(validatedBy = { ListValueConstraintValidator.class【可以指定多个不同的校验器,适配不同类型的校验】 })
- @ControllerAdvice
- 编写异常处理类,使用@ControllerAdvice。
- 使用@ExceptionHandler标注方法可以处理的异常。
@Data
public class RegisterVO {
@NotBlank(message = "用户名不能为空")
@Length(min = 4, max = 20, message = "用户名长度为4-20字符")
private String username;
@NotBlank(message = "密码不能为空")
@Length(min = 8, max = 16, message = "密码长度为8-16字符")
private String password;
@Pattern(regexp = "^1[3-9][0-9]{9}$", message = "手机号格式不合法")
private String phone;
@NotNull(message = "验证码不能为空")
@Pattern(regexp = "^[0-9]{6}$", message = "验证码为6位数字")
private String code;
}
@PostMapping("/register")
public String register(@Validated RegisterVO registerVO) {
// 校验出错会被异常处理器处理
return "success";
}
- 如果返回值是String,那么它也会被视图解析器处理,返回视图页面;
- 如果你想让它返回json数据,那么加上@ResponseBody注解即可;
- 如果你这个类所有方法最终都不返回视图,只返回json,那么很简单,直接把@
ControllerAdvice换成@RestControllerAdvice即可。
现在我们使用下面这个异常处理来处理对前端传来的数据RegisterVO 进行校验的结果。当数据校验失败时,会抛出异常,会抛出哪个异常呢,我们先直接使用Exception.class来接收,使用它总是没错的。
@ControllerAdvice
public class AuthExceptionHandler {
/\*\*
\* 注册,表单提交数据格式校验失败;返回json数据
\* @param e
\* @return
\*/
@ResponseBody
@ExceptionHandler({Exception.class})
public Map<String, String> exceptionHandler(Exception e) {
BindingResult bindingResult = e.getBindingResult();
// 使用stream api
Map<String, String> map = bindingResult.getFieldErrors()
.stream()
.collect(Collectors.toMap(FieldError::getField, FieldError::getDefaultMessage));
// 上面那种是种简写,如果你不熟悉,这样也可以
// Map<String, String> map = new HashMap<>();
// bindingResult.getFieldErrors().forEach(fieldError -> {
// String field = fieldError.getField();
// String message = fieldError.getDefaultMessage();
// map.put(field, message);
// });
return map;
}
}
然后我们让前端提交一个全空的数据
我们期待的返回给我们校验结果,以json数据返回。但是它报错了!!!
java.lang.IllegalStateException: Duplicate key 用户名长度为4-20字符
DuplicateKey一般是两个相同键出现,比如你在数据库插入两条id字段相同的记录,假设id是唯一索引,此时就会抛出DuplicateKeyXXXException,仔细查看报错内容,发现出错的代码位置
at com.vivi.auth.exception.AuthExceptionHandler.bindingExceptionHandler(AuthExceptionHandler.java:38)
也就是我们写的异常处理的这一行
Map<String, String> map = bindingResult.getFieldErrors().stream().collect(Collectors.toMap(FieldError::getField, FieldError::getDefaultMessage));
所以可以得出结果,肯定是这个校验结果是,某个key出现了两次,导致无法封装成功,因此他也不知道同一个键,第二次的值是要丢掉还是替换第一个呢?
所以这两个相同键是哪里来的?还记得我开始写的 RegisterVO 类么,有些字段上面有两个校验注解,那么是这个原因么,我们可以在异常处理方法上debug,在它封装成map之前,看一下它这个校验结果里面有什么
我们发现有6个校验错误,其中 username 和 password 都出现了两次,正如我们的校验注解缩写,每个字段都有两个校验
@NotBlank(message = "用户名不能为空")
@Length(min = 4, max = 20, message = "用户名长度为4-20字符")
private String username;
@NotBlank(message = "密码不能为空")
@Length(min = 8, max = 16, message = "密码长度为8-16字符")
private String password;
我们在点开看一下,比如 username 的两个结果,是不是我们的校验注解所写的message,的确是的!
bindingResult.getFieldErrors().forEach(fieldError -> {
String field = fieldError.getField();
String message = fieldError.getDefaultMessage(); // 当次结果
String msg = map.getOrDefault(field, ""); // 上次校验结果
map.put(field, msg + "," + message); // 连接起来再赋值
});
最后,还有一个问题,就是之前说的 **数据校验失败抛出的异常到底是什么类型**?
我这里简单说一下,有兴趣的朋友可以自己翻翻源码。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。