在企业系统的开发中,用户表单输入的场景是会经常遇见的,如何让数据校验脱离于业务代码逻辑,谁也不想在逻辑代码里对字段逐一判断。。。。
Spring MVC的校验方式
在使用Spring MVC时的时候,直接使用hibernate-validator的注解,如下:
publicclassUser {private Long id;@NotBlank(message ="name不能为空")@Size(min =5, max =10, message ="字符在5到10个")private String name;private String des;@NotNull@Max(value =3, message ="type 参数错误")@Min(value =0, message ="type 参数错误")private Integer type;@Min(value =0, message ="参数错误, limit必须大于或等于0")privateint limit;@Pattern(regexp ="^(true|false)$", message ="参数错误, 参数isActive只能是true或者false")private String flag;// setters and getters
然后将User对象作为Controller的参数,交给Spring MVC去帮你校验。
通过切面实现自己的注解式数据校验
这是一个SOA的微服务应用,没有controller和Spring MVC,当然也没有所谓的容器(Tomcat、Jetty),对于来自于client的调用,也要进行参数校验。继续基于hibernate-validator,
参看validator的官方文档:
http://hibernate.org/validator/documentation/getting-started/
和链接:https://diamondfsd.com/article/78fa12cd-b530-4a90-b438-13d5a0c4e26c (灵感来自于此)
引入依赖:
<dependency><groupId>org.hibernate</groupId><artifactId>hibernate-validator-cdi</artifactId><version>5.4.1.Final</version></dependency><dependency><groupId>org.glassfish</groupId><artifactId>javax.el</artifactId><version>3.0.1-b08</version></dependency>
这里需要引入spring boot和aop的一些知识点,自行去网上google吧。我直接上代码了,谁叫我是代码的搬运工。
定义一个切面:
@Aspect//一个切面@Configuration// spring boot 配置类publicclassRequestParamValidAspect {privatefinal ValidatorFactory factory = Validation.buildDefaultValidatorFactory();privatefinal ExecutableValidator methodValidator = factory.getValidator().forExecutables();privatefinal Validator beanValidator = factory.getValidator();private <T> Set<ConstraintViolation<T>>validMethodParams(T obj, Method method, Object [] params){return methodValidator.validateParameters(obj, method, params);
}private <T> Set<ConstraintViolation<T>>validBeanParams(T bean) {return beanValidator.validate(bean);
}@Pointcut("execution(* com.jiaobuchong.commodity.service.*.*(..))")publicvoidsoaServiceBefore(){}/* * 通过连接点切入 */@Before("soaServiceBefore()")publicvoidtwiceAsOld1(JoinPoint point) {// 获得切入目标对象
Object target = point.getThis();// 获得切入方法参数
Object [] args = point.getArgs();// 获得切入的方法
Method method = ((MethodSignature)point.getSignature()).getMethod();// 校验以基本数据类型 为方法参数的
Set<ConstraintViolation<Object>> validResult = validMethodParams(target, method, args);
Iterator<ConstraintViolation<Object>> violationIterator = validResult.iterator();while (violationIterator.hasNext()) {// 此处可以抛个异常提示用户参数输入格式不正确
System.out.println("method check---------" + violationIterator.next().getMessage());
}// 校验以java bean对象 为方法参数的for (Object bean : args) {if (null != bean) {
validResult = validBeanParams(bean);
violationIterator = validResult.iterator();while (violationIterator.hasNext()) {// 此处可以抛个异常提示用户参数输入格式不正确
System.out.println("bean check-------" + violationIterator.next().getMessage());
}
}
}
}
}
具体的Service
// DemoService.javapublicinterfaceDemoService {void one(@NotNull(message ="不能为null") Integer a,@NotBlank String b);void two(@NotNull(message ="paramsVo不能为null") ParamsVo paramsVo,@NotNull(message ="go不能为null") String go);
}// ParamsVo.javapublicclassParamsVo {@NotBlank(message ="不能为空")private String name;@NotBlank@Length(min =2, max =20, message ="不可以为空,最多20个字")private String desc;@NotNull@Valid// 需要加上@Valid注解,不然不会校验到Img对象private List<Img> imgList;@NotNull(message ="length不能为null")@Range(min =3, max =100, message ="长度范围3-100")private Integer length;// omitted other code
}publicclassImg {@NotNull(message ="img id 不能为null")private Long id;@NotBlank(message ="img name 不能为空")private String name;// omitted other code
}
运行DemoService:
@Autowiredprivate DemoService demoService;@TestpublicvoidtestGo() {
demoService.one(null,"");
ParamsVo paramsVo =new ParamsVo();
List<Img> list =new ArrayList<>();
Img img =new Img();
list.add(img);
paramsVo.setImgList(list);
paramsVo.setDesc("你");
paramsVo.setLength(1);
demoService.two(paramsVo,null);
}
运行结果:
method check———不能为空
method check———不能为null
method check———go不能为null
bean check——-img name 不能为空
bean check——-不能为空
bean check——-深度范围3-100
bean check——-img id 不能为null
bean check——-不可以为空,最多20个字
这样比Spring MVC的校验功能还强大了,
// Spring MVC中对下面这样的校验是没有作用的void one(@NotNull(message ="不能为null") Integer a,@NotBlank String b);
经过一番改造后,啥都支持了。而且独立于业务逻辑,维护和新增校验都很方便,代码量也变少了!
人生苦短,so less code!