引入依赖
<dependency><groupId>javax.validation</groupId><artifactId>validation-api</artifactId><version>2.0.1.Final</version>
</dependency>
<dependency><groupId>org.hibernate.validator</groupId><artifactId>hibernate-validator</artifactId><version>6.0.20.Final</version>
</dependency>
入参校验
参数字段上使用校验注解 例: @NotNull(message = “客户id不能为空”)
@Data
@EqualsAndHashCode(callSuper = false)
@ApiModel(value="####", description="")
public class AddParam implements Serializable {@ApiModelProperty(value = "客户id")@NotNull(message = "客户id不能为空")private Long customerId;}
控制层使用 @Validated 注解
@ApiOperation("####")@PostMapping("add")@Transactionalpublic JsonData addMedical(@RequestBody @Validated AddParam addParam) {return JsonData.buildSuccess();}
异常处理
处理Get请求,抛出BindException异常
处理请求参数格式错误 @RequestParam上,抛出ConstraintViolationException异常
处理请求参数格式错误 @RequestBody上,抛出MethodArgumentNotValidException
@ControllerAdvice
@Slf4j
public class ExceptionHandle{/*** 校验错误拦截处理* 处理Get请求中 使用@Valid 验证路径中请求实体校验失败后抛出的异常** @param exception 错误信息集合* @return 错误信息*/@ResponseBody@ExceptionHandler(BindException.class)@ResponseStatus(HttpStatus.BAD_REQUEST)public BaseResponse bindExceptionHandler(BindException exception) {log.error("BindException encountered: {0}", exception);String message =exception.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining());return BaseResponse.newError("YourProjectName_BindException", message);}/*** 校验错误拦截处理* 处理请求参数格式错误 @RequestParam上validate失败后抛出的异常是javax.validation.ConstraintViolationException** @param exception 错误信息集合* @return 错误信息*/@ResponseBody@ExceptionHandler(ConstraintViolationException.class)@ResponseStatus(HttpStatus.BAD_REQUEST)public BaseResponse constraintViolationHandler(ConstraintViolationException exception) {log.error("ConstraintViolation exception encountered: {0}", exception);return BaseResponse.newError("YourProjectName_ConstraintViolation", exception.getMessage());}/*** 校验错误拦截处理* 处理请求参数格式错误 @RequestBody上validate失败后抛出的异常是MethodArgumentNotValidException异常。** @param exception 错误信息集合* @return 错误信息*/@ResponseBody@ExceptionHandler(MethodArgumentNotValidException.class)@ResponseStatus(HttpStatus.BAD_REQUEST)public BaseResponse methodArgumentNotValidHandler(MethodArgumentNotValidException exception) {log.error("MethodArgumentNotValid exception encountered: {0}", exception);BindingResult bindingResult = exception.getBindingResult();StringBuilder sb = new StringBuilder();for (FieldError fieldError : bindingResult.getFieldErrors()) {sb.append(fieldError.getField()).append(": ").append(fieldError.getDefaultMessage()).append(", ");}return BaseResponse.newError("YourProjectName_MethodArgumentNotValid", sb.toString());}
}
配置多个请求参数校验失败,则遇到一个校验失败就抛出异常,接下来的异常参数不做校验
@Configuration
public class ValidatorConfig {@Beanpublic Validator validator() {ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class).configure()//failFast的意思只要出现校验失败的情况,就立即结束校验,不再进行后续的校验。.failFast(true).buildValidatorFactory();return validatorFactory.getValidator();}@Beanpublic MethodValidationPostProcessor methodValidationPostProcessor() {MethodValidationPostProcessor methodValidationPostProcessor = new MethodValidationPostProcessor();methodValidationPostProcessor.setValidator(validator());return methodValidationPostProcessor;}
}
校验时常用注解
- @Valid 递归的对关联对象进行校验,如果关联对象是个集合或者数组,那么对其中的元素进行递归校验
- @Pattern(value) 符合指定的正则表达式(校验非法字符)
- @NotNull 参数不为 null
- @NotEmpty 参数不能为null,或者是空
- @NotBlank() 参数不能为null,或者被Trim的长度是否大于0(可以用来校验全为空格字符)
- @Min() 一个数字,值大于给定值
- @Max() 一个数字,值小于给定值
- @Digits (integer, fraction) 一个数字,其值必须在可接受的范围内
注解常用案例
@Pattern(regexp = "^[\\u4E00-\\u9FA5\\w\\-]{1,57}$", message = "只能包含中文字符、英文字符、数字、下划线和中横线,1~57个字符")@Pattern(regexp = "^((?!=|\\+|-|@|>|<|%).)((?!>|<|%).){0,127}$", message = "不能以=,+,-或@开头,不能包含<,>和%字符,最长为128个字符")@Pattern(regexp = "^(?:false|true)$", message = "只支持false/true")@Pattern(regexp = "^[A-Za-z0-9]{32}$", message = "只能是32位的uuid(只有英文和字母)")@Pattern(regexp = "^[\\w-.;]{1,100}$", message = "最长为100,只能包含英文、数字、“-”、“_”、“;”")@Pattern(regexp = "^[/][/\\w-.]{1,254}$",message = "须以“/”开头,只能包含字母、数字、“/”、“_”、“-”和“.”," + "长度不少于2位,长度最长为255")@Pattern(regexp = "^(?:A|B)$", message = "类型必须为A或者B")@Max(value = 2_140_000_000, message = "只能大于0小于2140000")
@Min(value = 0, message = "只能大于0小于2140000")@Max(value = 5000, message = "分页大小在【1,5000】之间")
@Min(value = 1, message = "分页大小在【1,5000】之间")@Digits(integer = 1, fraction = 0, message = "只能为0或1")
@Max(value = 1, message = "只能为0或1")
@Min(value = 0, message = "只能为0或1")@NotEmpty(message = "缺少必要的参数,数组classIds不能为null,或者长度为0")private List<@Pattern(regexp = "^[a-zA-Z\\d]{32}$", message = "id仅由字母和数字组成,且长度为32个字符")@NotEmpty(message = "id不能为null或者为空") String>classIds;
自定义注解
自定义注解名称
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = ParamValidator.class)
public @interface RetryTimes {String message() default "重试次数只能为1,2,4,8";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};
}
实现ConstraintValidator类
public class ParamValidator implements ConstraintValidator<RetryTimes, Short> {private static final Pattern PATTERN = Pattern.compile("^(?:0|5|10|20|50|100)$");@Overridepublic boolean isValid(Short retryTimes, ConstraintValidatorContext constraintValidatorContext) {return PATTERN.matcher(retryTimes.toString()).matches();}
}
使用注解
@RetryTimes
private short retryTimes;