`
zhangwei_david
  • 浏览: 476250 次
  • 性别: 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
分享到:
评论

相关推荐

    自定义校验注解框架(validator)

    定义和实现完成后,我们可以在模型类或方法参数上使用自定义注解,Spring等框架会在执行前自动进行校验: ```java public class User { @Email private String email; } ``` 5. **异常处理** 如果校验失败...

    common(自定义注解校验数据有效性)

    这篇博客“common(自定义注解校验数据有效性)”显然探讨了如何利用自定义注解来确保程序中输入数据的有效性。自定义注解是Java等编程语言中的一种元编程特性,允许我们创建自己的标记来指定代码的行为或者进行特定...

    spring自定义注解实现拦截器的实现方法

    在Spring框架中,自定义注解结合AOP(面向切面编程)是实现业务逻辑与非业务逻辑分离的一种有效方式。通过自定义注解,可以针对不同的业务场景灵活地添加功能,比如权限控制、日志记录、事务管理等。本文将详细讨论...

    浅谈Spring自定义注解从入门到精通

    浅谈Spring自定义注解从入门到精通 在业务开发过程中,我们经常会遇到形形色色的注解,但是框架自有的注解并不是总能满足复杂的业务需求。这时,我们可以自定义注解来满足我们的需求。根据注解使用的位置,文章将...

    谈谈Java中自定义注解及使用场景

    在Spring Boot等框架中,可以定义自定义注解来实现特定的功能,如拦截器中的登录校验。通过在控制器方法上使用自定义注解,拦截器可以检测并执行相应的逻辑,例如检查用户是否已登录。 2. **注解+AOP(面向切面...

    validate+@Constraint自定义注解1

    为了使自定义注解生效,我们需要在需要校验的参数上使用`@Valid`(在控制器方法的参数上)以及`@RequestBody`(当参数是HTTP请求体时): ```java @GetMapping("/check") public String test02(@Valid @RequestBody...

    spring @Validated 注解开发中使用group分组校验的实现

    在Spring框架中,`@Validated`注解用于数据校验,它依赖于JSR-303/JSR-349(Bean Validation)规范。这个注解可以帮助我们在处理HTTP请求时验证输入参数,确保数据的正确性,避免无效的数据流入业务逻辑。当我们的...

    Spring Boot技术知识点:如何使用@Valid注解来对邮箱字段进行数据校验

    自定义校验注解需要使用`@Constraint`,而校验器则需要实现`Validator`接口。 总结来说,`@Valid`注解在Spring Boot中的作用是帮助我们进行数据校验,确保入参的正确性。结合其他验证注解,如`@Email`,可以有效地...

    java token验证和注解方式放行

    在Java中,我们可以使用Spring Security框架的注解,如`@Secured`, `@PreAuthorize`, 或 `@PostAuthorize`,来定义哪些方法需要用户验证,哪些方法允许匿名访问。例如,`@Secured("ROLE_USER")`表示只有具有"USER...

    参数校验注解使用指南1

    2. 使用注解校验:通过在方法签名中添加自定义的校验注解,Spring在调用该方法之前会自动执行参数校验。这种方式更加简洁,但需要配置相应的AOP拦截器。 在`VerifyConstants`中,通常会定义一些通用的业务错误码...

    spring boot+自定义 AOP 实现全局校验的实例代码

    为了使我们的应用程序能够使用自定义的 AOP 实现全局校验,我们需要在 Spring Boot 应用程序的配置文件中添加相应的配置。例如,我们可以在 application.properties 文件中添加以下配置项: spring.aop.auto=true ...

    springmvc注解验证

    这通常包括定义一个新的注解,声明一个或多个校验器,并在验证逻辑中实现具体的验证规则。 3. **使用ValidationUtils** Spring MVC提供了一个`ValidationUtils`工具类,可以在验证逻辑中方便地调用,例如`...

    javaWEB写到校验器代码

    校验器的实现通常基于一些常见的框架,例如Spring框架中的`Validator`接口。开发者可以自定义校验规则,实现该接口并编写对应的校验方法。此外,Spring还提供了JSR-303/JSR-349标准的`javax.validation`包,支持使用...

    利用Spring Security做角色权限校验

    - 自定义`UserDetailsService`后,需要将其绑定到Spring Security的配置中,以便在认证过程中使用。 4. **配置Spring Security**: - 在Spring Boot项目中,通常会创建一个配置类,继承`...

    JSR303校验注解和自定义校验注解的使用

    在实际应用中,这些注解通常与Spring MVC的控制器方法结合使用,通过`@Validated`或`@Valid`注解来触发验证过程。当验证失败时,Spring会自动将错误信息填充到模型对象中,以便在视图层展示给用户。 总结起来,JSR...

    spring注解整理,及应用

    * @AliasFor:顾名思义 @AliasFor 表示别名,用于自定义注解的两个属性上,表示这两个属性其实同一个含义。 * @Qualifier:当一个接口有多个实现类时,可以用此注解表明哪个实现类才是我们所需要的,名称为我们之前...

    spring集成cxf客户端和服务器端demo(含自定义拦截器)

    在本项目中,"spring集成cxf客户端和服务器端demo(含自定义拦截器)"是一个实战案例,展示了如何在Spring框架下与Apache CXF服务进行整合,实现客户端和服务端的交互,并利用拦截器来增强功能。以下是这个项目涉及的...

    spring+spring mvc+mybatis框架整合实现超市货物管理系统

    在本文中,我们将深入探讨如何使用JavaEE技术栈,特别是Spring、Spring MVC和MyBatis框架,来构建一个超市货物管理系统的实现。这个系统涵盖了基本的登录功能以及与MySQL数据库的交互,包括增删改查操作和分页显示。...

    Spring Mvc(1)Spring MVC 校验

    如此一来,我们就可以在用户实体类中使用 `@EmailUnique` 注解,进行自定义的邮箱唯一性校验。 3. **组合校验** 在某些情况下,可能需要对多个字段进行组合校验。Spring MVC 提供了 `@Validated` 和 `@...

Global site tag (gtag.js) - Google Analytics