您的位置:首页 > 编程语言 > Java开发

Spring中使用自定义的注解校验器的实现

2016-10-25 17:58 603 查看
 首先先学习一下注解,注解为我们在代码中添加信息提供了一种形式化的方法,使得我们在稍后的某个时刻可以方便地使用这些数据。
    在日常的编码中我们一直都在使用注解,只是没有特别关注过,Java中内置了三种注解:@Override,@SuppressWarnings @Deprecated。相信只要学习过Java的同学一定是见过这些主角的 。

    如果我们要写一个自定义的注解应该怎么呢?

    首先需要定义一个注解标注出是自定义的注解

 

Java代码  


/** 
 * 
 * @author zhangwei_david 
 * @version $Id: CustomerRule.java, v 0.1 2015年5月29日 下午10:12:16 zhangwei_david Exp $ 
 */  
@Documented  
@Target(ElementType.ANNOTATION_TYPE)  
@Retention(RetentionPolicy.RUNTIME)  
public @interface CustomerValidator {  
  
}  

      这个注解中没有任何内容,属于标记注解
 

 

    自定义 日期类型校验器的注解

 

Java代码  


/** 
 * 
 * @author zhangwei_david 
 * @version $Id: Date.java, v 0.1 2015年5月29日 下午10:00:20 zhangwei_david Exp $ 
 */  
@Documented  
@Target(ElementType.FIELD)  
@Retention(RetentionPolicy.RUNTIME)  
@CustomerValidator  
public @interface DateString {  
    String pattern() default "yyyy-MM-dd HH:mm:ss";  
  
    String errorCode() default "must date";  
  
    String message() default "must be date pattern";  
}  

 
 

 

, @Target是用来定义该注解将可以应用在什么地方,FIELD表示该注解应用在一个属性上,@Rectetion 用来定义该注解在哪一个级别可以使用 RUNTIME表示运行时。

     String pattern() default "yyyy-MM-dd HH:mm:ss" 表示如果不指定pattern这个值的时候将返回默认值“yyyy-MM-dd HH:mm:ss” 。

 

   有了自己的注解,那么就需要一个注解的处理器,定义一个处理器接

 

Java代码  


/** 
 *自定义注解处理器接口 
 * 
 * @author zhangwei_david 
 * @version $Id: CustomerValidatorRule.java, v 0.1 2015年5月30日 上午8:51:52 zhangwei_david Exp $ 
 */  
public interface CustomerValidatorRule {  
  
    /** 
     * 判断是否支持该注解 
     * 
     * @param annotation 
     * @param property 
     * @return 
     */  
    public boolean support(Annotation annotation);  
  
    /** 
     *  校验处理 
     *  
     * 
     * @param annotation 
     * @param field 
     * @param errors 
     */  
    public void valid(Annotation annotation, Object object, Field field, Errors errors)  
            throws Exception;  
}  

 
 

 

Java代码  


/** 
 * 
 * @author zhangwei_david 
 * @version $Id: AbastractCustomerValidatorRule.java, v 0.1 2015年5月30日 上午11:22:19 zhangwei_david Exp $ 
 */  
public abstract class AbastractCustomerValidatorRule implements CustomerValidatorRule {  
  
    /** 
     * @see com.cathy.core.service.annotation.rule.CustomerValidatorRule#support(java.lang.annotation.Annotation) 
     */  
    public abstract boolean support(Annotation annotation);  
  
    /** 
     * @param <T> 
     * @see com.cathy.core.service.annotation.rule.CustomerValidatorRule#valid(java.lang.annotation.Annotation, java.lang.reflect.Field, org.springframework.validation.Errors) 
     */  
    public void valid(Annotation annotation, Object target, final Field field, final Errors errors)  
                                                                                                   throws Exception {  
        preHandle(annotation, target, field, errors);  
        PropertyDescriptor propertyDescriptor = BeanUtils.getPropertyDescriptor(target.getClass(),  
            field.getName());  
        Method reader = propertyDescriptor.getReadMethod();  
        Object property = reader.invoke(target);  
        validProperty(annotation, property, new PostHandler() {  
  
            public void postHanle(String errorCode, String message) {  
                errors.rejectValue(field.getName(), errorCode, message);  
            }  
        });  
    }  
  
    public static interface PostHandler {  
        public void postHanle(String errorCode, String message);  
    }  
  
    /** 
     * 
     */  
    private void preHandle(Annotation annotation, Object target, Field field, Errors errors) {  
        Assert.notNull(target);  
        Assert.notNull(annotation);  
        Assert.notNull(errors);  
        Assert.notNull(field);  
    }  
  
    public abstract void validProperty(Annotation annotation, Object property,  
                                       PostHandler postHandler);  
  
}  

 
 

 

 

Java代码  


/** 
 * 
 * @author zhangwei_david 
 * @version $Id: DateValidatorRule.java, v 0.1 2015年5月30日 上午11:17:09 zhangwei_david Exp $ 
 */  
@CustomerRule  
public class DateValidatorRule extends AbastractCustomerValidatorRule {  
  
    /** 
     * @see com.cathy.core.service.annotation.rule.CustomerValidatorRule#support(java.lang.annotation.Annotation, java.lang.Object) 
     */  
    @Override  
    public boolean support(Annotation annotation) {  
        return annotation instanceof DateString;  
  
    }  
  
    /** 
     * @see com.cathy.core.service.annotation.rule.AbastractCustomerValidatorRule#validProperty(java.lang.annotation.Annotation, java.lang.Object) 
     */  
    @Override  
    public void validProperty(Annotation annotation, Object property, PostHandler postHandler) {  
        DateString ds = (DateString) annotation;  
        if (parse(ds.pattern(), (String) property) == null) {  
            postHandler.postHanle(ds.errorCode(), ds.message());  
        }  
    }  
  
    private Date parse(String pattern, String property) {  
        try {  
            SimpleDateFormat sdf = new SimpleDateFormat(pattern);  
            return sdf.parse(property);  
        } catch (ParseException e) {  
            //do noting  
        }  
        return null;  
    }  
}  

 
 

   这样我们就有了一个注解处理器,为了方便扩展,该处使用注解的方式加载定义的注解处理器,这就需要定义一个标注是自定义的注解处理器的注解。

 

 

Java代码  


/** 
 * 
 * @author zhangwei_david 
 * @version $Id: CustomerValidatorRule.java, v 0.1 2015年5月30日 下午12:51:20 zhangwei_david Exp $ 
 */  
@Documented  
@Target(ElementType.TYPE)  
@Retention(RetentionPolicy.RUNTIME)  
@Component  
public @interface CustomerRule {  
  
}  

 
 

 

Java代码  


/** 
 * 
 * @author zhangwei_david 
 * @version $Id: CustomerValidatorProcesser.java, v 0.1 2015年5月30日 下午12:38:33 zhangwei_david Exp $ 
 */  
public class CustomerValidatorConfig implements ApplicationContextAware {  
  
    private Map<Annotation, CustomerValidatorRule> rules                   = new ConcurrentHashMap<Annotation, CustomerValidatorRule>();  
  
    Map<String, Object>                            customerValidationRules = null;  
  
    /** 
     * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) 
     */  
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {  
        customerValidationRules = applicationContext  
                .getBeansWithAnnotation(CustomerRule.class);  
        System.out.println(customerValidationRules);  
    }  
  
    private CustomerValidatorRule findFormMap(Annotation annotation) {  
        for (Entry<String, Object> entry : customerValidationRules.entrySet()) {  
            if (entry.getValue() != null  
                    && ((CustomerValidatorRule) entry.getValue()).support(annotation)) {  
                return (CustomerValidatorRule) entry.getValue();  
            }  
        }  
        return null;  
    }  
  
    public CustomerValidatorRule findRule(Annotation annotation) {  
        CustomerValidatorRule customerValidatorRule = null;  
        if (!rules.containsKey(annotation)) {  
            CustomerValidatorRule cvr = findFormMap(annotation);  
            if (cvr != null) {  
                rules.put(annotation, cvr);  
            }  
            customerValidatorRule = cvr;  
        }  
        customerValidatorRule = rules.get(annotation);  
        return customerValidatorRule;  
    }  
}  

 通过实现ApplicationContextAware接口,从上下文中自动加载处理器。

Java代码  


/** 
 * 
 * @author zhangwei_david 
 * @version $Id: CustomerValidatorFactory.java, v 0.1 2015年5月30日 下午1:03:56 zhangwei_david Exp $ 
 */  
@Component  
public class CustomerValidatorFactory implements Validator {  
  
    @Autowired  
    private CustomerValidatorConfig customerValidatorConfig;  
  
    /** 
     * @see org.springframework.validation.Validator#supports(java.lang.Class) 
     */  
    public boolean supports(Class<?> clazz) {  
        return true;  
    }  
  
    /** 
     * @see org.springframework.validation.Validator#validate(java.lang.Object, org.springframework.validation.Errors) 
     */  
    public void validate(Object target, Errors errors) {  
        Assert.notNull(target);  
        Assert.notNull(errors);  
        List<Field> fileds = getFields(target.getClass());  
        for (Field field : fileds) {  
            Annotation[] annotations = field.getAnnotations();  
            for (Annotation annotation : annotations) {  
                if (annotation.annotationType().getAnnotation(CustomerValidator.class) != null) {  
                    try {  
                        CustomerValidatorRule customerValidatorRule = customerValidatorConfig  
                            .findRule(annotation);  
                        if (customerValidatorRule != null) {  
                            customerValidatorRule.valid(annotation, target, field, errors);  
                        }  
                    } catch (Exception e) {  
                        e.printStackTrace();  
                    }  
                }  
            }  
        }  
  
    }  
  
    /** 
     * 获取class的fields。 
     * 
     * @param clazz bean所在的class 
     * @return 
     */  
    private List<Field> getFields(Class<? extends Object> clazz) {  
        // 声明Field数组  
        List<Field> fields = new ArrayList<Field>();  
  
        // 如果class类型不为空  
        while (clazz != null) {  
            // 添加属性到属性数组  
            Collections.addAll(fields, clazz.getDeclaredFields());  
            clazz = clazz.getSuperclass();  
        }  
        return fields;  
    }  
  
}  

 
 

 
使用自定义校验处理器:
 

Java代码  


/** 
 * 
 * @author zhangwei_david 
 * @version $Id: MyTest.java, v 0.1 2014年12月31日 下午9:25:49 zhangwei_david Exp $ 
 */  
@RunWith(SpringJUnit4ClassRunner.class)  
@ContextConfiguration(locations = "classpath:spring.xml")  
public class DemoTest {  
  
    @Autowired  
    private Validator customerValidatorFactory;  
  
    @Test  
    public void helloTest() {  
        Form form = new Form();  
        form.setCurrent("2015 11 11");  
        BindException errors = new BindException(form, "target");  
        customerValidatorFactory.validate(form, errors);  
        System.out.println(errors.getFieldErrors());  
    }  
  
}  

 

Java代码  


/** 
 * 
 * @author zhangwei_david 
 * @version $Id: Form.java, v 0.1 2015年5月30日 下午4:04:06 zhangwei_david Exp $ 
 */  
public class Form {  
    @DateString  
    private String current;  
  
    /** 
     * Getter method for property <tt>current</tt>. 
     * 
     * @return property value of current 
     */  
    public String getCurrent() {  
        return current;  
    }  
  
    /** 
     * Setter method for property <tt>current</tt>. 
     * 
     * @param current value to be assigned to property current 
     */  
    public void setCurrent(String current) {  
        this.current = current;  
    }  
  
}  

 运行的结果是:

Java代码  


五月 30, 2015 8:21:35 下午 org.springframework.test.context.TestContextManager retrieveTestExecutionListeners  
信息: @TestExecutionListeners is not present for class [class com.cathy.core.service.annotation.HelloServiceTest]: using defaults.  
五月 30, 2015 8:21:36 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions  
信息: Loading XML bean definitions from class path resource [spring.xml]  
五月 30, 2015 8:21:36 下午 org.springframework.context.support.GenericApplicationContext prepareRefresh  
信息: Refreshing org.springframework.context.support.GenericApplicationContext@f7aae2: startup date [Sat May 30 20:21:36 CST 2015]; root of context hierarchy  
五月 30, 2015 8:21:36 下午 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons  
信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@19627bc: defining beans [customerValidatorFactory,dateValidatorRule,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,customerValidatorConfig,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy  
{dateValidatorRule=com.cathy.core.service.annotation.rule.DateValidatorRule@1758f2a}  
[Field error in object 'target' on field 'current': rejected value [2015 11 11]; codes [must date.target.current,must date.current,must date.java.lang.String,must date]; arguments []; default message [must be date pattern]]  

 PS: spring的配置文件

Java代码  


<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"  
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:jee="http://www.springframework.org/schema/jee"  
    xmlns:task="http://www.springframework.org/schema/task"  
    xsi:schemaLocation="  
        http://www.springframework.org/schema/beans  
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
        http://www.springframework.org/schema/context  
        http://www.springframework.org/schema/context/spring-context-3.0.xsd  
        http://www.springframework.org/schema/aop   
        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd  
        http://www.springframework.org/schema/tx  
        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd  
        http://www.springframework.org/schema/jee   
        http://www.springframework.org/schema/jee/spring-jee-3.0.xsd  
        http://www.springframework.org/schema/task    
        http://www.springframework.org/schema/task/spring-task-3.1.xsd    
        ">  
    <context:component-scan base-package="com.cathy.core.service"/>  
   
   
    <bean id="customerValidatorConfig" class="com.cathy.core.service.annotation.handle.CustomerValidatorConfig"/>  
      
      
     
</beans> 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: