高效使用hibernate-validator校验框架

一、前言高效、合理的使用hibernate-validator校验框架可以提高程序的可读性,以及减少不必要的代码逻辑。接下来会介绍一下常用一些使用方式。二、常用注解说明限制说明@Null限制只能为null@NotNull限制必须不为null@AssertFalse限制必须为false@AssertTrue限制必须为true@DecimalMax(value)限制必须为一个不大于指定值的数字@Dec...

高效使用hibernate-validator校验框架

一、前言

  高效、合理的使用hibernate-validator校验框架可以提高程序的可读性,以及减少不必要的代码逻辑。接下来会介绍一下常用一些使用方式。

二、常用注解说明

限制说明
@Null限制只能为null
@NotNull限制必须不为null
@AssertFalse限制必须为false
@AssertTrue限制必须为true
@DecimalMax(value)限制必须为一个不大于指定值的数字
@DecimalMin(value)限制必须为一个不小于指定值的数字
@Digits(integer,fraction)限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction
@Future限制必须是一个将来的日期
@Max(value)限制必须为一个不大于指定值的数字
@Min(value)限制必须为一个不小于指定值的数字
@Past限制必须是一个过去的日期
@Pattern(value)限制必须符合指定的正则表达式
@Size(max,min)限制字符长度必须在min到max之间
@Past验证注解的元素值(日期类型)比当前时间早
@NotEmpty验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0)
@NotBlank验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的空格
@Email验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式

三、定义校验分组

public class ValidateGroup { public interface FirstGroup { } public interface SecondeGroup { } public interface ThirdGroup { }}

四、定义校验Bean

@Validated@GroupSequence({ValidateGroup.FirstGroup.class, BaseMessageRequestBean.class})public class BaseMessageRequestBean { //渠道类型 @NotNull(message = "channelType为NULL", groups = ValidateGroup.FirstGroup.class) private String channelType; //消息(模板消息或者普通消息) @NotNull(message = "data为NUll", groups = ValidateGroup.FirstGroup.class)
@Valid
private Object data; //业务类型 @NotNull(message = "bizType为NULL", groups = ValidateGroup.FirstGroup.class) private String bizType; //消息推送对象 @NotBlank(message = "toUser为BLANK", groups = ValidateGroup.FirstGroup.class) private String toUser; private long createTime = Instant.now().getEpochSecond(); ......}

  请自行参考:@Validated和@Valid区别

五、validator基本使用

@RestControllerpublic class TestValidatorController { @RequestMapping("/test/validator") public void test(@Validated BaseMessageRequestBean bean){
... }}

  这种使用方式有一个弊端,不能自定义返回异常。spring如果验证失败,则直接抛出异常,一般不可控。

六、借助BindingResult

@RestControllerpublic class TestValidatorController { @RequestMapping("/test/validator") public void test(@Validated BaseMessageRequestBean bean, BindingResult result){  result.getAllErrors();  ... }}

  如果方法中有BindingResult类型的参数,spring校验完成之后会将校验结果传给这个参数。通过BindingResult控制程序抛出自定义类型的异常或者返回不同结果。

七、全局拦截校验器

  当然了,需要在借助BindingResult的前提下...

@Aspect@Componentpublic class ControllerValidatorAspect { @Around("execution(* com.*.controller..*.*(..)) && args(..,result)") public Object doAround(ProceedingJoinPoint pjp, result result) {  result.getFieldErrors();  ... }}

  这种方式可以减少controller层校验的代码,校验逻辑统一处理,更高效。

八、借助ValidatorUtils工具类

@Beanpublic Validator validator() { return new LocalValidatorFactoryBean();}

LocalValidatorFactoryBean官方示意

  LocalValidatorFactoryBean是Spring应用程序上下文中javax.validation(JSR-303)设置的中心类:它引导javax.validation.ValidationFactory并通过Spring Validator接口以及JSR-303 Validator接口和ValidatorFactory公开它。界面本身。通过Spring或JSR-303 Validator接口与该bean的实例进行通信时,您将与底层ValidatorFactory的默认Validator进行通信。这非常方便,因为您不必在工厂执行另一个调用,假设您几乎总是会使用默认的Validator。这也可以直接注入Validator类型的任何目标依赖项!从Spring 5.0开始,这个类需要Bean Validation 1.1 ,特别支持Hibernate Validator 5.x(参见setValidationMessageSource(org.springframework.context.MessageSource))。这个类也与Bean Validation 2.0和Hibernate Validator 6.0运行时兼容,有一个特别说明:如果你想调用BV 2.0的getClockProvider()方法,通过#unwrap(ValidatorFactory.class)获取本机ValidatorFactory,在那里调用返回的本机引用上的getClockProvider()方法。Spring的MVC配置命名空间也使用此类,如果存在javax.validation API但未配置显式Validator。

@Componentpublic class ValidatorUtils implements ApplicationContextAware { @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {  ValidatorUtils.validator = (Validator) applicationContext.getBean("validator"); } private static Validator validator; public static Optional<String> validateResultProcess(Object obj)  {  Set<ConstraintViolation<Object>> results = validator.validate(obj);  if (CollectionUtils.isEmpty(results)) {return Optional.empty();  }  StringBuilder sb = new StringBuilder();  for (Iterator<ConstraintViolation<Object>> iterator = results.iterator(); iterator.hasNext(); ) {sb.append(iterator.next().getMessage());if (iterator.hasNext()) { sb.append(" ,");}  }  return Optional.of(sb.toString()); }}

  为什么要使用这个工具类呢?

  1、controller方法中不用加入BindingResult参数

  2、controller方法中需要校验的参数也不需要加入@Valid或者@Validated注解

  怎么样是不是又省去了好多代码,开不开心。

  具体使用,在controller方法或者全局拦截校验器中调用ValidatorUtils.validateResultProce

源文地址:https://www.guoxiongfei.cn/cntech/4162.html