- 浏览: 786720 次
- 性别:
- 来自: 深圳
文章分类
最新评论
-
萨琳娜啊:
Java读源码之Netty深入剖析网盘地址:https://p ...
Netty源码学习-FileRegion -
飞天奔月:
写得有趣 ^_^
那一年你定义了一个接口 -
GoldRoger:
第二个方法很好
java-判断一个自然数是否是某个数的平方。当然不能使用开方运算 -
bylijinnan:
<script>alert("close ...
自己动手实现Java Validation -
paul920531:
39行有个bug:"int j=new Random ...
java-蓄水池抽样-要求从N个元素中随机的抽取k个元素,其中N无法确定
参数检查用得最多的是JSR 303,用法示例:
http://blog.csdn.net/caihaijiang/article/details/7463514
但JSR 303有个缺点,那就是当参数的限制发生变化时,例如某String类型的最大长度由10改为20,就需要改代码重新编译。
那有没有办法只改配置文件重启程序就达到目的呢?
网上还没有类似的解决方案,那就自己实现Java Validation。
思路:
参数检查时,从配置文件中取得参数的限制条件,通过反射取得对应的字段值,并进行验证。
用法:
测试表明,Checker比JSR 303速度更快。Checker没有JSR 303那么全面,但也基本够用。
源码:
http://blog.csdn.net/caihaijiang/article/details/7463514
但JSR 303有个缺点,那就是当参数的限制发生变化时,例如某String类型的最大长度由10改为20,就需要改代码重新编译。
那有没有办法只改配置文件重启程序就达到目的呢?
网上还没有类似的解决方案,那就自己实现Java Validation。
思路:
参数检查时,从配置文件中取得参数的限制条件,通过反射取得对应的字段值,并进行验证。
用法:
//利用反射和注解自行实现的参数检查 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); } }
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"); } }
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那么全面,但也基本够用。
源码:
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; } }
发表评论
-
BeanUtils.copyProperties使用笔记
2015-07-06 22:17 32635BeanUtils.copyProperties VS Pro ... -
Haproxy+Keepalived高可用双机单活
2015-01-06 17:37 6633我们的应用MyApp不支持集群,但要求双机单活(两台机器:ma ... -
返回null还是empty
2014-05-16 15:35 100第一个问题,函数是应当返回null还是长度为0的数组(或集合) ... -
返回null还是empty
2014-05-16 15:34 2326第一个问题,函数是应当返回null还是长度为0的数组(或集合) ... -
返回null还是empty
2014-05-16 15:34 152第一个问题,函数是应当返回null还是长度为0的数组(或集合) ... -
返回null还是empty
2014-05-16 15:34 114第一个问题,函数是应当返回null还是长度为0的数组(或集合) ... -
返回null还是empty
2014-05-16 15:33 100第一个问题,函数是应当返回null还是长度为0的数组(或集合) ... -
Spring源码学习-JdbcTemplate queryForObject
2014-05-09 19:45 3055JdbcTemplate中有两个可能会混淆的queryForO ... -
Spring源码学习-JdbcTemplate batchUpdate批量操作
2014-05-07 16:21 18846Spring JdbcTemplate的batch操作最后还是 ... -
Spring源码学习-PropertyPlaceholderHelper
2014-04-25 18:47 2631今天在看Spring 3.0.0.RELEASE的源码,发现P ... -
J2EE设计模式-Intercepting Filter
2013-11-27 16:56 1538Intercepting Filter类似于职责链模式 有两种 ... -
CAS实现单点登录(SSO)
2013-07-29 18:08 1485参考以下两篇文章,对原作者表示感谢: http://blog. ... -
《重构,改善现有代码的设计》第八章 Duplicate Observed Data
2012-12-04 20:34 1520import java.awt.Color; impor ... -
org.apache.tools.zip实现文件的压缩和解压,支持中文
2012-08-08 19:32 5129刚开始用java.util.Zip,发 ...
相关推荐
Java验证程序库,通常指的是JSR 303(Bean Validation)和其后续版本JSR 349(Bean Validation 1.1),以及更现代的JSR 380(Bean Validation 2.0)。这个Java教程将深入探讨如何使用这些规范来实现数据验证,以确保...
总的来说,学习和实践“简单的Struts实现”可以帮助初学者快速进入Java Web开发领域,了解MVC架构的优势,同时为进阶的Web开发技能打下坚实的基础。通过动手实践,你可以更深入地理解Struts如何处理请求,如何组织...
"还是自己动手,才能理解其中的联系"强调了实践的重要性,只有通过亲自编写和调试代码,才能真正掌握MyBatis的精髓。 标签"示例源码"表明这些代码是用于实例教学的,它们可能包含了一些常见的MyBatis用法,如动态...
Struts2是一个强大的Java web开发框架,它提供了一种优雅的方式来组织和控制应用程序的行为。...记住,实践是最好的老师,尝试自己动手实现一个拦截器,结合实际项目去运用,你的Struts2技能将得到显著提升。
- POJO(Plain Old Java Object):允许使用普通的Java类作为bean,无需继承特定的基类或实现接口。 - 自动持久化:引入了JSR 303(Bean Validation)和JSR 317(JPA 2.0),使得数据验证和持久化更加简单。 **5. ...
Spring 框架是Java开发中的一个核心框架,尤其对于初学者来说,它是一个极好的起点,可以帮助理解企业级应用的构建方式。...通过动手实践,你可以更好地掌握Spring的精髓,为将来开发更复杂的项目打下坚实的基础。
- 编译时处理:通过`@Processor`实现Java编译器插件,处理源代码中的注解。 - 运行时处理:通过反射获取类、方法、字段上的注解,如`Class.getAnnotations()`、`Method.getAnnotation(MyAnnotation.class)`。 4. ...
Spring 3.0 是一个重要的Java企业级应用框架版本,它在2009年发布,带来了许多新特性和改进,极大地提升了开发效率和代码的可维护...请务必花时间仔细研究每个部分,理解其工作原理,并尝试自己动手实践,以加深理解。
- `LoginAction.java`:实现登录功能的Action类。 - `LoginForm.java`:封装用户输入的表单类。 - `login.jsp`:登录页面,包含用户名和密码输入元素以及提交按钮。 - `validation.xml`或`@Validated`注解:定义输入...
Struts2是一个强大的Java web应用程序框架,它基于MVC(Model-View-Controller)...记得在学习过程中,不断实践和理解每个知识点,遇到问题不要怕,多查阅资料,多动手尝试,相信你很快就能成为Struts2的熟练开发者。
11. **Validation框架**:Struts1内置了验证框架,可以在ActionForm中定义字段验证规则,或使用XML配置文件定义,用于确保用户输入的数据有效。 12. **生命周期管理**:Struts1处理请求时,Action实例通常按需创建...
在每个阶段,都应尝试自己动手编写代码,以加深理解和记忆。 通过这3天的学习,你将能够独立地使用SpringMVC搭建一个完整的Web应用,包括处理HTTP请求、管理模型数据、实现视图展示,以及进行错误处理和数据验证。...
- "Struts,MVC 的一种开放源码实现用这种servlet和JSP框架管理复杂的大型网站.doc":这份文档详细阐述了Struts作为MVC框架如何管理和控制大型网站的流程。 - "Java Web开发框架.doc":可能会涵盖多个Java Web框架...
Struts2是一个基于MVC(Model-View-Controller)设计模式的开源Java Web框架,它在Web应用开发中被广泛使用,特别是在企业级项目中。Struts2的主要目的是简化MVC架构的实现,提高开发效率,并提供强大的动作调度、...
常见的拦截器有Params(参数校验)、Exception(异常处理)、Validation(表单验证)等。 5. **JSP或Freemarker模板**:视图层,用于展示数据。Struts2支持多种视图技术,包括JSP、FreeMarker、Velocity等,这个demo...
5. **国际化的消息支持**:通过`spring-boot-starter-validation`和`spring-boot-starter-i18n`可以实现多语言支持。 ### 四、myspringboot和myspringboot-maven子项目 这两个子项目可能分别代表了一个基于Maven...
11. **Validation**:Spring提供了数据验证机制,可以通过`@Valid`注解和Validator接口实现对表单数据的校验。 12. **Interceptor**:拦截器,允许在请求处理前后执行自定义逻辑,如日志记录、权限检查等。 13. **...
常见的拦截器有Params(处理参数)、Validation(进行表单验证)、Exception(处理异常)等。 6. **Struts2的插件** Struts2提供了丰富的插件,如Struts2-convention-plugin(自动映射Action和结果),Struts2-...
5. **验证**:通过 @Valid 和 Validation API 可以实现表单验证,确保输入数据的正确性。 6. **拦截器**:自定义拦截器可以实现通用的功能,如权限控制、日志记录等,这些拦截器可以在请求处理前后执行。 这个...
通过亲自动手调试和运行这些例子,你可以更好地理解Struts2的工作原理,以及如何利用其优势来开发Java web应用。此外,这也将有助于你进一步学习Struts2的高级特性和插件,如国际化、文件上传下载、Ajax支持等。不断...