作为java程序员,往往对于spring、struts、Hibernate、iBatis 等国外的开源框架都比较熟悉。它们的确经典,的确强大,的确好用。但是随着时间的发展,这些框架越来越庞大!Hibernate的核心包已经超过2M, spring呢,它现在已经被拆分为 18 个子项目,而且还有继续扩大的趋势。为了一个小小的功能,引入那么一大堆lib包,任谁都得考虑一下吧。
……
这个问题一直存在,直到 Nutz 框架的出现。
一个不到 900K 的开源框架,不仅包含了 ioc、aop、dao、mvc、log,还整合了很多好用的工具类,基本上我们做一个项目需要用到的功能都提供了。
还有要说明的是,它可是国人的开源项目哦,提供全套中文文档,及大量的中文注释。国内的开发人员应该会感到比较亲切吧。
更详细的信息,请参看Nutz的官方网站: http://code.google.com/p/nutz/
Nutz框架虽然提供了很多功能,却独独拉了校验功能的支持。我们知道,一个程序,尤其是Web程序,如果没有服务器端验证,那么将非常容易受到攻击的。
“自己动手,丰衣足食”。既然官方没有提供,那就自己搞一套吧。还好基于Nutz现有的工具类,实现起来并不太复杂。
整个验证框架提供了12种常见的验证形式,且支持自定义正则表达式,基本上可以满足实际的需要。对于有特殊要求的字段验证,允许用户自己定义验证的方法。
校验不仅可以用于Web层,你可以把它用于程序的任何层面(如入库前对pojo 字段值进行验证)。
目前验证框架基于注解,因为对于字段的验证需求一般比较固定,所以同代码一块管理比较方便。当然你也可以扩展它,提供其它形式的验证。如果你有更好的改动,请也一并发我邮箱一份哈。
废话不多说,直接上代码吧。
/** * 验证支持注解 * * @author QinerG([email protected]) */ @Retention(RetentionPolicy.RUNTIME) @Target( { ElementType.PARAMETER, ElementType.FIELD }) public @interface Validations { /** * 必填字段验证规则 */ public boolean required() default false; /** * 手机号验证规则 */ public boolean mobile() default false; /** * 帐号验证规则(字母开头,允许字母数字下划线),常与字串长度验证规则混合使用 */ public boolean account() default false; /** * Email 验证规则 */ public boolean email() default false; /** * QQ 号验证规则 */ public boolean qq() default false; /** * 字串必须为中文验证规则 */ public boolean chinese() default false; /** * 邮政编码验证规则 */ public boolean post() default false; /** * 正则表达式验证规则 */ public String regex() default ""; /** * 重复性验证规则。请放置待比较的字段名 */ public String repeat() default ""; /** * 字符串最大、最小长度验证规则 */ public int[] strLen() default {}; /** * 数值型数据取值范围区间验证规则,兼容 int、long、float、double */ public double[] limit() default {}; /** * 自定义效验规则,可以自行指定验证的方法名称 <br/> 该方法必须是public的,且没有参数返回值为boolean型 */ public String custom() default ""; /** * 错误提示语 */ public String errorMsg(); }
这就是注解类的全部代码。该注解是字段(FIELD)级别的,所以你可以把它声明在pojo的属性上。
比如:
//账号验证规则,与字符串长度区间验证共同作用 @Validations(account = true, strLen = { 3, 16 }, errorMsg = "account") private String account;
允许多种验证同时声明,errorMsg 是错误提示语,必填。
当pojo需要验证的时候,可以这样写:
AnnotationValidation av = new AnnotationValidation(); Errors ers = av.validate(pojo);
这时也许你会说,这种调用方法很麻烦。每次验证的时候,都需要创建 AnnotationValidation 的实例,有没有更简单的方法呢?
没错,Nutz提供了 AOP 的支持,这样我们就可以很方便的用它来进行拦截验证了。
下面是拦截器的全部代码:
/** * 基于注解的验证用拦截器 * <p> * 该拦截器主要用于方法参数的验证,要求该方法中必须有一个 Errors 类型的参数(允许为空),当验证完成后会向这个参数赋值 * * @author QinerG([email protected]) */ @IocBean(name = "validationInterceptor") public class ValidationInterceptor extends AbstractMethodInterceptor { private static AnnotationValidation av = new AnnotationValidation(); /** * 方法调用前进行拦截,遍历参数进行验证 */ public boolean beforeInvoke(Object obj, Method method, Object... args) { Errors es = ValidationUtils.checkArgs(method.getParameterTypes(), args); if (null != es) { for (Object argsObj : args) { if (argsObj instanceof Errors) continue; av.validate(argsObj, es); } } return true; } }
注意:该拦截器主要用于方法参数的验证,要求该方法中必须有一个 Errors 类型的参数(允许为空),当验证完成后会向这个参数赋值。
有了这个拦截器,就方便多了。只需要在需要提供验证功能的方法前使用 @Aop("validationInterceptor") 声明,例如:
@Aop("validationInterceptor") public Errors test(Bean bean, Errors es) { System.out.println(es.errorCount()); return es; }
之后在调用这个方法的时候,拦截器就会自动执行,并将验证结果注入到参数 Errors 中。下面是 junit测试用例:
@Test public void testAop() { Ioc ioc = new NutIoc(new AnnotationIocLoader("org.nutz.validation")); ServiceDemo sd = ioc.get(ServiceDemo.class); Bean b = new Bean(); Errors ers = sd.test(b, null); assertEquals(10, ers.errorCount()); }
这样是不就方便了很多?
应用程序可以用 aop 的方式验证,那么 web 程序呢,也可以这样用吗?那是当然了。在 action 前声明拦截器:
@At("/test") @Ok("json") @Aop("validationInterceptor") public int test(@Param("bean")Bean bean, Errors es) { System.out.println(Dumps.obj(bean)); if (es != null) { return es.errorCount(); } return -99; }
action 里即可以取到 Errors 对象,并可以对其进行显示等相关处理啦。
附件为全部源代码,及测试用例。欢迎大家拍砖!