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 @   Lz_蚂蚱  阅读(60)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起