本文共 3670 字,大约阅读时间需要 12 分钟。
自从我接触了spring-boot框架,对于基于注解的开发方式越来越中意,无疑这是一种提升开发效率和简化配置的开发方式。开发中对于方法入参数据校验是必须的也是严谨的,一方面是为了提升性能(对于不合法数据,或格式不正确的数据,不做处理,直接返回错误信息)。另一方面也是业务需求,对某些字段有着check。当我们使用spring框架来开发项目,其实spring-validation这个模块也已经提供了一些常用校验注解。例如@Size、@NotNull、@Email之类的格式或者非空校验。
既然spring-validation这个模块已经提供一部分常用注解,但是在实际开发中的需求,并不能完全解决。
所以我们可以参照既有的注解的实现方式,照葫芦画瓢,也用注解来完成数据字段的校验。源码分析
@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})@Retention(RetentionPolicy.RUNTIME)@Repeatable(NotNull.List.class)@Documented@Constraint( validatedBy = { }//1.注入校验类)public @interface NotNull { //2.定义message String message() default "{javax.validation.constraints.NotNull.message}"; Class [] groups() default { };//支持分组校验 Class [] payload() default { }; @Target({ ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface List { NotNull[] value(); }}
这个是validation包定义的@NotNull的注解接口的定义
此处需要注意我标注的两处 1.Constraint中注入校验类 2.校验用的message@Documented@Target({ ElementType.ANNOTATION_TYPE})@Retention(RetentionPolicy.RUNTIME)public @interface Constraint { Class >[] validatedBy();//校验类注入}
此处是@Constraint注解接口的定义
validatedBy 方法中可以传入ConstraintValidator的校验类public interface ConstraintValidator { default void initialize(A constraintAnnotation) { } boolean isValid(T var1, ConstraintValidatorContext var2);//校验实现方法}
ConstraintValidator校验类接口,具体实现的校验类需要实现这个ConstraintValidator接口,实现isValid这个抽象方法。
分析总结:实装自定义注解校验,需要定义一个注解接口用于标识字段,需要一个ConstraintValidator的实现类,用于判断字段是否满足校验规则
具体实现
@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@Documented@Constraint(validatedBy = IpCheckValidator.class)//校验实现类绑定public @interface IpCheck { String message() default "{} ip address is not legal"; Class [] groups() default { }; Class [] payload() default { }; @Target({ ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface List { IpCheck[] value(); }}
我这里是自定实现的ip地址check的注解
public class IpCheckValidator implements ConstraintValidator{ //实现方法 @Override public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) { String ipArry[] = value.split("\\."); if(ipArry.length==4){ int ipArryInt[] = new int[4]; for (int i=0;i<4;i++){ try { ipArryInt[i]=Integer.parseInt(ipArry[i]); } catch (Exception e){ return false; } } if(ipArryInt[0]>=1&&ipArryInt[0]<=255) for (int j=1;j<4;j++){ if(ipArryInt[j]<0||ipArryInt[j]>255){ return false; } } return true; } return false; }}
使用方式
@IpCheck private String ipAddress;
最后的校验信息存在BindingResult,通过hasErrors方法就可以判断校验是否通过
@RequestMapping(value = "/logon",method =RequestMethod.POST) public BaseResponse userRegister(@RequestBody @Valid RegisterUserInfo userInfo, BindingResult result){ //判断校验是否有误 if(!result.hasErrors()){ //执行注册 service.register(userInfo); }else{ //抛出异常-提交参数格式不对 throw new APIException(HttpServletResponse.SC_BAD_REQUEST, "request parameters formatter is wrong "); } return NORMAL_RESPONSE; }
转载地址:http://rqugn.baihongyu.com/