一、单个基本类型的包装类进行校验
-
@Validated 声明要检查的参数
这里我们在控制器层进行注解声明@PostMapping("/save/valid")
public RspDTO save(@RequestBody @Validated UserDTO userDTO) {
userService.save(userDTO);
return RspDTO.success();
} 对参数的字段进行注解标注
/**
-
@Description: 用户传输对象
*/
@Data
public class UserDTO implements Serializable {private static final long serialVersionUID = 1L;
/*** 用户ID*/
@NotNull(message = "用户id不能为空")
private Long userId;/** 用户名/
@NotBlank(message = "用户名不能为空")
@Length(max = 20, message = "用户名不能超过20个字符")
@Pattern(regexp = "^[\u4E00-\u9FA5A-Za-z0-9\]*$", message = "用户昵称限制:最多20字符,包含文字、字母和数字")
private String username;/** 手机号*/
@NotBlank(message = "手机号不能为空")
@Pattern(regexp = "^[1][3,4,5,6,7,8,9][0-9]{9}$", message = "手机号格式有误")
private String mobile;/*性别/
private String sex;/** 邮箱*/
@NotBlank(message = "联系邮箱不能为空")
@Email(message = "邮箱格式不对")
private String email;/** 密码*/
private String password;/*** 创建时间 */
@Future(message = "时间必须是将来时间")
private Date createTime;
}
- 在全局校验中增加校验异常
MethodArgumentNotValidException是springBoot中进行绑定参数校验时的异常,需要在springBoot中处理,其他需要
处理ConstraintViolationException异常进行处理.
为了优雅一点,我们将参数异常,业务异常,统一做了一个全局异常,将控制层的异常包装到我们自定义的异常中
为了优雅一点,我们还做了一个统一的结构体,将请求的code,和msg,data一起统一封装到结构体中,增加了代码的复用性
/**
-
@Description: 全局异常处理器
*/
@RestControllerAdvice
public class GlobalExceptionHandler {private Logger logger = LoggerFactory.getLogger(getClass());
private static int DUPLICATE_KEY_CODE = 1001;
private static int PARAM_FAIL_CODE = 1002;
private static int VALIDATION_CODE = 1003;/**
- 处理自定义异常
*/
@ExceptionHandler(BizException.class)
public RspDTO handleRRException(BizException e) {
logger.error(e.getMessage(), e);
return new RspDTO(e.getCode(), e.getMessage());
}
/**
- 方法参数校验
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public RspDTO handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
logger.error(e.getMessage(), e);
return new RspDTO(PARAM_FAIL_CODE, e.getBindingResult().getFieldError().getDefaultMessage());
}
/**
- ValidationException
*/
@ExceptionHandler(ValidationException.class)
public RspDTO handleValidationException(ValidationException e) {
logger.error(e.getMessage(), e);
return new RspDTO(VALIDATION_CODE, e.getCause().getMessage());
}
/**
- ConstraintViolationException
*/
@ExceptionHandler(ConstraintViolationException.class)
public RspDTO handleConstraintViolationException(ConstraintViolationException e) {
logger.error(e.getMessage(), e);
return new RspDTO(PARAM_FAIL_CODE, e.getMessage());
}
@ExceptionHandler(NoHandlerFoundException.class)
public RspDTO handlerNoFoundException(Exception e) {
logger.error(e.getMessage(), e);
return new RspDTO(404, "路径不存在,请检查路径是否正确");
}@ExceptionHandler(DuplicateKeyException.class)
public RspDTO handleDuplicateKeyException(DuplicateKeyException e) {
logger.error(e.getMessage(), e);
return new RspDTO(DUPLICATE_KEY_CODE, "数据重复,请检查后提交");
}@ExceptionHandler(Exception.class)
public RspDTO handleException(Exception e) {
logger.error(e.getMessage(), e);
return new RspDTO(500, "系统繁忙,请稍后再试");
}
} - 处理自定义异常
二、自定义对象的校验
自定义对象可能用在不同的场景,校验规则不一样,比如新增申请单的时候要求id可以为null,但是修改申请单的时候就必须要求修改的申请单的id不能为空,但是二者又是使用的同一个业务对象,这时候我们就是需要使用分组校验了。具体步骤如下:
定义校验分组
首先我们要定义为了分组校验所使用的分组,其实就是一些空的接口。
-
然后在业务对象上定义校验规则和校验规则所生效的分组,如果不定义分组,则默认所有分组都生效。
-
最后在需要校验的方法上去加上校验所使用的分组,然后参数校验规则就会生效了。
-
为了给前端一个友好的提示,需要对参数校验不满足抛出的异常进行统一的处理,使不满足的规则具有易读性,大家可以看到我针对参数校验抛出的异常定义了二个异常处理器,因为不同的参数校验框架,抛出的异常不一样,而且抛出异常里面封装的对象格式不一样。因为我使用了多个参数校验框架,原生的validate-api抛出的是ConstraintViolationException,但是其支持的校验的规则有限,比如针对字符串只支持notNull,但是我们其实想的是NotEmpty,就是不仅仅是null,还不能是空字符串。这之后就要使用spring或者hibernate扩展的校验,这时候每个框架校验抛出的异常就不一样,需要做不同的处理。
统一参数校验validator 注解
https://www.jianshu.com/p/db2a735d9d2b
-