使用 ConstraintValidator 接口及BindingResult实现注解定义参数范围

1. 简介 在java开发中,经常见到许多通过注解@Annotation实现功能的优秀代码,尤其在接触spring之后,对注解更是一发不可收拾,这里将向读者介绍一种范围定界方法。需要说明的是,这种定界方法不能独立于世,而必须结合Validation-api-*.jar公共包一起使用。这里以定界一个变量privateString agentId; 取值范围(1,3) 为例来说明。
2. 创建Annotation 在eclipse上选中某个指定的package,右键 new ,选择Annotation,这里创建的Annotation的名字叫做@IntRange,其代码如下

import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; import java.lang.annotation.ElementType; import java.lang.annotation.RetentionPolicy; import javax.validation.Constraint; import javax.validation.Payload; import com.*.constrait.validator.IntRangeValidator; /** * * @author *** * @see 用于判定指定类中的某个域是否在规定区间之内 */ @Target({ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Documented @Constraint(validatedBy = IntRangeValidator.class) public @interface IntRange { String message() default "{com.*.validation.constraints.IntRange.message}"; Class[] groups() default { }; Class[] payload() default { }; int min() default 0; int max() default Integer.MAX_VALUE; }

代码中的@Target 用于指定该注解的应用范围,此注解应用于 方法、域、构造函数 、入参四个区域;@Retention指定应用时间,这里是RUNTIME;@Constraint指明具体实现的类,即IntRangeValidator.java类
代码中定义了两个函数 int min(); 和 int max(); 两个函数都有各自的默认值。
Annotation可以认为是一个接口,其中只是简单定义了要实现哪些功能,具体的实现步骤则交由其他指定的类(这里专指IntRangeValidator)去处理。
3. 具体实现 上面已经指出,@Annotation只是一个类似于接口的类,具体的实现由其他类完成,这里将介绍具体实现,代码如下:
import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; import com.*.constrait.constrains.IntRange; public class IntRangeValidator implements ConstraintValidator { private int min; private int max; @Override public void initialize(IntRange arg0) { this.min = arg0.min(); this.max = arg0.max(); } @Override public boolean isValid(String value, ConstraintValidatorContext arg1) {if((null == value) || 0 == value.length()) { return false; }try { int integer = Integer.valueOf(value); //System.out.println("++++++ the value is " + integer+ " +++++++"); return (integer > this.min) && (integer < this.max); }catch(NumberFormatException e) { //System.out.println("---there is a exception , " + e.toString()); return false; } }}

该函数实现了ConstraintValidator接口,该接口为泛型接口,第一个参数IntRange为上文中的Annotation,其他代码也比较容易理解,此处不做介绍。
4.使用方法 【使用 ConstraintValidator 接口及BindingResult实现注解定义参数范围】假设定义了一个类Mytest01,其中有一个变量private String agentId; ,则注解的方式如下
public class BasicInfo {}public class Mytest01 extends{@IntRange(min=1,max=3) private String agentId; }

代码@IntRange()中的min和max分别调用了@IntRange中的两个函数。
该注解一般应用于对外接口,和@RequestBody、@Valid、@BindingResult一起使用,代码如下
import javax.validation.Valid; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; @Controller @RequestMapping(value="https://www.it610.com/cct") public class CcgmsController { @PostConstruct public void init() { System.out.println("----------------------------------"); } @RequestMapping(value="https://www.it610.com/agent", headers = "Accept=application/json", method = RequestMethod.POST) public @ResponseBody ResultInfo agentAction(@RequestBody @Valid Mytest01 mytest,BindingResult result, HttpServletRequest request) {if(result.hasErrors()) { List list = result.getFieldErrors(); for(FieldError error:list) { System.out.println(error.getObjectName()+"." + error.getField() + " failed; cause by : "+ error.getDefaultMessage()); } }System.out.println("++++++++++++++++++++++++++++"); return new ResultInfo("0"); } }public class ResultInfo { private String result; ResultInfo(){ } public ResultInfo(String result){ this.result = result; } ..........//省略get/set方法 }

当mytest入参有问题时,则将执行如下代码if(result.hasErrors){}

上述使用是结合BindingResult的,而实际使用中又不一定会用到它,如果项目中不用BindingResult,那又应该如何实现呢? 其实Validate已经提供了类似的方法,代码如下,在使用的地方显式的调用一下Validate.checkInfo() 方法来检测注解
import javax.validation.ConstraintViolation; import javax.validation.Validation; import com.***.BasicInfo; public class Validate { private static javax.validation.Validator VALIDATOR = Validation.buildDefaultValidatorFactory().getValidator(); public static boolean checkInfo(BasicInfo basicInfo) {if(null == basicInfo) { System.out.println("[ccgms]: basicInfo is null"); return false; }Set> sets =Validate.VALIDATOR.validate(basicInfo); if(!sets.isEmpty()) { System.out.println("[ccgms-validate] : there is error message" ); for(ConstraintViolation set:sets) { //参数所在类的名称 String className = set.getRootBeanClass().getSimpleName(); //参数所在类的具体域的名称 String path = set.getPropertyPath().toString(); //定义的注解中的默认message String message = set.getMessage(); System.out.println("[className]="+className+" ; [path]=" + path+" ; [message]=" + message ); } return false; }return true; } }


    推荐阅读