【后端】@Validated校验踩坑记录

139 阅读1分钟

前言:下午着手开发毕设的后端,写到注册接口时,需要校验表单字段。form类写了各字段校验规则,校验却没有生效。

错误实践
// controller类
@PostMapping("register")
public Result<String> register(@RequestBody @Validated UserForm form) {
    UserDTO dto = UserDTO.toDTO(form);
    userService.register(dto);
    return ResultUtil.success("注册成功");
}
// form类
@Data
public class UserForm {
    @NotBlank(message = "用户名不能为空")
    @Size(min = 2, max = 6, message = "用户名不得少于两位或多于六位")
    private String username;

    @NotEmpty(message = "密码不得为空")
    @Size(min = 2, max = 6, message = "密码不得少于两位或多于六位")
    private String password;

    private String realName;

    private String avatar;

    private Integer gender;

    @Email
    private String email;

    @Pattern(regexp = "^1[3-9]\d{9}$", message = "手机号码格式不正确")
    private String phone;
}
implementation 'org.springframework.boot:spring-boot-starter-validation'
核心原因为没有添加捕获校验失败的异常方法

在UserController类中加入捕获方法即可正常抛出错误校验

// controller类
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result<String> handleValidationException(MethodArgumentNotValidException ex) {
    BindingResult bindingResult = ex.getBindingResult();
    List<FieldError> errors = bindingResult.getFieldErrors();
    StringBuilder errorMessage = new StringBuilder();
    for (FieldError error : errors) {
        errorMessage.append(error.getDefaultMessage()).append("; ");
    }
    return ResultUtil.error(errorMessage.toString());
}
这时大坑来了,每个控制器类写一段肯定不现实,要抽出来当全局方法,我在controller的同级下新建exception目录,写入GlobalExceptionHandler类
// exception目录下的全局方法
@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<String> handleValidationException(MethodArgumentNotValidException ex) {
        BindingResult bindingResult = ex.getBindingResult();
        List<FieldError> errors = bindingResult.getFieldErrors();
        StringBuilder errorMessage = new StringBuilder();
        for (FieldError error : errors) {
            errorMessage.append(error.getDefaultMessage()).append("; ");
        }
        return ResultUtil.error(errorMessage.toString());
    }
}

这样写后捕获异常就无法生效了,痛苦了许久,东找西找,最后在换注解的时候,发现是注解的问题,需要与controller上的注解相对应

我的UserController注解为@RestController,而捕获类的注解为@ControllerAdvice,导致了无法生效,改为@RestControllerAdvice注解即可

问题核心&&最佳实践
@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<String> handleValidationException(MethodArgumentNotValidException ex) {
        BindingResult bindingResult = ex.getBindingResult();
        List<FieldError> errors = bindingResult.getFieldErrors();
        StringBuilder errorMessage = new StringBuilder();
        for (FieldError error : errors) {
            errorMessage.append(error.getDefaultMessage()).append("; ");
        }
        return ResultUtil.error(errorMessage.toString());
    }
}

一壶茶,一包烟,一个异常修一天