论坛首页 入门技术论坛

Struts2潜水(客户端静态验证)

浏览 2832 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2008-12-08  

<!----><!----><!----> <!-- /* Font Definitions */ @font-face {font-family:宋体; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-alt:SimSun; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} @font-face {font-family:"\@宋体"; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; mso-pagination:none; font-size:10.5pt; mso-bidi-font-size:12.0pt; font-family:"Times New Roman"; mso-fareast-font-family:宋体; mso-font-kerning:1.0pt;} /* Page Definitions */ @page {mso-page-border-surround-header:no; mso-page-border-surround-footer:no;} @page Section1 {size:612.0pt 792.0pt; margin:72.0pt 90.0pt 72.0pt 90.0pt; mso-header-margin:36.0pt; mso-footer-margin:36.0pt; mso-paper-source:0;} div.Section1 {page:Section1;} --> <!---->

Struts2 潜水(客户端 静态 验证)

背景:

       看了一阵子的 struts2 Struts2 的开放性,使得我们可以不再特别死板地写 action jsp 代码,可以选择 velocity freemark 。对于以前的 struts1 tag ,我是很不喜欢的,代码时甚至不用,宁可用 script 来控制请求,特别是 Ajax 流行起来之后,以 script 来处理更是大有前途。于是对 struts2 中的 tag 进行了研究。为什么要用 tag 呢,我认为主要是为了标准化,它的特点是降低代码耦合、复用代码。而在 struts2 tag 渲染部分,可以选择 jsp/velocity/freemark ,(以前见过用一些自定义的标签库,内部生成的时候,以 print 的方式写出,逻辑相当复杂,而且不利于改造,因为要进参数的话,不但要改标签代码,还要改 JSP 代码。)由于前一个项目用的 velocity 渲染页面,所以比较熟,这里就想仔细研究一下自定义的 velocity 标签改造。

试验:

       根据网上的大部分可查到的代码,改造 struts.properties struts.ui.templateDir=template/archive

struts.ui.templateSuffix=vm

       这样,再做一个 jsp 的例子:

<s:form action="hello" validate="true" theme="ajax" id="aaa">

            Name: <s:textfield name="name" />

            <s:submit />

  </s:form>

Action 部分本来不用多话,但由于 annotation 的出现,这里我也做了新的试验,

package hello;

 

import java.text.DateFormat;

import java.util.Date;

 

import org.apache.struts2.config.NullResult;

import org.apache.struts2.config.Result;

import org.apache.struts2.config.Results;

import org.apache.struts2.dispatcher.VelocityResult;

 

import com.opensymphony.xwork2.ActionSupport;

import com.opensymphony.xwork2.validator.annotations.IntRangeFieldValidator;

import com.opensymphony.xwork2.validator.annotations.RequiredFieldValidator;

import com.opensymphony.xwork2.validator.annotations.RequiredStringValidator;

import com.opensymphony.xwork2.validator.annotations.Validation;

 

@Validation

@Results({

    @Result(name="success",value="/HelloWorld.jsp",type=NullResult.class),

    @Result(name="error",value="/SayHelloWorld.jsp",type=NullResult.class),

    @Result(name="input",value="/SayHelloWorld.jsp",type=NullResult.class),

    @Result(name="velocity",value="/HelloWorld.vm",type=VelocityResult.class)

})

public class HelloAction extends ActionSupport { 

 

private static final long serialVersionUID = -3236383242453104587L;

 

private int name;

    @RequiredFieldValidator(message=" 需要 ")

    @IntRangeFieldValidator(message=" 数字 ",max="1000",min="0")

    public int getName() {

        return name;

    }

 

    public void setName(int name) {

        this.name = name;

    }

   

     public String execute() {

         //name = "Hello, " + name + "!";

        return SUCCESS;

}

}

 

其它的准备是codebehinde— 这个就不多说了,有jar 就行,web.xml

<filter>

        <filter-name>struts2</filter-name>

               <filter-class>org .apache .struts2.dispatcher.FilterDispatcher</filter-class>

   <init-param >

    <param-name>actionPackages</param-name>

    <param-value>hello</param-value>

  </init-param >

</filter>

好了,这个好处是不用像 struts1 中那样配 action struts.xml 可以完全不用, annotation 的主要目的就是减少 xml 配置量,甚至零配置。

结果:

结果并不让人满意,看到的是包含 validation JS ,好像是 ajax 的,但看了源代码之后,发现虽然基本完成了验证的作用,但说到所谓“客户端”验证,实在是没有达到。网上也有很多对 struts2 验证的评价,都说不太好用,我也同样认为不行,它好像实际是用 ajax 方式向服务器请求,看验证的输入值对不对,从性能角度,没有太多改善。为什么不能在客户端静态验证呢?其实所有的验证条件已经在代码时就写好了,为什么还要在运行时再来请求验证呢?这时,看到了 jquery validator 框架,下了代码,确实非常好用,而且也非常有利于和模板结合生成。但关键是,如何在运行前取到验证条件呢?

    先来看自定义模板吧。按 struts2 什么深入什么权威什么的书上写的,在 src 下建一下目录 template/archive/mytest ,(这里还容易犯一个错误,书上说建到 template 下,但已经换成了 vm 形式的了, struts.ui.templateDir=template/archive ,所以这里也得这么建)。建一个 theme.properties 文件,里面写一个 parent = xhtml 。这里不知道是不是一个 struts2 BUG ,理论上这样就可以了,只要在 form theme 中写 mytest 就可以了,实际上,大部分是可以的,但如果 struts2 源代码 (\src\core\src\main\resources\template\archive\) 中的 vm 里用了

#parse("/$parameters.templateDir/xhtml/controlheader.vm") 之类,会报错说找不到什么什么的,所以需要把源代码中 xhtml 中的所有 vm 都复制到 mytest 目录下才行。

接下来直接重写原来的 vm 就可以了。

改进:

对于veloctiy 来说,可以自定义隐含在context 中的对像,也就是toolbox; 而对于annoation 来说,本来是第一次用,所以从网上找到一段代码ValidationUtils

public HashMap getActionForm(String clazz) {

       HashMap actionform = new HashMap ();

       try {

           Class bean = Class.forName (clazz);

           validateMethods(bean, actionform);

       } catch (Exception e) {

           // TODO : handle exception

       }

 

       return actionform;

    }

 

    private void validateMethods(Class bean, HashMap actionform) {

       // get all of public methods

       Method[] publicMethods = bean.getMethods();

       // System.out.println (publicMethods.length);

       for (Method method : publicMethods) {

           // ignore if it is not getXXX method

           if (!isGetterMethod(method)) {

              continue ;

           }

 

           Annotation[] annotations = method.getAnnotations();

   

           if (annotations. length ==0) continue ;

           List annotations1= new ArrayList ();

           for (Annotation annotation : annotations) {

              // 如果有 validate--> 后面再试以 xml 方式混合的

              if (annotation != null )

              {

                  annotations1.add(annotation);

              }

           }

           actionform.put(StringUtils.lowerCase(StringUtils.remove(

                  method.getName(), "get")), annotations1);

       }

    }

也说是从 class 的中取回所有的声明,对于 struts2 action 来说,就是 getXXX

然后,建一个 velocity-toolbox.xml

<toolbox>

<tool>

     <key>validator</key>

     <scope>application</scope>

     <class>utils.ValidationUtils</class>

  </tool>

</toolbox>

把它放到 src 下,再在 struts.properties 里, struts.velocity.toolboxlocation=WEB-INF/classes/velocity-toolbox.xml

试过之后,开始改 form.vm ,这里只是试验性的代码,当然你也可以不这么写,无所谓,反正是 vm 的模板代码,随时改,不用编译。

<form

#if ($parameters.namespace) namespace="$!struts.htmlEncode($parameters.namespace)" #end

#if ($parameters.id) id="$!struts.htmlEncode($parameters.id)" #end

#if ($parameters.name) name="$!struts.htmlEncode($parameters.name)" #end

#if ($parameters.action) action="$!struts.htmlEncode($parameters.action)" #end

#if ($parameters.target) target="$!struts.htmlEncode($parameters.target)" #end

#if ($parameters.method) method="$!struts.htmlEncode($parameters.method)" #end

#if ($parameters.enctype) enctype="$!struts.htmlEncode($parameters.enctype)" #end

#if ($parameters.cssClass) class="$!struts.htmlEncode($parameters.cssClass)" #end

#if ($parameters.cssStyle) style="$!struts.htmlEncode($parameters.cssStyle)" #end

 

#if ($parameters.validate)

  <script type="text/javascript">

    #set($form=$validator.getActionForm("$parameters.actionClass.getName()"))

  $("#${parameters.id}").validate({ 

        rules: {

         'inttype':{

            required:true,

            number:true,

            min:0,

            max:100

        },

        #foreach($method in $form.keySet())

        #set($annotations=$form.get($method))

            $method :{

            #foreach($annotation in $annotations)

       

                $validator.toJQueryValidRule($annotation)   #if($velocityCount!=$annotations.size()),#end

            #end

            }

        #end

          }

      }

);

       

  </script>

#end

<table class="wwFormTable">

 

这里主要是两个问题,一个是如何得到 action uri 对应的 classname ,比较难,看了 struts2 源代码,找了好多方法,因为是 annotation 的方式验证,所以都不太成功,不知有没有找这个的代码。最后在 Form.java 里看到, evaluateExtraParamsServletRequest 方法里, addParameter("actionClass", clazz) ,发现其实是可以直接得到 classname 的。在 ValidtaionUtils 里加代码(其实并不好,只是为了减少 VM 中的代码,毕竟 VM 里写逻辑并不太好写)

public String toJQueryValidRule(Annotation annotation) {

       String rule = "" ;

       String vname = annotation.annotationType().getSimpleName();

       String v = (String) Validators .get(vname);

       if (vname.equals( "RequiredStringValidator" )) {

          

论坛首页 入门技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics