`
yzabstract
  • 浏览: 14259 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

自己动手实现Java Validation 和JSR 303

    博客分类:
  • J2EE
阅读更多
参数检查用得最多的是JSR 303,用法示例:
http://blog.csdn.net/caihaijiang/article/details/7463514
但JSR 303有个缺点,那就是当参数的限制发生变化时,例如某String类型的最大长度由10改为20,就需要改代码重新编译。
那有没有办法只改配置文件重启程序就达到目的呢?
网上还没有类似的解决方案,那就自己实现Java Validation。

思路:
参数检查时,从配置文件中取得参数的限制条件,通过反射取得对应的字段值,并进行验证。

用法:

Java代码  收藏代码
//利用反射和注解自行实现的参数检查 
 
           Order order = newOrder(); 
           Map<String, String> configMap = ConfigMap.INSTANCE.getMap(); 
         
        //需要两个参数:一是需要参数检查的对象,二是参数的限制条件 
           List<String> list = Checker.INSTANCE.check(order, configMap); 
           for (String str : list) { 
         
            /*输出示例:
            cardNo不符合正则表达式\d+
            name长度最小不能小于2
            address长度最小不能小于2
            intVal最大不能超过9
            integerVal最小不能小于4
            longVal最小不能小于4
            longGVal最小不能小于4
            */ 
               System.out.println(str); 
           } 
 
       } 
 
     

Java代码  收藏代码
     
package com.ljn.validation; 
 
import java.util.HashMap; 
import java.util.Map; 
 
/**

* 模拟从配置文件中读取配置值
* 用点号分隔,最后是字段名
*/ 
public enum ConfigMap { 
    INSTANCE; 
     
    private Map<String, String> map; 
     
    ConfigMap() { 
        map = new HashMap<String, String>(); 
         
        //在配置文件中这样写:check.com.ljn.validation.MyOrder.userId.max=3 
        //表示MyOrder这个类的userId字段,长度最大为3 
        map.put("check.com.ljn.validation.MyOrder.userId.max", "3"); 
        map.put("check.com.ljn.validation.MyOrder.name.max",  "3"); 
        map.put("check.com.ljn.validation.MyOrder.address.max", "3"); 
         
        map.put("check.com.ljn.validation.MyOrder.cardNo.reg", "\\d+"); 
         
        map.put("check.com.ljn.validation.MyOrder.intVal.max",  "9"); 
        map.put("check.com.ljn.validation.MyOrder.integerVal.max",  "9"); 
        map.put("check.com.ljn.validation.MyOrder.longVal.max",  "9"); 
        map.put("check.com.ljn.validation.MyOrder.longGVal.max",  "9"); 
         
        map.put("check.com.ljn.validation.MyOrder.userId.min", "2"); 
        map.put("check.com.ljn.validation.MyOrder.name.min",  "2"); 
        map.put("check.com.ljn.validation.MyOrder.address.min", "2"); 
                       
        map.put("check.com.ljn.validation.MyOrder.intVal.min",  "4"); 
        map.put("check.com.ljn.validation.MyOrder.integerVal.min",  "4"); 
        map.put("check.com.ljn.validation.MyOrder.longVal.min",  "4"); 
        map.put("check.com.ljn.validation.MyOrder.longGVal.min",  "4"); 
         
        map.put("check.com.ljn.validation.MyOrder.bigDecimalVal.maxBigDecimalIntegerSize",  "5"); 
        map.put("check.com.ljn.validation.MyOrder.bigDecimalVal.maxBigDecimalFractionSize",  "2"); 
    } 
 


Java代码  收藏代码
package com.ljn.validation; 
 
import java.math.BigDecimal; 
import java.util.List; 
 
import javax.validation.constraints.Digits; 
import javax.validation.constraints.Max; 
import javax.validation.constraints.Min; 
import javax.validation.constraints.NotNull; 
import javax.validation.constraints.Size; 
 
public class Order { 
     
    @Check(NotNull=true) 
    @NotNull 
    private List nullVal; 
     
    @Size(min =2, max = 3) 
    @Check(Min=true,Max=true) 
    private String name; 
     
    @Size(min =2, max = 3) 
    @Check(Min=true, Max=true) 
    private String address; 
 
    private String userId; 
 
    @Min(4) 
    @Max(9) 
    @Check(Min=true, Max=true) 
    private int intVal; 
     
    @Min(4) 
    @Max(9) 
    @Check(Min=true, Max=true) 
    private Integer integerVal; 
     
    @Min(4) 
    @Max(9) 
    @Check(Min=true, Max=true) 
    private long longVal; 
     
    @Min(4) 
    @Max(9) 
    @Check(Min=true, Max=true) 
    private Long longGVal; 
     
    @Digits(integer=5, fraction=2) 
    @Check(MaxBigDecimalFractionSize=true, MaxBigDecimalIntegerSize=true) 
    private BigDecimal bigDecimalVal; 
     
//...setter and getter 
    } 

测试表明,Checker比JSR 303速度更快。Checker没有JSR 303那么全面,但也基本够用。

源码:
Java代码  收藏代码
import java.lang.annotation.ElementType; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 
 
/**
* 1.NotNull/NotBlank默认值为false,其他为true
* 2.即使Min/Max/MaxBigDecimalIntegerSize/MaxBigDecimalFractionSize/RegExp这些选项配置为true,
*   也需要在配置文件中配置了具体值才会进行检查
* 3.对于String类型,不要同时配置NotNull和NotBlank,建议只配置NotBlank
* @author ljn
*
*/ 
@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.FIELD) 
public @interface Check { 
  
    /**
     * 检查是否为null,适用所有数据类型
     */ 
    public boolean NotNull() default false; 
     
    /**
     * 检查字符串是否为空字符串(包括null),相当于StringUtils.isBlank
     */ 
    public boolean NotBlank() default false; 
     
    /**
     * 对于String类型,检查字符串长度是否小于最小长度
     * 对于short/Short/int/Integer/long/Long类型,检查是否小于最小值
     */ 
    public boolean Min() default true; 
     
    /**
     * 对于String类型,检查字符串长度是否超过最大长度
     * 对于short/Short/int/Integer/long/Long类型,检查是否超过最大值
     */ 
    public boolean Max() default true; 
     
    /**
     * 检查BigDecimal类型的整数部分的长度是否超过最大长度
     */ 
    public boolean MaxBigDecimalIntegerSize() default true; 
     
    /**
     * 检查BigDecimal类型的小数部分的长度是否超过最大长度
     */ 
    public boolean MaxBigDecimalFractionSize() default true; 
     
    /**
     * 检查字符串类型的值是否符合正则表达式指定的格式
     */ 
    public boolean RegExp() default true; 
  

 
public enum Checker { 
     
    INSTANCE; 
     
     
    public static final String KEY_SEPARATOR = "."; 
    public static final String PREFIX = "check"; 
    public static final String SUFFIX_MAX = "max"; 
    public static final String SUFFIX_MIN = "min"; 
    public static final String SUFFIX_MAX_BIGDECIMAL_INTEGER_SIZE = "maxBigDecimalIntegerSize"; 
    public static final String SUFFIX_MAX_BIGDECIMAL_FRACTION_SIZE = "maxBigDecimalFractionSize"; 
    public static final String SUFFIX_REG_EXP = "regExp"; 
     
    private Map<Class<?>, List<Field>> classFields = new HashMap<Class<?>, List<Field>>(); 
     
    /**
     * 
     * @param obj 对obj进行参数检查
     * @param configMap 配置值,配置了各字段的限制值,例如最小长度,最大长度
     * @return 参数不合法的信息列表
     */ 
    public List<String> check(Object obj, Map<String, String> configMap){ 
        List<String> list = new ArrayList<String>(); 
         
        if (obj == null || configMap == null || configMap.isEmpty()) { 
            return list; 
        } 
         
        Class<? extends Object> clazz = obj.getClass(); 
        List<Field> fields = classFields.get(clazz); 
        if (fields == null) { 
            fields = getFieldsUpTo(clazz, Object.class); 
            if (fields == null || fields.isEmpty()) { 
                return list; 
            } 
            classFields.put(clazz, fields); 
        } 
         
        for (Field field : fields) { 
            field.setAccessible(true); 
            Check check = field.getAnnotation(Check.class); 
            if (check == null) { 
                continue; 
            } 
             
            Class<?> fieldType = field.getType(); 
            String fieldName = field.getName(); 
            Object value = null; 
            try { 
                value = field.get(obj); 
            } catch (Exception e) { 
                throw new RuntimeException(e); 
            } 
             
            if (value == null) { 
                if (check.NotNull()) { 
                    list.add(fieldName + "不能为null"); 
                } else if ( check.NotBlank() && fieldType.equals(String.class)) { 
                    list.add(fieldName + "不能为空"); 
                } 
            } else { 
                 
                //check_className_fieldName_suffix 
                String minKey = StringUtils.join(new String[]{PREFIX, clazz.getName(), fieldName, SUFFIX_MIN}, KEY_SEPARATOR);                 
                String maxKey = StringUtils.join(new String[]{PREFIX, clazz.getName(), fieldName, SUFFIX_MAX}, KEY_SEPARATOR);                 
                String maxBigDecimalIntegerSizeKey = StringUtils.join(new String[]{PREFIX, clazz.getName(), fieldName, SUFFIX_MAX_BIGDECIMAL_INTEGER_SIZE}, KEY_SEPARATOR); 
                String maxBigDecimalFractionSizeKey = StringUtils.join(new String[]{PREFIX, clazz.getName(), fieldName, SUFFIX_MAX_BIGDECIMAL_FRACTION_SIZE}, KEY_SEPARATOR); 
                String regExpKey = StringUtils.join(new String[]{PREFIX, clazz.getName(), fieldName, SUFFIX_REG_EXP}, KEY_SEPARATOR); 
                 
                if (fieldType.equals(String.class)) { 
                    String val = (String)value; 
                    if (check.NotBlank() && StringUtils.isBlank(val)) { 
                        list.add(fieldName + "不能为空"); 
                    } 
                    if (check.Min()) { 
                        int min = getInt(configMap, minKey); 
                        if (min != -1 && val.length() < min) { 
                            list.add(fieldName + "长度最小不能小于" + min);  
                        } 
                    } 
                    if (check.Max()) { 
                        int max = getInt(configMap, maxKey); 
                        if (max != -1 && val.length() > max) { 
                            list.add(fieldName + "长度最大不能超过" + max);  
                        } 
                    } 
                    if (check.RegExp()) { 
                        String exp = configMap.get(regExpKey); 
                        if (StringUtils.isNotBlank(exp) && StringUtils.isNotBlank(val) && !val.matches(exp)) { 
                            list.add(fieldName + "不符合正则表达式" + exp); 
                        } 
                    } 
                } 
                 
                if (fieldType.equals(Integer.class) || fieldType.equals(int.class)) { 
                    Integer val = (Integer)value; 
                    if (check.Min()) { 
                        int min = getInt(configMap, minKey); 
                        if (min != -1 && val < min) { 
                            list.add(fieldName + "最小不能小于" + min);  
                        } 
                    } 
                    if (check.Max()) { 
                        int max = getInt(configMap, maxKey); 
                        if (max != -1 && val > max) { 
                            list.add(fieldName + "最大不能超过" + max);  
                        } 
                    } 
                } 
                 
                if (fieldType.equals(Short.class) || fieldType.equals(short.class)) { 
                    Short val = (Short)value; 
                    if (check.Min()) { 
                        int min = getInt(configMap, minKey); 
                        if (min != -1 && val < min) { 
                            list.add(fieldName + "最小不能小于" + min);  
                        } 
                    } 
                    if (check.Max()) { 
                        int max = getInt(configMap, maxKey); 
                        if (max != -1 && val > max) { 
                            list.add(fieldName + "最大不能超过" + max);  
                        } 
                    } 
                } 
                 
                if (fieldType.equals(Long.class) || fieldType.equals(long.class)) { 
                    Long val = (Long)value; 
                    if (check.Min()) { 
                        long min = getLong(configMap, minKey); 
                        if (min != -1 && val < min) { 
                            list.add(fieldName + "最小不能小于" + min);  
                        } 
                    } 
                    if (check.Max()) { 
                        long max = getLong(configMap, maxKey); 
                        if (max != -1 && val > max) { 
                            list.add(fieldName + "最大不能超过" + max);  
                        } 
                    } 
                } 
                 
                if (fieldType.equals(BigDecimal.class)) { 
                    BigDecimal val = (BigDecimal)value; 
                    String str = val.toPlainString(); 
                    String[] parts = str.split("\\."); 
                    if (parts == null || parts.length == 0) { 
                        continue; 
                    } 
                    int integerSize = parts[0].length(); 
                    int fractionSize = parts.length == 2 ? parts[1].length() : 0; 
                    if (check.MaxBigDecimalIntegerSize()) { 
                        int max = getInt(configMap, maxBigDecimalIntegerSizeKey); 
                        if (max != -1 && integerSize > max) { 
                            list.add(fieldName + "整数部分长度最大不能超过" + max); 
                        } 
                    } 
                    if (check.MaxBigDecimalFractionSize()) { 
                        int max = getInt(configMap, maxBigDecimalFractionSizeKey); 
                        if (max != -1 && fractionSize > max) { 
                            list.add(fieldName + "小数部分长度最大不能超过" + max); 
                        } 
                    } 
                } 
                 
                 
            } 
             
 
        } 
        return list; 
    } 
     
    /**
     * 获取所有的Field
     * @param startClass
     * @param exclusiveParent
     * @return
     */ 
    public List<Field> getFieldsUpTo(Class<?> startClass, Class<?> exclusiveParent) { 
 
        List<Field> currentClassFields = new ArrayList<Field>(); 
        Field[] declaredFields = startClass.getDeclaredFields(); 
        for (Field field : declaredFields) { 
            currentClassFields.add(field); 
        } 
        Class<?> parentClass = startClass.getSuperclass(); 
 
        if (parentClass != null && (exclusiveParent == null || !(parentClass.equals(exclusiveParent)))) { 
            List<Field> parentClassFields = (List<Field>) getFieldsUpTo(parentClass, exclusiveParent); 
            currentClassFields.addAll(parentClassFields); 
        } 
 
        return currentClassFields; 
    } 
     
    private static int getInt(Map<String, String> map, String key) { 
        String val = map.get(key); 
        if (val != null) { 
            return Integer.parseInt(val); 
        } 
        return -1; 
    } 
     
    private static long getLong(Map<String, String> map, String key) { 
        String val = map.get(key); 
        if (val != null) { 
            return Long.parseLong(val); 
        } 
        return -1; 
    } 
     
 
分享到:
评论

相关推荐

    jsr 303 jar包下载

    按照课件推荐下载,准确有效,包括(hibernate-validator-4.3.2.Final.jar;jboss-logging-3.1.0.CR2.jar;validation-api-1.1.0.Alpha1.jar和jsr303约束文档)

    JSR303依赖的jar包

    JSR-303 是 JAVA EE 6 中的一项子规范,叫做 Bean Validation,官方参考实现是Hibernate Validator。JSR 303 用于对 Java Bean 中的字段的值进行验证。 Spring MVC 3.x 之中也大力支持 JSR-303,可以在控制器中对...

    JSR-303接口标准和参考实现

    整合jsf2 bean验证需要的jar包,j2ee6规范jsr303 hibernate-validator-4.2.0.Final validation-api-1.0.0.GA

    佟刚_JSR303验证.

    JSR-303 是 JAVA EE 6 中的一项子规范,叫做 Bean Validation,官方参考实现是 Hibernate Validator。 此实现与 Hibernate ORM 没有任何关系。JSR 303 用于对 Java Bean 中的字段的值 进行验证。

    JSR303 jar包 文档

    JSR 303 jar包 validation-api-1.1.0.jar hibernate-validator-4.3.0.jar

    JSR303校验Hibernate Validator实现需要用到的jar包

    JSR303校验Hibernate Validator实现需要用到的jar包。hibernate-validator-5.4.1.Final.jar + jboss-logging-3.1.3.GA.jar + validation-api-1.1.0.Final.jar+classmate-1.3.3.jar + hibernate-validator-cdi-5.4.1....

    JSR303要用的jar包

    JSR303要用的jar包 validation-api-1.0.0.GA hibernate-validator-4.3.0.Final

    jsr303jar包.zip

    JSR303用到的jar包,本人使用的,现分享给大家,希望能给大家带来帮助 classmate-0.8.0.jar hibernate-validator-5.0.0.CR2.jar hibernate-validator-annotation-processor-5.0.0.CR2.jar jboss-logging-3.1.1...

    JSR303需要用到的3个jar包

    JSR303需要用到的3个jar包。hibernate-validator-4.3.2.Final+jboss-logging-3.1.0.CR2+validation-api-1.0.0.GA

    jsr 303需要的jar包

    内涵 jboss-logging-3.1.0.CR2、hibernate-validator-4.3.2.Final、validation-api-1.0.0.GA

    validation-api-1.1.0.Final.jar

    JSR-303 是JAVA EE 6 中的一项子规范,叫做Bean Validation,现在一共有两个规范:BeanValidation1.0(即JSR303)和BeanValidation1.1(即JSR349),主要用于对数据进行校验,确保输入进来的数据从语 义上来讲是正确的。...

    The Java XML Validation API

    这是java和xml联合编程可使用的文档!

    JSR303数据效验.rar

    Spring MVC 数据效验 jar包 :classmate-1.1.0.jar,hibernate-validator-5.2.4.Final.jar,hibernate-validator-annotation-processor-5.2.4.Final.jar,hibernate-validator-cdi-5.2.4....validation-api-1.1.0.Final.jar

    Java Validation Api实现原理解析

    主要介绍了Java Validation Api实现原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    【商场秒杀项目】– 使用JSR303进行参数校验、全局异常处理

    JSR-303是JAVA EE 6中的一项子规范,叫做Bean Validation,Hibernate Validator是Bean Validation的参考实现;Hibernate Validator提供了JSR-303规范中所有内置constraint的实现,除此之外还有一些附

    Mybatis JSR303 bean validation plugin

    NULL 博文链接:https://peihexian.iteye.com/blog/1332527

    Bean+Validation中文参考手册

    Bean+Validation中文参考手册,jsr303

    Input_Validation.zip_it_java validation

    IT is a input validation system in java

    Java Validation Api如何实现自定义注解

    主要介绍了Java Validation Api如何实现自定义注解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

Global site tag (gtag.js) - Google Analytics