Spring Boot 注解探秘:@Validated 开启数据验证之旅(下)

今天我们继续来探究自定义验证规则以及@Validated结合@RestControllerAdvice实现全局异常处理。

首先来看自定义验证规则。假设有一个场景,需要批量解绑手机号和微信, 为了确保请求数据的有效性和一致性,我们应当如何对请求参数进行严格的校验呢?

首先,创建用于数据验证的实体类。

@Data
public class Account{
    
    @NotBlank(message = "手机号不能为空")
    @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
    private String phone;
    
    @NotBlank(message = "微信号不能为空")
    private String weChat;
}

接下来,在controller层,定义处理解绑请求的方法。

@RequestMapping("/account")
@Validated
public class Demo{
    @PostMapping("/unbind")
    Response unbind(@valid @ValidUnbindAccount @RequestBody List list){ 
        ……               
    }
}

这里简单聊聊@Validated和@Valid的差异。

  • @Validated支持更细粒度的方法参数级别的校验,同时其针对多场景,可以采用分组校验。
  • @Valid是面向整个对象做校验。以下是代码示例。
@RequestMapping("/account")
@Validated
public class Demo{
    // @Valid针对对象使用
    @PostMapping("/unbind")
    Response unbind(@valid @ValidUnbindAccount @RequestBody List list){ 
        ……               
    }
    
    // @Validated 具体参数可用
    @GetMapping("/getWechat")
    Response getWechat(@NotBlank(message = "用户ID不能为空") String userId){ 
        ……               
    }
}

然后,创建@ValidUnbindAccount注解。

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validateBy = UnbindAccountValidator.class)
public @interface ValidUnbindAccount {
    String message() default "",
    Class[] group() default {},
    Class[] payload() default {};
}

紧接着,创建对应的验证器UnbindAccountValidator类。

public class ValidUnbindAccount implements ConstraintValidator>{
    
    @Override
    public boolean isValid(List accountList, ConstraintValidatorContext constraintValidatorContext) {
    if(ObjectUtils.isEmpty(accountList) || accountList.size() < 1){
        return false;
    }
    // 手机号准确性或者微信号准确性的更多细节校验逻辑可以放到这里, 欢迎大家评论区探讨。
    return true;
}

最后,通过@RestControllerAdvice创建全局异常处理类。

@RestControllerAdvice
public class GlobalExceptionHandler{

    @ResponseBody
    @ExceptionHandler(Throwable.class)
    public Response handleException(Throwable ex){
        if(e instanceof MethodArgumentNotValidException){
           String msg = ex.getBindingResult().getFieldErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining(","))
           return Response.fail(HttpStatus.BAD_REQUEST.value(), msg)
        }
        if(e instanceOf BizRuntimeException){
           return Response.fail(ex.getMessage())
        }
    }
}

当向/account/unbind接口发送请求时,如果传入的list为空或者list的size< 1都会抛出

MethodArgumentNotValidException异常。全局异常处理类会捕获这个异常,并将错误信息以 JSON 格式返回给客户端,状态码为400 Bad Request。此外,如果urI找不到或者请求到达service层处理时发生异常(如数据索引越界,空指针异常等),全局异常处理类业会捕获该异常,并响应给客户端。

你可能感兴趣的:(spring,boot,java,后端,springcloud)