结合验证在struts中减少Action和ActionForm的数量 选择自 fancyerII 的 Blog

在用 struts 框架开发的 Web 应用中,一般习惯为数据库中的每一 Action 建一个 ActionForm ,每一张表队员几个 Action 。比如一个用户注册的简单应用中,可能有这样一些操作:新注册一个账户,修改现有账户以及删除一个账户。(对应数据库表的三种基本操作)。
最简单的做法是:分别写三个 Action 来处理他们,每个 Action 对应一个 ActionForm 。这么做比较简单,但会导致大量的类,而且对应一张表的 ActionForm 一般相同(可能有些字段没有)。因此在 struts 自己带的 struts-example 中使用了一个 RegistrationForm.java 对应了好几个 Action 。另外为了减少 JSP 的数量,它利用了 <logic:Present> 标签判断 RegistrationForm 中的属性 action 。这样根据不同的 action 的取值来显示几个(例子是两个)大同小异的 JSP 页面。
但即使这样,每一张表的操作仍然对应好几个 action 。因此 struts 中提供了 DispatchAction
[org.apache.struts.actions.DispatchAction] 来减少这些相关业务逻辑的 action 的个数,以便于系统的开发与维护。它的使用方法是:
1, 写一个 Action 继承 DispatchAtion 。如果是用 JBuilder 等工具,记得去掉自动给加上的 execute() 方法,因为 struts 会先调用此方法,如果没有的话它才会查找 action mapping 中
的 parameter 属性,根据这个属性用 Reflection 调用相应的方法。如果没找到 parameter 指定的方法,则会出错。 JBuilder 会生成一个抛出异常的 execute 方法,而我们开发最初可能不会实现这个方法,因此习惯 return 一个 null ,然后我们实现了 parameter 指定的方法,结果弄了半天也调不通。
2. 在 struts-config.xml 文件里进行 action mapping 时在 action 元素中加入一个 parameter 属性,用来指明不同参数时使用不同的方法,习惯将 parameter 取 method ,事实上取别的值也可以。如果 ActionForm 里有个请求参数的也叫 method ,那么就会引起错误。 Action[/newAccountAction] does not contain method named de   上面就是我在请求的 jsp 中添加一个 name method 的文本输入框时的错误(我在其中输入的时 de )。
 
另外,许多与更新数据库相关的业务逻辑会需要验证,在没有 validator 包 [org.apache.struts.validator] 之前只能在 ActionForm 里用 validate() 方法校验数据。如果客户端也需要验证的话, JSP 程序员还要自己写 javascript 代码,这可是件很头痛的事情,因为一般的 Java IDE 都没有调试 javascript 的功能,有时弄了半天发现是 document.formname 弄错了。在引入了 validator plugin 之后,一切变得简单了,要进行一些基本的验证(类型, email 等)只需在 validation.xml 中说明一些就可以了,也不用写 ActionForm 的 validate ()方法了。
使用方法为:
1. 写一个类继承 ValidatorForm[org.apache.struts.validator.ValidatorForm] ,如果想使用动态的 FormBean 的话修改 struts-config.xml 的 form 元素。
2 .在 validation.xml 中加入 <form> 元素。如 struts 自带的 struts-validator 例子中使用了:
      <form    name="registrationForm">
         <field    property="firstName"
                 depends="required,mask,minlength">
                   <arg0 key="registrationForm.firstname.displayname"/>
                   <arg1 name="minlength" key="${var:minlength}" resource="false"/>
                     <var>
                       <var-name>mask</var-name>
                       <var-value>^/w+$</var-value>
                     </var>
                     <var>
                       <var-name>minlength</var-name>
                       <var-value>5</var-value>
                     </var>
         </field>
         <!—more fields are omitted here à
      </form>
      它的意思是:逻辑名为 registrationForm (在 struts-config.xml 的 <form-bean> 中定义)的 ValidatorForm 的 firstName 属性需要 3 个验证:必填,输入内容是一个或多个字符,最少 5 个字符。有关 field 的属性和子元素请参考 struts 参考文档。正则表达式请参考 ORO 和 Regexp ,它们都是 jakarta 的项目。
 
在上面的 form 元素有一个必需的属性 name ,它指明了需要验证的 ActionForm 的逻辑名,如果一个 ActionForm 对应一个 Action ,这当然没有问题。但如果一个 ActionForm 想被多个 Action 使用,而且这些 Action 需要的验证是不同的,例如新注册一个用户需要验证,而查看已注册用户的信息就不能验证。因此 struts 又提供了一个 ValidatorActionForm ,它的特点是:它不是根据 form 的逻辑名,而是根据 action 的路径来验证不同的 actionform ,因为在 action mapping 时会用 name 属性指定这个 action 的 actionform 。这样一个 actionform 就可以可选择的被或不被验证了。
 
我们的目标是:对应一张表的操作,只有一个 Action 类(或其子类)和一个 ActionForm 类(或其子类)。因此,可以选择使用 DispatchAction 来处理所有相关的业务逻辑。而 ActionForm 可以是 ValidatorForm 或 ValidatorActionForm 。我在最初的想法是:使用 ValidatorActionForm 。这样,可以在 validation.xml 中将 form 元素的 name 属性指定为一个 action 的 path ,但发现这样用的话就没有办法使用客户端验证了。客户端验证要在 <html:javascript formName=””> 的 formName 属性指定 formName ( ActionForm 的逻辑名),我试着把 struts1.1 的 validator 例子的 RegistrationForm 改成 ValidatorActionForm 的子类,发现它根本每验证,而且在 jsp 中把 javascript 直接显示出来了。将 formName 属性改成那个 Action 的 path 也不管用,不知有没有别的办法实现(不能修改 Validator 类)。
即使不考虑客户端验证,也遇到一个难题:提交给一个 Action 的操作,有的需要验证(如新注册一个用户),有的不需要(如查看用户信息)。如果不作任何处理的话,则只能要么全验证,要么全不验证,这显然是不行的。当时我就想,要是 Validator 能根据请求 action 后面的参数来决定是否验证就好了。比如我在 validation.xml 中使用
      <form name="/registerAction?method=AddUser">
         <field property="userName"
                 depends="required">
                   <arg0 key="register.label.userName"/>
         </field>
      </form>
如果我的请求是 registerAction?method=AddUser ,它就验证,而如果是
registerAction?method=ViewUser ,它就不验证。于是我把 validator 包的源码加入工程,发现这个 validation.xml 中的内容都读到 ValidatorResource 这个类的一个实例中了,在验证时从这个类的实例查找相应的 formbean ,例如我在 <form name=”registerForm”> 的话,它在 ValidatorPlugIn 的 init() 方法(被 ActionServlet 的 init() 调用)时会把 name=registerForm 保存在 ValidatorPlugIn 的一个 ValidatorResource 的变量里。如果客户请求一个 action ,当然会生成一个 ActionForm (或是已存在的),如果这个 ActionForm 的逻辑名是 registerForm ,并且这个 ActionForm 的父类的 validate() 被调用(这个 ActionForm 没有 validate() 方法,或者在 validate ()方法中通过 super.validate() ),那么 ValidatorForm 会通过这个 ValidatorResource 找到要验证的 ActionForm 的逻辑名,而 ValidatorActionForm 则先通过 path 找到一个 Action ,再通过 action mapping 的 name 属性找到要验证的 ActionForm 。
因此我用 <form name="/registerAction?method=AddUser"> ,则它自然找不到一个 action 的 path 是 /registerAction?method=AddUser ,因此没有任何验证。看来这么是不行的。
那有没有别的办法呢? DispatchAction 能根据不同的参数选择不同的方法,那就应该能根据不同的参数选择不同的验证。因此我只要重写 validate 方法,如果参数是 viewUser 就不验证( return null ),否则调用父类的 validate ()。不过用这种方法有一个问题,那就是不能使用动态的 ActionForm ,即 DynaValidatorForm ,因为它根本没有这个类,不可能写 validate() 方法。
 public ActionErrors validate(ActionMapping actionMapping, HttpServletRequest httpServletRequest) {
    /**@todo: finish this method, this is just the skeleton.*/
    String parameter=actionMapping.getParameter();
    String paramValue=httpServletRequest.getParameter(parameter);
    System.out.println("from actionmapping "+paramValue);
    parameter=httpServletRequest.getParameter("method");
    System.out.println("from request "+parameter);
    if(paramValue.equals("ViewUser")){
     return null;
    }
   
    ActionErrors errors=super.validate(actionMapping,httpServletRequest);
    return errors;
   }
 
 
     测试一下,还好,都正常。绕了半天弯路,在 struts 源码中设了无数断点,却发现有这么简单的实现方法。不过也学到不少东西。对开源项目,我们总是抱怨文档太少,其实源代码就是最好的文档。

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值