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

时间:2022-05-01 20:35:36
 首先先学习一下注解,注解为我们在代码中添加信息提供了一种形式化的方法,使得我们在稍后的某个时刻可以方便地使用这些数据。

    在日常的编码中我们一直都在使用注解,只是没有特别关注过,Java中内置了三种注解:@Override,@SuppressWarnings @Deprecated。相信只要学习过Java的同学一定是见过这些主角的 。

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

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

 

Java代码  Spring中使用自定义的注解校验器的实现
  1. /** 
  2.  * 
  3.  * @author zhangwei_david 
  4.  * @version $Id: CustomerRule.java, v 0.1 2015年5月29日 下午10:12:16 zhangwei_david Exp $ 
  5.  */  
  6. @Documented  
  7. @Target(ElementType.ANNOTATION_TYPE)  
  8. @Retention(RetentionPolicy.RUNTIME)  
  9. public @interface CustomerValidator {  
  10.   
  11. }  
      这个注解中没有任何内容,属于标记注解

 

 

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

 

Java代码  Spring中使用自定义的注解校验器的实现
  1. /** 
  2.  * 
  3.  * @author zhangwei_david 
  4.  * @version $Id: Date.java, v 0.1 2015年5月29日 下午10:00:20 zhangwei_david Exp $ 
  5.  */  
  6. @Documented  
  7. @Target(ElementType.FIELD)  
  8. @Retention(RetentionPolicy.RUNTIME)  
  9. @CustomerValidator  
  10. public @interface DateString {  
  11.     String pattern() default "yyyy-MM-dd HH:mm:ss";  
  12.   
  13.     String errorCode() default "must date";  
  14.   
  15.     String message() default "must be date pattern";  
  16. }  
 

 

 

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

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

 

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

 

Java代码  Spring中使用自定义的注解校验器的实现
  1. /** 
  2.  *自定义注解处理器接口 
  3.  * 
  4.  * @author zhangwei_david 
  5.  * @version $Id: CustomerValidatorRule.java, v 0.1 2015年5月30日 上午8:51:52 zhangwei_david Exp $ 
  6.  */  
  7. public interface CustomerValidatorRule {  
  8.   
  9.     /** 
  10.      * 判断是否支持该注解 
  11.      * 
  12.      * @param annotation 
  13.      * @param property 
  14.      * @return 
  15.      */  
  16.     public boolean support(Annotation annotation);  
  17.   
  18.     /** 
  19.      *  校验处理 
  20.      *  
  21.      * 
  22.      * @param annotation 
  23.      * @param field 
  24.      * @param errors 
  25.      */  
  26.     public void valid(Annotation annotation, Object object, Field field, Errors errors)  
  27.             throws Exception;  
  28. }  
 

 

 

Java代码  Spring中使用自定义的注解校验器的实现
  1. /** 
  2.  * 
  3.  * @author zhangwei_david 
  4.  * @version $Id: AbastractCustomerValidatorRule.java, v 0.1 2015年5月30日 上午11:22:19 zhangwei_david Exp $ 
  5.  */  
  6. public abstract class AbastractCustomerValidatorRule implements CustomerValidatorRule {  
  7.   
  8.     /** 
  9.      * @see com.cathy.core.service.annotation.rule.CustomerValidatorRule#support(java.lang.annotation.Annotation) 
  10.      */  
  11.     public abstract boolean support(Annotation annotation);  
  12.   
  13.     /** 
  14.      * @param <T> 
  15.      * @see com.cathy.core.service.annotation.rule.CustomerValidatorRule#valid(java.lang.annotation.Annotation, java.lang.reflect.Field, org.springframework.validation.Errors) 
  16.      */  
  17.     public void valid(Annotation annotation, Object target, final Field field, final Errors errors)  
  18.                                                                                                    throws Exception {  
  19.         preHandle(annotation, target, field, errors);  
  20.         PropertyDescriptor propertyDescriptor = BeanUtils.getPropertyDescriptor(target.getClass(),  
  21.             field.getName());  
  22.         Method reader = propertyDescriptor.getReadMethod();  
  23.         Object property = reader.invoke(target);  
  24.         validProperty(annotation, property, new PostHandler() {  
  25.   
  26.             public void postHanle(String errorCode, String message) {  
  27.                 errors.rejectValue(field.getName(), errorCode, message);  
  28.             }  
  29.         });  
  30.     }  
  31.   
  32.     public static interface PostHandler {  
  33.         public void postHanle(String errorCode, String message);  
  34.     }  
  35.   
  36.     /** 
  37.      * 
  38.      */  
  39.     private void preHandle(Annotation annotation, Object target, Field field, Errors errors) {  
  40.         Assert.notNull(target);  
  41.         Assert.notNull(annotation);  
  42.         Assert.notNull(errors);  
  43.         Assert.notNull(field);  
  44.     }  
  45.   
  46.     public abstract void validProperty(Annotation annotation, Object property,  
  47.                                        PostHandler postHandler);  
  48.   
  49. }  
 

 

 

 

Java代码  Spring中使用自定义的注解校验器的实现
  1. /** 
  2.  * 
  3.  * @author zhangwei_david 
  4.  * @version $Id: DateValidatorRule.java, v 0.1 2015年5月30日 上午11:17:09 zhangwei_david Exp $ 
  5.  */  
  6. @CustomerRule  
  7. public class DateValidatorRule extends AbastractCustomerValidatorRule {  
  8.   
  9.     /** 
  10.      * @see com.cathy.core.service.annotation.rule.CustomerValidatorRule#support(java.lang.annotation.Annotation, java.lang.Object) 
  11.      */  
  12.     @Override  
  13.     public boolean support(Annotation annotation) {  
  14.         return annotation instanceof DateString;  
  15.   
  16.     }  
  17.   
  18.     /** 
  19.      * @see com.cathy.core.service.annotation.rule.AbastractCustomerValidatorRule#validProperty(java.lang.annotation.Annotation, java.lang.Object) 
  20.      */  
  21.     @Override  
  22.     public void validProperty(Annotation annotation, Object property, PostHandler postHandler) {  
  23.         DateString ds = (DateString) annotation;  
  24.         if (parse(ds.pattern(), (String) property) == null) {  
  25.             postHandler.postHanle(ds.errorCode(), ds.message());  
  26.         }  
  27.     }  
  28.   
  29.     private Date parse(String pattern, String property) {  
  30.         try {  
  31.             SimpleDateFormat sdf = new SimpleDateFormat(pattern);  
  32.             return sdf.parse(property);  
  33.         } catch (ParseException e) {  
  34.             //do noting  
  35.         }  
  36.         return null;  
  37.     }  
  38. }  
 

 

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

 

 

Java代码  Spring中使用自定义的注解校验器的实现
  1. /** 
  2.  * 
  3.  * @author zhangwei_david 
  4.  * @version $Id: CustomerValidatorRule.java, v 0.1 2015年5月30日 下午12:51:20 zhangwei_david Exp $ 
  5.  */  
  6. @Documented  
  7. @Target(ElementType.TYPE)  
  8. @Retention(RetentionPolicy.RUNTIME)  
  9. @Component  
  10. public @interface CustomerRule {  
  11.   
  12. }  
 

 

 

Java代码  Spring中使用自定义的注解校验器的实现
  1. /** 
  2.  * 
  3.  * @author zhangwei_david 
  4.  * @version $Id: CustomerValidatorProcesser.java, v 0.1 2015年5月30日 下午12:38:33 zhangwei_david Exp $ 
  5.  */  
  6. public class CustomerValidatorConfig implements ApplicationContextAware {  
  7.   
  8.     private Map<Annotation, CustomerValidatorRule> rules                   = new ConcurrentHashMap<Annotation, CustomerValidatorRule>();  
  9.   
  10.     Map<String, Object>                            customerValidationRules = null;  
  11.   
  12.     /** 
  13.      * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) 
  14.      */  
  15.     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {  
  16.         customerValidationRules = applicationContext  
  17.                 .getBeansWithAnnotation(CustomerRule.class);  
  18.         System.out.println(customerValidationRules);  
  19.     }  
  20.   
  21.     private CustomerValidatorRule findFormMap(Annotation annotation) {  
  22.         for (Entry<String, Object> entry : customerValidationRules.entrySet()) {  
  23.             if (entry.getValue() != null  
  24.                     && ((CustomerValidatorRule) entry.getValue()).support(annotation)) {  
  25.                 return (CustomerValidatorRule) entry.getValue();  
  26.             }  
  27.         }  
  28.         return null;  
  29.     }  
  30.   
  31.     public CustomerValidatorRule findRule(Annotation annotation) {  
  32.         CustomerValidatorRule customerValidatorRule = null;  
  33.         if (!rules.containsKey(annotation)) {  
  34.             CustomerValidatorRule cvr = findFormMap(annotation);  
  35.             if (cvr != null) {  
  36.                 rules.put(annotation, cvr);  
  37.             }  
  38.             customerValidatorRule = cvr;  
  39.         }  
  40.         customerValidatorRule = rules.get(annotation);  
  41.         return customerValidatorRule;  
  42.     }  
  43. }  
 通过实现ApplicationContextAware接口,从上下文中自动加载处理器。 Java代码  Spring中使用自定义的注解校验器的实现
  1. /** 
  2.  * 
  3.  * @author zhangwei_david 
  4.  * @version $Id: CustomerValidatorFactory.java, v 0.1 2015年5月30日 下午1:03:56 zhangwei_david Exp $ 
  5.  */  
  6. @Component  
  7. public class CustomerValidatorFactory implements Validator {  
  8.   
  9.     @Autowired  
  10.     private CustomerValidatorConfig customerValidatorConfig;  
  11.   
  12.     /** 
  13.      * @see org.springframework.validation.Validator#supports(java.lang.Class) 
  14.      */  
  15.     public boolean supports(Class<?> clazz) {  
  16.         return true;  
  17.     }  
  18.   
  19.     /** 
  20.      * @see org.springframework.validation.Validator#validate(java.lang.Object, org.springframework.validation.Errors) 
  21.      */  
  22.     public void validate(Object target, Errors errors) {  
  23.         Assert.notNull(target);  
  24.         Assert.notNull(errors);  
  25.         List<Field> fileds = getFields(target.getClass());  
  26.         for (Field field : fileds) {  
  27.             Annotation[] annotations = field.getAnnotations();  
  28.             for (Annotation annotation : annotations) {  
  29.                 if (annotation.annotationType().getAnnotation(CustomerValidator.class) != null) {  
  30.                     try {  
  31.                         CustomerValidatorRule customerValidatorRule = customerValidatorConfig  
  32.                             .findRule(annotation);  
  33.                         if (customerValidatorRule != null) {  
  34.                             customerValidatorRule.valid(annotation, target, field, errors);  
  35.                         }  
  36.                     } catch (Exception e) {  
  37.                         e.printStackTrace();  
  38.                     }  
  39.                 }  
  40.             }  
  41.         }  
  42.   
  43.     }  
  44.   
  45.     /** 
  46.      * 获取class的fields。 
  47.      * 
  48.      * @param clazz bean所在的class 
  49.      * @return 
  50.      */  
  51.     private List<Field> getFields(Class<? extends Object> clazz) {  
  52.         // 声明Field数组  
  53.         List<Field> fields = new ArrayList<Field>();  
  54.   
  55.         // 如果class类型不为空  
  56.         while (clazz != null) {  
  57.             // 添加属性到属性数组  
  58.             Collections.addAll(fields, clazz.getDeclaredFields());  
  59.             clazz = clazz.getSuperclass();  
  60.         }  
  61.         return fields;  
  62.     }  
  63.   
  64. }  
 

 

  使用自定义校验处理器:   Java代码  Spring中使用自定义的注解校验器的实现
  1. /** 
  2.  * 
  3.  * @author zhangwei_david 
  4.  * @version $Id: MyTest.java, v 0.1 2014年12月31日 下午9:25:49 zhangwei_david Exp $ 
  5.  */  
  6. @RunWith(SpringJUnit4ClassRunner.class)  
  7. @ContextConfiguration(locations = "classpath:spring.xml")  
  8. public class DemoTest {  
  9.   
  10.     @Autowired  
  11.     private Validator customerValidatorFactory;  
  12.   
  13.     @Test  
  14.     public void helloTest() {  
  15.         Form form = new Form();  
  16.         form.setCurrent("2015 11 11");  
  17.         BindException errors = new BindException(form, "target");  
  18.         customerValidatorFactory.validate(form, errors);  
  19.         System.out.println(errors.getFieldErrors());  
  20.     }  
  21.   
  22. }  
 
Java代码  Spring中使用自定义的注解校验器的实现
  1. /** 
  2.  * 
  3.  * @author zhangwei_david 
  4.  * @version $Id: Form.java, v 0.1 2015年5月30日 下午4:04:06 zhangwei_david Exp $ 
  5.  */  
  6. public class Form {  
  7.     @DateString  
  8.     private String current;  
  9.   
  10.     /** 
  11.      * Getter method for property <tt>current</tt>. 
  12.      * 
  13.      * @return property value of current 
  14.      */  
  15.     public String getCurrent() {  
  16.         return current;  
  17.     }  
  18.   
  19.     /** 
  20.      * Setter method for property <tt>current</tt>. 
  21.      * 
  22.      * @param current value to be assigned to property current 
  23.      */  
  24.     public void setCurrent(String current) {  
  25.         this.current = current;  
  26.     }  
  27.   
  28. }  
 运行的结果是:
Java代码  Spring中使用自定义的注解校验器的实现
  1. 五月 302015 8:21:35 下午 org.springframework.test.context.TestContextManager retrieveTestExecutionListeners  
  2. 信息: @TestExecutionListeners is not present for class [class com.cathy.core.service.annotation.HelloServiceTest]: using defaults.  
  3. 五月 302015 8:21:36 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions  
  4. 信息: Loading XML bean definitions from class path resource [spring.xml]  
  5. 五月 302015 8:21:36 下午 org.springframework.context.support.GenericApplicationContext prepareRefresh  
  6. 信息: Refreshing org.springframework.context.support.GenericApplicationContext@f7aae2: startup date [Sat May 30 20:21:36 CST 2015]; root of context hierarchy  
  7. 五月 302015 8:21:36 下午 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons  
  8. 信息: 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  
  9. {dateValidatorRule=com.cathy.core.service.annotation.rule.DateValidatorRule@1758f2a}  
  10. [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代码  Spring中使用自定义的注解校验器的实现
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.     xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"  
  5.     xmlns:aop="http://www.springframework.org/schema/aop" xmlns:jee="http://www.springframework.org/schema/jee"  
  6.     xmlns:task="http://www.springframework.org/schema/task"  
  7.     xsi:schemaLocation="  
  8.         http://www.springframework.org/schema/beans  
  9.         http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
  10.         http://www.springframework.org/schema/context  
  11.         http://www.springframework.org/schema/context/spring-context-3.0.xsd  
  12.         http://www.springframework.org/schema/aop   
  13.         http://www.springframework.org/schema/aop/spring-aop-3.0.xsd  
  14.         http://www.springframework.org/schema/tx  
  15.         http://www.springframework.org/schema/tx/spring-tx-3.0.xsd  
  16.         http://www.springframework.org/schema/jee   
  17.         http://www.springframework.org/schema/jee/spring-jee-3.0.xsd  
  18.         http://www.springframework.org/schema/task    
  19.         http://www.springframework.org/schema/task/spring-task-3.1.xsd    
  20.         ">  
  21.     <context:component-scan base-package="com.cathy.core.service"/>  
  22.    
  23.    
  24.     <bean id="customerValidatorConfig" class="com.cathy.core.service.annotation.handle.CustomerValidatorConfig"/>  
  25.       
  26.       
  27.      
  28. </beans>