`
yueguangyuan
  • 浏览: 336848 次
  • 性别: Icon_minigender_1
  • 来自: 新加坡
社区版块
存档分类
最新评论

复杂Struts Validation汇总

阅读更多

不得不承认我用了太久的Struts1,但实际上并没有太多好的回忆,在大家都忙着学习Seam、JSF、SpringMVC和Struts2的时候我还不得不使用老掉牙的Struts1。好在每次用还是会用新收获,前提是你跳槽到新公司 -__-!!

    背景:说正题,新公司新项目,主体不在Web App上面,因为系统主要用于数据管理对数据库的完整性和准确性,所以需求上光是验证就有60页的文档,对每一条进入系统的数据都有很严格的要求:包括单个数据和数据之间的关系都有详细的规定,由于我负责的是单个数据的验证,所以本文只关心单个数据的有效性验证。

   

    方案:既然用了Struts,那就很难离开ActionForm(当然也有狠人直接把ActionFrom也干掉@_@),用了ActionForm自然而然的选择Struts Validation。Struts Validation不知道算不算目前Web表现层最好的验证方案,但是肯定是使用最广泛的一种,但是它仍然不够用。

 

    又跑题了,所以对于单个用户录入数据的有效性验证仍然采用Struts Validation,在做过一些改动后,Struts Validation还是能很好的完成这项工作。

 

1.使用validwhen来做简单的交互性验证

     这个网上经常可以搜到,也算是Validation里面最复杂、功能最花哨的一部分,单单为了实现这个功能,Validation就用了4个以上的类去工作,包括字符串的解析这种比较繁琐的工作。它的主要用途是用来做一些简单的交互性的验证,比如A不为空的时候B必须有值,可以做点简单的交互验证哦,但是我并不是很喜欢这东西,写表达式测试起来挺烦的,但是2,3个数据的相互制约还是可以考虑,最常用的就是上面说到的要求,我们可以这样写:

<field property="name" depends="validwhen">
  <arg position="0" key="label.name" resource="true" bundle="common" />
  <var>
    <var-name>test</var-name>
    <var-value>((age == null) or (*this* != null))</var-value>
  </var>
</field>

 

 age不为空的时候name也不能为空,很常见的验证要求。由于这东西每次调试都要重启Server,很烦人,所以我也没做过多的尝试,那个表达式写起来也挺折腾人的,一不小心就失败。如果有兴趣可以参考Validation官方文档中的几条要求做更复杂的表达式来给你的表单做验证。当然这东西还是问题多多的,也可以说凡是用配置文件搞出来的东西,就不会百分之百的符合你的要求。

 

2.使用indexedListProperty为一个循环fields

    这也是Validation里面默认就提供的功能,如果你的表单中包含循环元素生成的元素的时候就可以考虑用indexedListProperty来进行验证,这个很简单,只给出例子:

<field property="name" indexedListProperty="friends" depends="required">
  <arg position="0" key="label.name" resource="true" bundle="common" />
 </field>

indexedListProperty经常与validwhen一起用。

 

3.自定义validator

    Validation里面提供的都是写基本的验证,更多时候需要自定义一些验证来整合我们的业务,所以validation提供了它的扩展接口,其实也就是用配置文件validator-rules.xml的方式来扩展validator。有了这个东西,你可以把任意复杂度的东西放在里面做你想做的验证。这个扩展功能很得人心,这样Validation的灵活度就非常大,更好的做到重用。

<validator name="name"
               classname="com.cyan.action.validator.CommonValidator"
               method="validateName"
               methodParams="java.lang.Object,
               org.apache.commons.validator.ValidatorAction,
               org.apache.commons.validator.Field,
               org.apache.struts.action.ActionMessages,
               org.apache.commons.validator.Validator,
               javax.servlet.http.HttpServletRequest"
               msg="msg.error.name">
    </validator>

 

 指定了这个新的validator,你可以任意加入自己的验证机制,在com.cyan.action.validator.CommonValidator中增加validateName()方法,注意在配置文件中已经默认指定了适合Struts ActionForm所需要的参数,你也需要在方法里使用,这样才能整合进Struts Validation并且方便的使用它的Message popup机制。这样你就可以实现你自己的validator:

public static boolean validateName(Object bean, ValidatorAction va,
        Field field, ActionMessages errors, Validator validator,
        HttpServletRequest request) {
        String value = null;
        Integer result = null;

        value = evaluateBean(bean, field);

        // add your validation logic here
        if (!GenericValidator.isBlankOrNull(value)) {
              errors.add(field.getKey(),
                Resources.getActionMessage(validator, request, va, field));            
              return false;
        }

        return true;
}

 这样的扩展写着非常的自如,因为本身Validation对这个CommonValidator的要求很低,它不需要继承和实现任何接口类,当然你也可以继承org.apache.struts.validator.FieldChecks去继承它的一些基本验证。你也同样可以修改validator-rules.xml里面的默认validator指定到你自己的验证规则上。

 

4.JavaScript客户端验证

    这个功能很早就在Struts中得到了支持,因为是客户端就验证了,可以有效减少服务器端的负载,而且Struts Validation JavaScript模式还可以提供Client Server两端验证这种双保险机制,可以减少不少工作量和维护工作。要使用它除了在服务器端进行基础的validation配置以外,还需要给你的页面form增加一点东西(参考:http://www.xker.com/page/e2007/0727/28232.html):

< script language="Javascript1.1" src="js/validator.js">< /script>
< html:javascript formName=”loginForm”>
< html:form action="manageContract.do" onsubmit="return validateLoginForm(this);>
大概是这么写,显然这不是我想说的,网上找这个很容易。我要说的是JavaScript验证方式的问题: JavaScript方式的验证会自动将后台验证代码转化成JavaScript,毕竟是框架生成的,会导致每页JS代码暴增,会影响页面加载速度;还有一个问题就是你自己定义的验证人家没法给你转化成JS,怎么办?用它的JavaScript Plugin。

//TODO

 

5.验证器的继承

     上面已经提到过,系统对验证的要求比较高,common validation就多达100多个,那么按照validation默认的方式对每个ActionForm去写这重复的东西很不现实,所以Validation提供了一个继承方式:

<form name="BaseForm">
  <field property="name" depends="required">
    <arg position="0" key="label.name" resource="true" bundle="common" />
  </field>
</form>

<form name="loginForm" extends="BaseForm">
</form>

 

这样loginForm就会默认的包含一个name的validator,增加一点配置的重用性。在系统启动的时候,validation会检查所有form的parent并进行合并validator,它会让“子类”form里面的validator覆盖父类的,也就是说你继承了BaseForm,如果有不同的验证,你可以把它覆盖掉。

 

6.扩展Validation

     这里说的扩展Validation不是说写那个validator-rules.xml,我要说的是Validation验证还是太简单,我想更好的使用它就得在它的基础上进行扩展。用框架的时候为了使得框架更适合我们的项目,自然而然的选择去扩展,在Struts1中我们最经常看到的就是扩展org.apache.struts.action.RequestProcessor中的方法,比如其提供的

protected boolean processPreprocess(HttpServletRequest request,
        HttpServletResponse response) {
        return (true);
    }

 这是Struts框架中提供的一个很常用的扩展点,不过自打有了AOP之后它有点落寞,不妨碍我继续数用 :P。

      之所以要扩展,问题就来自于上面的使用validation继承,这个继承的问题在于你的子类form会被强迫加入所有父类的validator,比如父类里面有一个age的验证,而你子类里面也被强制增加了这个age验证器,不管你有没有age这个字段。我不知道是validation没想明白还是我没用明白,这样的继承机制谁还敢用,所以我使用下面的扩展方案,如果有其他办法,希望不吝赐教。

 

在这里先抱怨一下,Validation的确是个好东西,但是它的代码显然是积怨太深,每次验证出问题我去调试跟代码都会很痛苦,因为它写的的确很难懂,好多类、好多方法掺和在一起,也许是我无法理解那些大师们的用意。

 

扩展org.apache.struts.validator.ValidatorForm中的validate()方法,当然你的类是可以继承任意ValidatorForm的子类,我们继承的是LazyValidatorForm。

这个扩展类里面的代码就比较多了(主要因为里面bug比较多),这里只给出部分代码段,主要实现的功能有:

     1.子类实现“伪”继承,就是说子类只根据需要取父类的validator

     2.validator支持多个名字,如:<field property="name, person.name" depends="required, length">

由于项目中使用的是LazyValidatorForm,form表单里的名字是以map方式传回Action,并支持POJO的populate,所以我们的验证器会有对person.name这种字段的验证,当然扩展的时候也主要在这里出现问题。

 

首先是修改validator加载的来源:

public class BaseForm extends LazyValidatorForm {
        
    public ActionErrors validate(ActionMapping mapping,
        HttpServletRequest request) {
        ServletContext application = getServlet().getServletContext();
        ActionErrors errors = new ActionErrors();

        String validationKey = getValidationKey(mapping, request);

        // Override code Validator validator =
        //     Resources.initValidator(validationKey, this, application, request,  errors, page);
        Validator validator =
            initValidator(validationKey, this, application, request,
                errors, page);

        try {
            validatorResults = validator.validate();
        } catch (ValidatorException e) {
            logger.error(e.getMessage(), e);
        }

        return errors;
    }
}

  顺便你还得提供一个类似于org.apache.struts.validator.Resources.initValidator()的方法:

 

public Validator initValidator(String key, Object bean,
        ServletContext application, HttpServletRequest request,
        ActionMessages errors, int page) {
        ValidatorResources resources =
            Resources.getValidatorResources(application, request);

        Locale locale = RequestUtils.getUserLocale(request, null);
        
        Form form = resources.getForm(locale, key);

        // Override codes here start
        if (form != null) {
            List lFields = (List) getPrivateField(form, "lFields");
            Map hFields = (Map) getPrivateField(form, "hFields");
            
            filterFields(lFields, resources, hFields);
        }
        // end

        Validator validator = new Validator(resources, key);

        validator.setUseContextClassLoader(true);

        validator.setPage(page);

        validator.setParameter(SERVLET_CONTEXT_PARAM, application);
        validator.setParameter(HTTP_SERVLET_REQUEST_PARAM, request);
        validator.setParameter(Validator.LOCALE_PARAM, locale);
        validator.setParameter(ACTION_MESSAGES_PARAM, errors);
        validator.setParameter(Validator.BEAN_PARAM, bean);

        return validator;
    }

 (代码中的private property accessor参考:http://snippets.dzone.com/posts/show/2242

 

因为这并不是框架中提供的一个扩展点,所以这个代码看起来挺别扭,明明只要修改它一句话,但其他的你也得加上。

这样你就可以修改它加载validator的方式,不过这只是个开始,validation并不希望你去这么做,真正的麻烦还在后面。其实麻烦已经出现了,在上面这段覆盖initValidator()的方法中我已经被迫使用了Java reflection中的private property accessor,再一次提醒你人家validation不想你去碰它,god bless me。

    这样总算是获得了Struts Validation里面针对没一个form的validator集合,实际是存放在ValidatorResources中的org.apache.commons.validator.Form中的一个List类型的多个org.apache.commons.validator.Field。然后我们就可以任意的去修改它们,发挥你的聪明才智去适应你的需求吧!记得在修改完毕以后需要完璧归赵:ValidatorResources资源被存放在ServletContext里面作为全局变量保存,你在修改完Form里面的lFields以后需要重新放回去,这个很关键,否则你修改的东西就只能生效一次,下次再来的时候人家就不认识你咯。

    至于如何修改我就不给出代码了,有兴趣的朋友可以看看附件,代码我简单改过,主要是去掉了公司的信息,代码还在测试使用中(因为要适应我们项目的需要),也许你会感到代码写的比较ugly,狂多的for循环和if else,写的时候着实耗费我不少功夫去调试。

 

这样就算是把我目前知道的有关Struts Validation的一些复杂应用总结完了,其实验证就是一个纯体力活,写这些东西就是为了减少奋战在一线的战友们减轻点负担,hope it will help you。

分享到:
评论
2 楼 dmwdmc 2010-05-04  
小月。。。。。。。。。
1 楼 xyjava 2008-11-17  
沙发,,,

相关推荐

    Struts Validation框架浅尝

    ### Struts Validation框架浅尝 #### Struts Validation框架概述 Struts Validation框架是Apache Struts框架的一个重要组成部分,主要用于在Web应用中实现表单验证功能。通过使用该框架,开发者可以方便地对用户...

    Struts2中Validation数据验证框架教程

    在Struts2中,Validation框架是用于处理数据验证的重要组件,它允许开发者在用户输入提交到服务器之前或之后进行验证,确保数据的准确性和完整性。下面将详细解释Struts2中的Validation框架及其在前后台验证中的应用...

    Struts-Validation

    自动验证基于配置文件(通常是struts-config.xml或struts-validation.xml)和自定义的ValidatorForm类。在配置文件中,开发者定义了每条验证规则,如字段的必要性、长度限制、正则表达式等。自定义的ValidatorForm类...

    struts2_validation

    Struts2提供了一些基于XWork Validation Framework的内建验证程序,它们大大简化了输入验证工作。 使用这些验证程序不需要编程,程序员只需要在一个XML文件里对验证程序应该如何工作做出声明就行了。需要声明的内容...

    Struts1.2中的validation验证框架的实现步骤

    ### Struts1.2中的Validation验证框架实现步骤详解 #### 一、环境配置与准备工作 在Struts1.2框架中实现验证功能首先需要完成环境配置。这包括添加必要的库文件(JAR包)、配置XML文件等。 ##### 1.1 添加...

    关于Struts2与Validation框架使用中的问题

    1. 添加依赖:在项目中引入Struts2和Validation相关的jar包,例如struts2-core、struts2-convention-plugin、hibernate-validator等。 2. 配置Struts2:在struts.xml配置文件中启用Struts2的验证插件,如`...

    Struts2_Validation

    从...相信对正在学习Struts2的朋友有很大的帮助,最后还要说重申,所用资料均来源于互联网,所有版权归原作者所有! 上班时间偷偷做的,希望能对大家有所帮助,多多交流!

    Struts 下应用 validation验证 配置详细

    Struts validation 验证框架配置,简单易懂,一看就会

    struts的validation验证框架源码

    Struts的Validation验证框架是基于Java的Web应用开发中的一个重要组件,主要用于处理用户输入的数据验证。这个框架在Struts 1.x版本中被广泛使用,它通过定义一系列的规则来确保用户提交的数据满足应用程序的需求,...

    struts2 validation

    Struts2 Validation是Apache Struts框架的一个重要组成部分,主要用于处理Web应用中的数据验证。这个框架提供了灵活且强大的机制,帮助开发者实现对用户输入的有效性检查,确保数据的准确性和安全性。下面将详细介绍...

    Struts2 Validation验证实例

    Struts2提供了一种强大的验证机制,即Struts2 Validation,它允许开发者定义并执行表单字段的验证规则。 验证在Web开发中的主要目的是防止无效数据进入数据库或执行错误的业务逻辑。Struts2的验证框架允许我们在...

    Struts使用validation框架来实现校验,4种以上的校验规则

    在Struts中,Validation框架是用于处理用户输入验证的重要组件,它可以确保用户提交的数据符合预定义的规则,从而提高应用程序的安全性和用户体验。 在创建一个注册模块时,通常需要对用户的输入数据进行严格的验证...

    struts_validation.zip

    这个"struts_validation.zip"压缩包显然包含了与Struts框架相关的验证功能的示例项目。Struts的核心目标是提供一个可扩展且模块化的平台,用于构建企业级的Java Web应用程序。在Struts中,验证是非常重要的一环,它...

    struts2 validation入门

    这篇博客"Struts2 Validation入门"可能引导读者了解如何在Struts2中实现有效且直观的输入验证。 在Struts2框架中,验证分为两个主要阶段:客户端验证和服务器端验证。客户端验证通常通过JavaScript在用户的浏览器上...

    struts2中两种validation.xml的配置方式

    在Struts2框架中,`validation.xml`是用于定义验证规则的重要配置文件。根据所提供的信息,我们可以了解到文章主要探讨了Struts2中两种不同的`validation.xml`配置方式,并且通过一个具体的例子进行了说明。下面将对...

    Validation_Struts2

    2. **Validator插件**:Struts2的Validator插件提供了验证框架,它可以读取XML配置文件(struts-validation.xml或struts-plugin.xml)或使用注解定义验证规则。 3. **Validation拦截器**:这是Struts2的核心组件之...

    Struts2 validation.xml 经典验证

    在Struts2框架中,`validation.xml`是用于定义数据校验规则的重要配置文件,它允许开发者对Action类中的字段进行各种格式的验证,确保数据的完整性和正确性。通过`validation.xml`,我们可以实现对日期、字符、数字...

    struts_auto_Validation

    在Struts中,自动验证(Auto Validation)是一种方便且强大的功能,它允许开发者在处理用户输入时进行数据校验,以确保数据的有效性和一致性。在"struts_auto_Validation"的包中,我们很显然关注的是Struts 1.x版本...

Global site tag (gtag.js) - Google Analytics