`
zhangwei_david
  • 浏览: 469845 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

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

 
阅读更多

  

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

    在日常的编码中我们一直都在使用注解,只是没有特别关注过,Java中内置了三种注解:@Override,@SuppressWarnings @Deprecated。相信只要学习过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 {

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

 

 

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

 

/**
 *
 * @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” 。

 

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

 

/**
 *自定义注解处理器接口
 *
 * @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;
}
 

 

 

/**
 *
 * @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);

}
 

 

 

 

/**
 *
 * @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;
    }
}
 

 

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

 

 

/**
 *
 * @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 {

}
 

 

 

/**
 *
 * @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接口,从上下文中自动加载处理器。
/**
 *
 * @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;
    }

}
 

 

 
使用自定义校验处理器:
 
/**
 *
 * @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());
    }

}
 
/**
 *
 * @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;
    }

}
 运行的结果是:
五月 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的配置文件
<?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>
 
1
0
分享到:
评论

相关推荐

    Spring3MVC注解教程.ppt

    如何使用注解驱动的校验 使用校验功能时,处理方法要如何签名?? 校验错误信息存放在什么地方?? 页面如何显示错误信息 如何对错误信息进行国际化(1) 如何对错误信息进行国际化(2) 目录 数据模型访问结构 ...

    人工智能-项目实践-信息检索-一个基于微服务架构的前后端分离博客系统 使用Vue + Element ,后端使用Spring c

    采用 AOP + 自定义注解 + Redis 实现限制IP接口访问次数 采用 Nacos 作为服务发现和配置中心,轻松完成项目的配置的维护 采用 Sentinel 流量控制框架,通过配置再也不怕网站被爆破 支持Markdown 编辑器 采用 Elastic...

    Spring中文帮助文档

    6.8.1. 在Spring中使用AspectJ进行domain object的依赖注入 6.8.2. Spring中其他的AspectJ切面 6.8.3. 使用Spring IoC来配置AspectJ的切面 6.8.4. 在Spring应用中使用AspectJ加载时织入(LTW) 6.9. 更多资源 7...

    Spring-Reference_zh_CN(Spring中文参考手册)

    6.8.1. 在Spring中使用AspectJ来为domain object进行依赖注入 6.8.1.1. @Configurable object的单元测试 6.8.1.2. 多application context情况下的处理 6.8.2. Spring中其他的AspectJ切面 6.8.3. 使用Spring IoC来...

    Spring.3.x企业应用开发实战(完整版).part2

    12.2 在Spring中使用Hibernate 12.2.1 配置SessionFactory 12.2.2 使用HibernateTemplate 12.2.3 处理LOB类型数据 12.2.4 添加Hibernate事件监听器 12.2.5 使用原生Hibernate API 12.2.6 使用注解配置 12.2.7 事务...

    Spring API

    6.8.1. 在Spring中使用AspectJ进行domain object的依赖注入 6.8.2. Spring中其他的AspectJ切面 6.8.3. 使用Spring IoC来配置AspectJ的切面 6.8.4. 在Spring应用中使用AspectJ加载时织入(LTW) 6.9. 更多资源 7...

    基于Spring MVC的web框架 1.1.11

    工具类数据校验 jsp自定义标签 Spring自定义注解 默认requestMapping 1.1.2 代码生成器 1.1.3 首页修改 dateformat.js 时间参数转换 SpringMVC配置文件集中 快递参数接口 1.1.4 des加解密字符串和文件 1.1.5 redis...

    Spring攻略(第二版 中文高清版).part1

    6.2 在你的Servlet和过滤器中使用Spring 214 6.2.1 问题 214 6.2.2 解决方案 215 6.2.3 工作原理 215 6.3 将Spring与Struts 1.x集成 220 6.3.1 问题 220 6.3.2 解决方案 220 6.3.3 工作原理 220 6.4...

    Spring MVC 3.0实战指南.ppt

    如何使用注解驱动的校验 使用校验功能时,处理方法要如何签名?? 校验错误信息存放在什么地方?? 页面如何显示错误信息 如何对错误信息进行国际化(1) 如何对错误信息进行国际化(2) 目录 数据模型访问结构 访问数据...

    Spring 2.0 开发参考手册

    6.8.1. 在Spring中使用AspectJ来为domain object进行依赖注入 6.8.2. Spring中其他的AspectJ切面 6.8.3. 使用Spring IoC来配置AspectJ的切面 6.8.4. 在Spring应用中使用AspectJ Load-time weaving(LTW) 6.9. ...

    Spring3.x企业应用开发实战(完整版) part1

    12.2 在Spring中使用Hibernate 12.2.1 配置SessionFactory 12.2.2 使用HibernateTemplate 12.2.3 处理LOB类型数据 12.2.4 添加Hibernate事件监听器 12.2.5 使用原生Hibernate API 12.2.6 使用注解配置 12.2.7 事务...

    Spring攻略(第二版 中文高清版).part2

    6.2 在你的Servlet和过滤器中使用Spring 214 6.2.1 问题 214 6.2.2 解决方案 215 6.2.3 工作原理 215 6.3 将Spring与Struts 1.x集成 220 6.3.1 问题 220 6.3.2 解决方案 220 6.3.3 工作原理 220 6.4...

    spring chm文档

    6.8.4. 在Spring应用中使用AspectJ Load-time weaving(LTW) 6.9. 其它资源 7. Spring AOP APIs 7.1. 简介 7.2. Spring中的切入点API 7.2.1. 概念 7.2.2. 切入点实施 7.2.3. AspectJ切入点表达式 7.2.4. ...

    Spring_MVC_051:Spring MVC 学习总结(五)——校验与文件上传

    三、使用jQuery扩展插件Validate实现前端校验 3.1、jQuery扩展插件validate—1基本使用方法 3.2、jQuery扩展插件validate—2通过参数设置验证规则 3.3、jQuery扩展插件validate—3通过参数设置错误信息 3.4、jQuery...

    一个SpringBoot基础项目框架

    自定义注解+拦截器实现基于RBAC接口权限校验(配套文档:https://blog.csdn.net/wujiangbo520/article/details/122057616) 全局异常处理 接口统一结果返回 一键生成数据库设计文档 大批量数据插入数据库测试 根据...

    基于SpringMVC的一个web框架

    工具类数据校验 jsp自定义标签 Spring自定义注解 默认requestMapping 1.1.2 代码生成器 1.1.3 首页修改 dateformat.js 时间参数转换 SpringMVC配置文件集中 快递参数接口 1.1.4 des加解密字符串和文件 1.1.5 redis...

    SpringMVC基础上的web框架

    工具类数据校验 jsp自定义标签 Spring自定义注解 默认requestMapping 1.1.2 代码生成器 1.1.3 首页修改 dateformat.js 时间参数转换 SpringMVC配置文件集中 快递参数接口 1.1.4 des加解密字符串和文件 1.1.5 redis...

    springCloud.rar(私聊博主要密码)

    + springBoot + springCloud + 日志组件logback-spring + 多配置 + 多数据源...+ 传参注解式校验 + session练习 + 公用日志设计封装 + db乐观锁设计 + 优雅启停 + 配置文件信息加密 + AES加解密 + spring 事件监听设计

    一个可以直接运行的基于SpringMVC的web框架1.1.12

    工具类数据校验 jsp自定义标签 Spring自定义注解 默认requestMapping 1.1.2 代码生成器 1.1.3 首页修改 dateformat.js 时间参数转换 SpringMVC配置文件集中 快递参数接口 1.1.4 des加解密字符串和文件 1.1.5 redis...

    可以直接运行的基于SpringMVC的web框架示例,也可以直接当公司框架

    工具类数据校验 jsp自定义标签 Spring自定义注解 默认requestMapping 1.1.2 代码生成器 1.1.3 首页修改 dateformat.js 时间参数转换 SpringMVC配置文件集中 快递参数接口 1.1.4 des加解密字符串和文件 1.1.5 redis...

Global site tag (gtag.js) - Google Analytics