5.Validation数据校验

级联校验

级联校验,就是在一个类A中设置的属性类型是另一个类B,我们对类A中的属性设置@NotNull等注解校验时,如果也想同时对类B中属性进行校验
这时就需要级联校验了,如何级联校验,就需要在类A中的属性类型是类B的属性上加上注解@Valid

public class PersonVO {
    @Valid
    private SchoolVO schoolVO;
}
public class SchoolVO {
    @NotBlank
    private String name;
}

参数校验

参数校验,在Controller类接口方法属性中如果只是普通参数(不是实体类),我们对属性进行校验如果只是单单加了@NotNull等注解不会生效,
需要在Controller类上加上注解@Validated才会生效。

@RestController
@RequestMapping("/curl-test")
@Validated
public class DemoController {
    @PostMapping("/id")
    public void testRequestBody(@NotBlank String id) {}
}

@Valid与@Validated区别

  • @Valid不能使用分组校验,@Validated可以使用分组校验,
  • @Validated是spring提供的注解,@Valid校验规范提供的注解

BindingResult

想要获取注解校验结果(异常信息),可以在参数列表中加上BindingResult bindingResult,通过bindingResult可以获取错误等信息。BindingResult用在实体类校验信息返回结果绑定。

举个例子:

@RestController
@RequestMapping("/binding")
@Slf4j
public class BindingResultController {

    @PostMapping("/result")
    public RestResult testBindingResult(@RequestBody @Validated Param param) {
        log.info("test bindingResult param:{}", JSONObject.toJSONString(param));
        System.out.println("请求处理成功");
        return RestResult.successResult();
    }

}
@Data
public class Param {

    @NotBlank(message = "名字不能为空")
    private String name;

    @NotNull(message = "年龄不能为空")
    @Min(value = 18, message = "年龄不能小于18")
    @Max(value = 30, message = "年龄不能大于30")
    private Integer age;

    @NotNull(message = "手机号不能为空")
    private String phone;

}

请求结果:

请求结果异常,但是不是正常我们定义的响应格式。我们期望返回结果如下格式:

{
    "code": 1,
    "success": false,
    "errMsg": "年龄不能小于18",
    "data": null
}

方式一 添加BindingResult类

第一种方法,我们可以直接在controller中通过BindingResult类,返回校验结果看是否有参数错误。

@RestController
@RequestMapping("/binding")
@Slf4j
public class BindingResultController {

    /**
     * 添加BindingResult处理校验异常返回结果
     *
     * @param param
     * @param bindingResult
     * @return
     */
    @PostMapping("/result")
    public RestResult testBindingResult(@RequestBody @Validated Param param, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return RestResult.failResult(bindingResult.getFieldError().getDefaultMessage());
        }

        log.info("test bindingResult param:{}", JSONObject.toJSONString(param));
        System.out.println("请求处理成功");
        return RestResult.successResult();
    }


}

BindingResult:

方式二 统一异常处理

当项目中多处出现参数校验的时候,使用统一异常处理,参数校验错误后,会抛出一个MethodArgumentNotValidException异常,我们可以捕获这个异常并处理。就不用在每个方法上都写BindingResult和异常判断。

@RestController
@RequestMapping("/binding")
@Slf4j
public class BindingResultController {

    @PostMapping("/result")
    public RestResult testBindingResult(@RequestBody @Validated Param param) {
        log.info("test bindingResult param:{}", JSONObject.toJSONString(param));
        System.out.println("请求处理成功");
        return RestResult.successResult();
    }


}

统一异常处理:

@RestControllerAdvice
public class GlobalExceptionHandle {
    
     /**
     * 处理参数校验异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public RestResult notValidExceptionHandle(MethodArgumentNotValidException e) {
        BindingResult bindingResult = e.getBindingResult();
        Objects.requireNonNull(bindingResult.getFieldError());
        // 这里错误码可以使用自定义的错误码枚举
        return RestResult.failResult(ErrorCodeEnum.ERROR_INCOMPLETE_RESULT.getCode(),
                bindingResult.getFieldError().getField() + " " + bindingResult.getFieldError().getDefaultMessage());
    }

    @ExceptionHandler({BindException.class})
    public RestResult MethodArgumentNotValidExceptionHandler(BindException e) {
        // 从异常对象中拿到ObjectError对象
        ObjectError objectError = e.getBindingResult().getAllErrors().get(0);
        return RestResult.failResult(ErrorCodeEnum.ERROR_INCOMPLETE_RESULT.getCode(), objectError.getDefaultMessage());
    }
    
}

错误码枚举类:

public enum ErrorCodeEnum {

    SUCCESS(0, "请求成功"),
    ERROR(500, "未知异常"),
    ERROR_EMPTY_RESULT(1001, "查询结果为空"),
    ERROR_INCOMPLETE_RESULT(1002, "请求参数异常");

    private int code;
    private String message;

    ErrorCodeEnum(int code, String message) {
        this.code = code;
        this.message = message;
    }

    public int getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }
}

参数校验异常返回结果:

JSR303数据校验

JSR303数据校验 , 这个就是我们可以在字段上增加一层过滤器验证 , 可以保证数据的合法性

spring-boot中可以用@validated来校验数据,如果数据异常则会统一抛出异常,方便异常中心统一处理。

我们这里来写个注解让我们的name只能支持Email格式:

注意:一定要写@Validated注解后才能使用校验

@Component //注册bean
@ConfigurationProperties(prefix = "person")
@Validated  //数据校验
public class Person {

    //@Value("${person.name}")
    @Email //name必须是邮箱格式
    private String name;
}

查看源码:

posted @ 2022-09-12 18:07  Lz_蚂蚱  阅读(65)  评论(0)    收藏  举报