零基础学Struts
上QQ阅读APP看书,第一时间看更新

10.3 Struts 2整合Ajax开发

图10.8 登录失败

由于Ajax技术的广泛应用,从而发展起来了许多的Ajax框架,基于这些框架能够更轻松和方便地开发出Ajax应用。其中DWR框架是其中比较流行的一个Ajax框架,而它最大的优势就是可以像使用本地的JavaScript函数一样,调用服务器上的Java方法。

10.3.1 基于DWR开发Ajax应用

首先从DWR的官方网站http://getahead.ltd.uk/dwr下载DWR框架,这里选择1.1.4版本下载。安装DWR非常简单,只需将下载的“dwr.jar”复制到Web应用的WEB-INF\lib目录下即可。

为了让DWR的核心Servlet起作用,所以还必须在“web.xml”文件中配置该核心Servlet,代码如下所示。

        <servlet>
              <servlet-name>dwr-invoker</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-invoker</servlet-name>
                <url-pattern>/dwr/*</url-pattern>
          </servlet-mapping>

新建业务逻辑组件RegistCheck,该类提供isRegist方法来判断用户名是否被占用,如果被占用则返回“用户名已被占用,请重新输入”字符串;如果没有被占用则返回“该用户名可以使用”字符串,代码如下所示。

          package net.hncu.service;
          import java.util.HashSet;
          import java.util.Set;
          public class RegistCheck {
                public String isRegist(String username){
                    Set<String> users = new HashSet<String>();
                    users.add("xiaoqiang");
                    if(users.contains(username)) {
                      return "用户名已被占用,请重新输入";
                    }else {
                      return "该用户名可以使用";
                    }
              }
          }

为了使得JavaScript能够调用该业务逻辑组件中的isRegist方法,需要在WEB-INF目录下添加“dwr.xml”配置文件,并在该配置文件中配置被暴露的Java方法,代码如下所示。

          <? xml version="1.0" encoding="UTF-8"? >
          <! 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="checkUser">
                          <param name="class" value="net.hncu.service.RegistCheck" />
                    </create>
              </allow>
          </dwr>

新建注册页面,该页面包含一个注册表单。通过单击“用户名是否占用”按钮能触发JavaScript中的check()函数,通过该函数调用服务器端的isRegist方法,并通过DIV标签显示该方法的返回值信息,代码如下所示。

    <%@ page language="java" import="java.util.*" pageEncoding="gb2312"%>
    <! DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
          <head>
              <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
              <title>用户注册</title>
              <script type=' text/javascript' src=' dwr/interface/checkUser.js' ></script>
              <script type=' text/javascript' src=' dwr/engine.js' ></script>
              <script type=' text/javascript' src=' dwr/util.js' ></script>
              <script type="text/javascript">
              function check() {
                var username = document.getElementById(' username' ).value;
                checkUser.isRegist(username, callback);
                }
                function callback(msg) {
                      DWRUtil.setValue(' result' , msg);
                }
              </script>
          </head>
          <body>
              <! -- 显示用户名是否占用信息 -->
              <div id="result" style="color: red"></div>
              <! -- 注册表单 -->
              <form action="aa" method="post"">
              <table>
                    <tr>
                          <td>用户名:</td>
                          <td><input   id="username" type="text" name="username"></td>
                          <td><input type="button" value="用户名是否占用" onclick=' check(); ' /></td>
                    </tr>
                    <tr>
                          <td>密码:</td>
                          <td><input type="password" name="password"></td>
                    </tr>
                    <tr>
                          <td>确认密码:</td>
                          <td> <input type="password" name="repassword"></td>
                    </tr>
                    <tr>
                          <td>年龄: </td>
                          <td><input type="text" name="age"></td>
                    </tr>
                    <tr>
                          <td>出生日期: </td>
                          <td><input type="text" name="birth"></td>
                    </tr>
                    <tr>
                                  <td>邮箱地址:</td>
                                  <td><input type="text" name="email"></td>
                            </tr>
                            <tr>
                                  <td></td>
                                  <td><input type="submit" value="提交">
                                      <input type="reset" value="重置">
                                  </td>
                            </tr>
                      </table>
                      </form>
                </body>
            </html>

运行注册页面,随意输入一个用户名,单击“用户名是否占用”按钮,页面提示该用户名可以使用的提示信息,如图10.9所示。

输入用户名“xiaoqiang”,因为该用户已经存在,单击“用户名是否占用”按钮,所以页面提示用户名已被占用,请重新输入的提示信息,如图10.10所示。

图10.9 用户注册页(1)

图10.10 用户注册页(2)

10.3.2 在Struts 2中实现Ajax表单校验

Struts 2的Ajax表单校验是基于DWR和Dojo两个框架之上的,其中DWR负责实现在JavaScript代码中调用Java方法,而Dojo负责实现页面显示效果。Struts 2对于这两个框架的封装非常好了,因此只需通过少量的配置就能实现Ajax表单校验。

首先同前面介绍的一样,需要在Web应用中加入“dwr.jar”文件。然后在“web.xml”文件中配置DWR的核心Servlet。

配置完核心Servlet后,需要新增“dwr.xml”配置文件,并在该配置文件中添加配置代码,使得DWRValidator中的方法暴露为Javascript可以调用的远程接口。这份代码是非常固定的,基本上无需修改,代码如下所示。

        <? 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>

新建注册页面,该注册页面仅仅包含一个注册表单。设置该表单的主题为Ajax主题,并设置validate属性值为true,代码如下所示。

        <%@ page language="java" import="java.util.*" pageEncoding="gb2312"%>
        <%@ taglib prefix="s" uri="/struts-tags" %>
        <! DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
        <html>
          <head>
            <title>注册页面</title>
            <s:head theme="ajax"/>
          </head>
          <body>
            <! -- 注册表单 -->
            <center>
            <h2>注册页面</h2>
            <s:form action="register" validate="true" theme="ajax">
                    <s:textfield name="username" label="用户名"></s:textfield>
                    <s:password name="password" label="密码"></s:password>
                    <s:password name="repassword" label="确认密码"></s:password>
                    <s:submit value="注册"></s:submit>
            </s:form>
            </center>
          </body>
        </html>

接下来新建业务控制器RegisterAction,设置同注册表单相对应的属性,并添加其setter和getter方法,代码如下所示。

        package net.hncu.action;
        import java.util.Calendar;
        import java.util.Date;
        import java.util.regex.Pattern;
        import com.opensymphony.xwork2.ActionSupport;
        public class RegisterAction extends ActionSupport{
              private String username;
              private String password;
              private String repassword;
              public String getUsername() {
                    return username;
              }
              public void setUsername(String username) {
                    this.username = username;
              }
              public String getPassword() {
                    return password;
              }
              public void setPassword(String password) {
                    this.password = password;
              }
              public String getRepassword() {
                    return repassword;
              }
              public void setRepassword(String repassword) {
                    this.repassword = repassword;
              }
              public String execute() throws Exception {
                    return SUCCESS;
              }
        }

在“struts.xml”文件中配置该业务控制器RegisterAction,并定义处理结果与视图资源之间的关系,代码如下所示。

        <? 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为配置文件根元素-->
        <struts>
              <package name="struts2" extends="struts-default">
                    <! -- 定义registerAction,其实现类为net.hncu.action.RegisterAction-->
                    <action name="register" class="net.hncu.action.RegisterAction">
                        <! -- 定义处理结果与视图资源之间的关系-->
                        <result name="success">/result.jsp</result>
                        <result name="input">/register.jsp</result>
                    </action>
              </package>
          </struts>

添加校验规则文件,这里使用非字段校验器风格来配置校验规则,当然也可以使用字段风格来配置,代码如下所示。

        <? xml version="1.0" encoding="UTF-8"? >
        <! 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="requiredstring">
                    <param name="fieldName">username</param>
                    <param name="trim">true</param>
                    <message>必须输入用户名</message>
              </validator>
              <validator type="regex">
                    <param name="fieldName">username</param>
                    <param name="expression"><! [CDATA[(\w{6,20})]]></param>
                    <message>用户名长度必须为620之间</message>
              </validator>
              <validator type="requiredstring">
                    <param name="fieldName">password</param>
                    <param name="trim">true</param>
                    <message>必须输入密码</message>
              </validator>
              <validator type="regex">
                    <param name="fieldName">password</param>
                    <param name="expression"><! [CDATA[(\w{6,20})]]></param>
                    <message>密码长度必须为620之间</message>
              </validator>
              <validator type="requiredstring">
                    <param name="fieldName">repassword</param>
                    <param name="trim">true</param>
                    <message>必须输入确认密码</message>
              </validator>
              <validator type="regex">
                    <param name="fieldName">repassword</param>
                    <param name="expression"><! [CDATA[(\w{6,20})]]></param>
                    <message>确认密码长度必须为620之间</message>
              </validator>
              <validator type="fieldexpression">
                    <param name="fieldName">repassword</param>
                    <param name="expression"><! [CDATA[(repassword==password)]]></param>
                    <message>密码和确认密码必须一致</message>
              </validator>
        </validators>

运行注册页面,当不输入任何用户信息,直接单击“注册”按钮进行注册时,页面将提示错误信息,如图10.11所示。

这和客户端校验有什么区别吗?下面重点观察错误提示信息的输出。首先输入不符合长度的用户名信息,当将光标移出该文本框时,可以看出错误提示立即出现了,如图10.12所示。

图10.11 用户提示错误信息(1)

图10.12 用户提示错误信息(2)

Struts 2的Ajax表单校验,是采用异步的方式提交表单请求。和传统的Web应用不同的是,当前页面不会提交,提交的只是部分数据。用户可能根本就感觉不到这种提交,在提交的过程中依然可以进行其他的操作,而当服务器返回信息时,Struts 2会自动加载这些信息并显示给用户。