锁定老帖子 主题:Struts2潜水(客户端静态验证)
精华帖 (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" )) {
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
浏览 2832 次