• Struts 2与AJAX(第三部分)


    什么是DWR

    DWR(Direct Web Remoting)是在Java EE中较流行的AJAX框架,它的最大优势就是可以像使用本地的Javascript函数一样,调用服务器上的Java方法。如下图所示:

    DWR工作原理
    图1 DWR工作原理

    其实DWR原理也不复杂,它先在web.xml中配置一个Servlet,映射到特定的路径(通常是%CONTEXT_PATH%/dwr/*)。这个Servlet的作用就是初始化要暴露给Javascript调用的Java类(通过dwr.xml进行配置),并生成相应的代理的Javascript类代码。在XHR请求到来的时候,Servlet负责将请求的参数变成对应的Java对象,并以其为参数调用目标Java方法,并将返回值转化为Javascript代码。详情请参考:http://getahead.ltd.uk/dwr/

    Struts 2与DWR

    在Struts 2.0.x中使用DWR实现AJAX表单校验。在大家掌握了DWR的原理后,下面我想详细介绍一下实现的步骤。

    首先,到以下站点https://dwr.dev.java.net/files/documents/2427/47455/dwr.jar下载DWR的1.1.4版本的JAR包。需要注意的是,DWR虽然已经发布2.0版本,但它与1.1.4有很大的区别,所以请大家不要使用2.0版本,否则会出现异常的;

    接着,新建WEB工程,将下图所示的JAR包加入到工程的“Build Path”中;

    依赖的JAR包
    图2 依赖的JAR包

    接下来,配置web.xml文件,内容如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app id="WebApp_9" version="2.4"
        xmlns
    ="http://java.sun.com/xml/ns/j2ee"
        xmlns:xsi
    ="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation
    ="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

       
    <display-name>Struts 2 AJAX Part 3</display-name>

       
    <filter>
           
    <filter-name>struts-cleanup</filter-name>
           
    <filter-class>
                org.apache.struts2.dispatcher.ActionContextCleanUp
           
    </filter-class>
       
    </filter>

       
    <filter-mapping>
           
    <filter-name>struts-cleanup</filter-name>
           
    <url-pattern>/*</url-pattern>
       
    </filter-mapping>

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

       
    <filter-mapping>
           
    <filter-name>struts2</filter-name>
           
    <url-pattern>/*</url-pattern>
       
    </filter-mapping>
       
    <!-- 开始DWR配置 -->
       
    <servlet>
           
    <servlet-name>dwr</servlet-name>
           
    <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
           
    <init-param>
               
    <param-name>debug</param-name>
               
    <param-value>true</param-value>
           
    </init-param>
       
    </servlet>

       
    <servlet-mapping>
           
    <servlet-name>dwr</servlet-name>
           
    <url-pattern>/dwr/*</url-pattern>
       
    </servlet-mapping>
       
    <!-- 结束DWR配置 -->
       
    <welcome-file-list>
           
    <welcome-file>index.html</welcome-file>
       
    </welcome-file-list>

    </web-app>
    清单1 WebContent/WEB-INF/web.xml

    然后是DWR的配置文件:

    <?xml version="1.0" encoding="UTF-8"?>

    <!-- START SNIPPET: dwr -->
    <!DOCTYPE dwr PUBLIC 
        "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN" 
        "http://www.getahead.ltd.uk/dwr/dwr10.dtd"
    >

    <dwr>
       
    <allow>
           
    <create creator="new" javascript="validator">
               
    <param name="class" value="org.apache.struts2.validators.DWRValidator"/>
           
    </create>
           
    <convert converter="bean" match="com.opensymphony.xwork2.ValidationAwareSupport"/>
       
    </allow>

       
    <signatures>
           
    <![CDATA[
            import java.util.Map;
            import org.apache.struts2.validators.DWRValidator;

            DWRValidator.doPost(String, String, Map<String, String>);
           
    ]]>
       
    </signatures>
    </dwr>
    <!-- END SNIPPET: dwr -->
    清单2 WebContent/WEB-INF/dwr.xml

    通过以上配置,我们可以将DWRValidator中的方法暴露为Javascript可以调用的远程接口。

    在正确完成以上步骤之后,我们发布运行一下应用程序,在浏览器地址栏中输入http://localhost:8080/Struts2_Ajax3/dwr/,应该会出现如下页面:

    DWR Servlet默认输出页面
    图3 DWR Servlet默认输出页面

     接下来,我们要开始编写Action类了,代码如下:

    package tutorial;

    import com.opensymphony.xwork2.ActionSupport;

    public class AjaxValidation extends ActionSupport {
       
    private static final long serialVersionUID = -7901311649275887920L;

       
    private String name;
       
    private String password;
       
    private int age;
       
       
    public int getAge() {
           
    return age;
       }

       
       
    public void setAge(int age) {
           
    this.age = age;
       }

       
       
    public String getName() {
           
    return name;
       }

       
       
    public void setName(String name) {
           
    this.name = name;
       }

       
       
    public String getPassword() {
           
    return password;
       }

       
       
    public void setPassword(String password) {
           
    this.password = password;
       }

       
       @Override
       
    public String execute() {        
           
    return SUCCESS;
       }

    }
    清单3 src/tutorial/AjaxValidation.java

    上述代码一目了然,相信大家已经很熟悉了。下面,我们再来看看表单校验的配置代码:

    <!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN" "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
    <validators>
       
    <validator type="regex">
           
    <param name="fieldName">password</param>
           
    <param name="expression">
               
    <![CDATA[(?!^[0-9]*$)(?!^[a-zA-Z]*$)^([a-zA-Z0-9]{8,10})$]]>
           
    </param>
           
    <message>Password must be between 8 and 10 characters, contain at least one digit and one alphabetic character, and must not contain special characters</message>
       
    </validator>    
       
    <field name="name">
           
    <field-validator type="requiredstring">
               
    <message>You must enter a name</message>
           
    </field-validator>
       
    </field>
       
    <field name="age">
           
    <field-validator type="int">
               
    <param name="min">18</param>
               
    <param name="max">127</param>
               
    <message>Age must be between 18 and 127</message>
           
    </field-validator>
       
    </field>
    </validators>
    清单4 src/tutorial/AjaxValidation-validation.xml

    对于AjaxValidation类的name、password和age三个字段,我分别用了非空、正规表达式和范围验证。正规表达式(?!^[0-9]*$)(?!^[a-zA-Z]*$)^([a-zA-Z0-9]{8,10})$的作用是保证密码由至少包括一个数字和一个字母,且不能含有符号的长度为8到10的字符串组成。它也是所谓强密码(Strong Password)的普通实现。

    接下来的是JSP的代码,内容如下:

    <%@ page language="java" contentType="text/html; charset=utf-8"
        pageEncoding
    ="utf-8"%>
    <%@ taglib prefix="s" uri="/struts-tags"%>

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
       
    <head>
           
    <title>Struts 2 AJAX - Validation</title>
           
    <s:head theme="ajax" />
       
    </head>
       
    <body>
           
    <h2>
                AJAX Validation Using DWR
           
    </h2>
           
    <s:form method="post" validate="true" theme="ajax">
               
    <s:textfield label="Name" name="name" />
               
    <s:password label="Password" name="password" />
               
    <s:textfield label="Age" name="age" />
               
    <s:submit />
           
    </s:form>
       
    </body>
    </html>
    清单5 WebContent/AjaxValidation.jsp

    以上代码也不复杂,不过需要的是注意的是除了要加入<s:head theme="ajax" />外,<s:form />也必须加入validate="true" theme="ajax"的属性。

    最后是Struts 2的配置文件,内容如下所示:

    <?xml version="1.0" encoding="UTF-8"?>

    <!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
        "http://struts.apache.org/dtds/struts-2.0.dtd"
    >

    <struts>
       
    <package name="Struts2_AJAX_DEMO" extends="struts-default">
           
    <action name="AjaxValidation" class="tutorial.AjaxValidation">
               
    <result name="input">AjaxValidation.jsp</result>
               
    <result>AjaxValidation.jsp</result>
           
    </action>
       
    </package>
    </struts>
    清单6 src/struts.xml

    最后发布运应用程序,在浏览器地址栏中输入http://localhost:8080/Struts2_Ajax3/AjaxValidation!input.action出现如下图所示页面:

    AjaxValidation页面输出
    图4 AjaxValidation页面输出

    在文本框中输入错误的值使页面出现错误提示信息,如下图所示:

    AjaxValidation页面错误提示
    图5 AjaxValidation页面错误提示

    可能有朋友会问怎么知道这是通过AJAX进行校验的呢?在这里我向大家推荐一个AJAX开发必备的工具——Firebug。Firebug是Firefox的一个功能强大的插件,它可以准确地输出和定位Javascript的错误、通过直观的方式查看HTML文档的DOM及其样式、所见即所得的编辑方式,更值得一赞的是它可以方便地对Javascript进行跟踪和调试,如果你希望这进一步了解这个工具,请安装Firefox 2.0以上版本,并使用它浏览以下网址http://www.getfirebug.com

    在安装完成Firebug之后,在Firefox中打开http://localhost:8080/Struts2_Ajax3/AjaxValidation!input.action,按“F12”键找开Firebug窗口,如果你第一次使用Firebug,请点击其窗口中的链接“Enable Firebug”激活插件。之后,点击“Net”,并在出现的菜单中点击选中“XHR”。然后将光标移入文本框,再将光标移出使文本框失去焦点,你可以看到Firebug窗口会多出一项记录,如下图所示:

    Firebug中查看XHR请求
    图6 Firebug中查看XHR请求

    这就证明你在文本框失去焦出时,Struts 2会发送XHR请求到服务器以对该文本框值进行校验。有兴趣的朋友可以通过Firebug,研究XHR的请求与响应,这样可以加深对DWR工作原理的理解。

    何时使用AJAX表单校验

    虽然在Struts 2实现AJAX表单校验是一件非常简单的事,但我建议大家不要在所有的场合都使用这个功能,原因可以分为以下几个方面:

    1. AJAX校验在服务器上进行数据校验,可能会比较耗时;
    2. AJAX校验可能会过于频繁,加重服务器的负载;
    3. 一些普通的校验,只需要使用纯Javascript便可以实现。

    读到这里,有的朋友可能会问:“那么什么时候才应该使用AJAX表单校验呢?”答案其实很简单,当我们的校验在页面加载时还不能够确定的情况下,就应该使用这个功能。例如,注册用户时,校验用户名是否已经存在;或者校验涉及过多的页务逻辑等。

    现在让我们来改造一下上述例子,对于name我们可以使用AJAX校验,但对于其它的字段应该使用纯Javascript的校验。

    在tutorial.AjaxValidation类加入如下方法:

       @Override
       
    public void validate() {
           Set
    <String> users = new HashSet<String>();
           users.add(
    "max");
           users.add(
    "scott");
           
    if(users.contains(name)) {
               addFieldError(
    "name", "The user name has been used!");
           }

       }
    清单7 src/tutorial/AjaxValidation.java代码片段

    用于模拟用户注册的场境,当然在真实情况应该在数据库中检查用户是否存在。

    接下来再修改JSP文件,将<s:form />里面的内容改为如下所示代码:

            <s:form method="post" validate="true" theme="ajax_xhtml">
               
    <s:textfield label="Name" name="name" theme="ajax" />
               
    <s:password label="Password" name="password" theme="xhtml" />
               
    <s:textfield label="Age" name="age" theme="xhtml" />
               
    <s:submit theme="xhtml" />
           
    </s:form>
    清单8 WebContent/AjaxValidation.jsp代码片段

    对比早前的JSP代码,大家可以看出我将<s:form />的theme改成了“ajax_xhtml”,这个theme不是Struts 2自带,需要自定义。另外,除了Name使用了ajax的theme之外,其它的表单标签的theme都为xhtml,如此一来便可以实现只有当Name文本框失去焦点时才发生AJAX表单校验。

    接下来,应该是我们的自定义ajax_xhtml的theme了。在源代码文件夹下新建包“template.ajax_xhtml”,然后在其中加入form.ftl和form-close.ftl文件,内容分别如下:

    <#if parameters.validate?exists>
    <script type="text/javascript" src="${base}/struts/validationClient.js"></script>
    <script type="text/javascript" src="${base}/dwr/interface/validator.js"></script>
    <script type="text/javascript" src="${base}/dwr/engine.js"></script>
    <script type="text/javascript" src="${base}/struts/ajax/validation.js"></script>
    </#if>
    <#include "/${parameters.templateDir}/xhtml/form-validate.ftl" />
    <#include "/${parameters.templateDir}/simple/form.ftl" />
    <#include "/${parameters.templateDir}/xhtml/control.ftl" />
    清单9 src/template/ajax_xhtml/form.ftl

    上述的文件与xhtml theme中的form.ftl文件相似,我只是加入了AJAX表单校验所用的Javascript库,以便theme为ajax的表单标签使用。

    <#include "/${parameters.templateDir}/xhtml/control-close.ftl" />
    <#include "/${parameters.templateDir}/simple/form-close.ftl" />
    <#include "/${parameters.templateDir}/xhtml/form-close-validate.ftl" />
    清单10 src/template/ajax_xhtml/form-close.ftl

    这个文件与xhtml theme中的form-close.ftl文件相同。

    最后发布运行应用程序,大家可以发现在Password与Age的校验,只有在表单提交时才发生,而且是纯Javascript的校验。不过,以上代码还不是很完善,在行为上有些BUG。

    总结

    Struts 2相比一些其它的框架,在实现AJAX方面的确简单很多。更激动人心的是Struts 2的标签库支持基于模板的输出,使得开发者可以跟据自身的需要方便地改变标签的行为。

    在将要发布的Struts 2.1版本中,AJAX表单校验将不再使用DWR,统一使用DOJO实现,详情请参考:http://struts.apache.org/2.0.9/docs/ajax-validation.html

  • 相关阅读:
    Watir: 当出现错误提示AutoItX3.dll 没有注册的时候,该怎么处理?
    Watir 能够为你做什么?
    第三章:JMeter 常用的测试元件——线程组
    第二章:JMeter 目录结构分析
    第二章:JMeter 工作原理
    第二章:JMeter 测试结果的名词解释
    第二章:JMeter 中常见 的术语
    第二章:JMeter 的介绍
    第一章:性能测试的常见指标
    第一章:性能测试的常见分类
  • 原文地址:https://www.cnblogs.com/myssh/p/1390906.html
Copyright © 2020-2023  润新知