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

1. 简介

       在java开发中,经常见到许多通过注解@Annotation实现功能的优秀代码,尤其在接触spring之后,对注解更是一发不可收拾,这里将向读者介绍一种范围定界方法。需要说明的是,这种定界方法不能独立于世,而必须结合Validation-api-*.jar公共包一起使用。这里以定界一个变量private  String 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<? extends Payload>[] 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<IntRange, String> {

	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.使用方法

        假设定义了一个类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="/cct")
public class CcgmsController {

	@PostConstruct
	public void init() {
		System.out.println("----------------------------------");
	}
	
	@RequestMapping(value="/agent", headers = "Accept=application/json", method = RequestMethod.POST)
	public @ResponseBody ResultInfo agentAction(@RequestBody @Valid Mytest01 
 mytest,BindingResult result, HttpServletRequest request) {
		
		if(result.hasErrors()) {
			 List<FieldError> 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<ConstraintViolation<BasicInfo>> sets =  Validate.VALIDATOR.validate(basicInfo);
		if(!sets.isEmpty()) {
			System.out.println("[ccgms-validate] : there is error message" );
			for(ConstraintViolation<BasicInfo> 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;
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值