Struts2框架学习第二章——Struts2下的HelloWorld

本章要点html

—  Struts 2的下载和安装java

— 纯手工建立一个Web应用程序员

— 纯手工建立一个Struts 2应用web

— 实现Struts 2的Action数据库

— 配置Struts 2的Actionapache

— 在Action中访问HttpSession编程

— 在JSP中输出Action的返回值数组

— 使用Struts 2的表单标签浏览器

— 程序国际化初步服务器

— 数据校验初步

前面已经简要介绍了Struts 2的起源,以及Struts 2的两个前身:Struts 1和WebWork,并详细对比了Struts 2和Struts 1的差别,对比了Struts 2和WebWork的差别,并且指出:Struts 2是WebWork的升级,而不是Struts 1的升级。

虽然Struts 2提供了与Struts 1的兼容,但已经不是Struts 1的升级。对于已有Struts 1开发经验的开发者而言,Struts 1的开发经验对于Struts 2并无太大的帮助;相反,对于已经有WebWork开发经验的开发者而言,WebWork的开发经验对Struts 2的开发将有很好的借鉴意义。

下面将以一个Struts 2的HelloWorld应用为例,介绍Strust 2 MVC框架如何拦截用户请求,如何调用业务控制器处理用户请求,并介绍Action处理结果和资源之间的映射关系。

本HelloWorld应用是一个简单的应用:用户进入一个登陆页面,容许用户输入用户名、密码,若是用户输入的用户名和密码符合要求,则进入一个欢迎页面;若是用户输入错误,则进入一个提示页面。当用户提交表单时,本应用会有基本的数据校验。

2.1  下载和安装Struts 2框架

下面咱们从下载、安装Struts 2开始,慢慢开始体验Struts 2 MVC框架的魅力。

笔者写本书的时候,Struts 2已经发布了其产品化GA(General Availability)版,其实最新的产品化GA版是Struts 2.06,故本书的全部应用都是基于该版本的Struts 2。建议读者下载Struts 2.06版,而不是下载最新的Beta版,若是Struts 2有最新的GA版,读者也能够下载更新的GA版,相信不会有太大差别。

下载和安装DWR请按以下步骤进行。

 登陆http://struts.apache.org/download.cgi#Struts206站点,下载Struts 2的最新GA版。在Struts 2.06下有以下几个选项:

—  Full Distribution:下载Struts 2的完整版。一般建议下载该选项。

—  Example Applications:下载Struts 2的示例应用,这些示例应用对于学习Struts 2有很大的帮助,下载Struts 2的完整版时已经包含了该选项下所有应用。

—  Blank Application only:仅下载Struts 2的空示例应用,这个空应用已经包含在Example Applications选项下。

—  Essential Dependencies:仅仅下载Struts 2的核心库,下载Struts 2的完整版时将包括该选项下的所有内容。

—  Documentation:仅仅下载Struts 2的相关文档,包含Struts 2的使用文档、参考手册和API文档等。下载Struts 2的完整版时将包括该选项下的所有内容。

—  Source:下载Struts 2的所有源代码,下载Struts 2的完整版时将包括该选项下的所有内容。

—  Alternative Java 4 JARs:下载可选的JDK 1.4的支持JAR。下载Struts 2的完整版时将包括该选项下的所有内容。

一般建议读者下载第一个选项:下载Struts 2的完整版,将下载到的Zip文件解压缩,该文件就是一个典型的Web结构,该文件夹包含以下文件结构:

—  apps:该文件夹下包含了基于Struts 2的示例应用,这些示例应用对于学习者是很是有用的资料。

—  docs:该文件夹下包含了Struts 2的相关文档,包括Struts 2的快速入门、Struts 2的文档,以及API文档等内容。

—  j4:该文件夹下包含了让Struts 2支持JDK 1.4的JAR文件。

—  lib:该文件夹下包含了Struts 2框架的核心类库,以及Struts 2的第三方插件类库。

—  src:该文件夹下包含了Struts 2框架的所有源代码。

 将lib文件夹下的Struts2-core-2.0.6.jar、xwork-2.0.1.jar和ognl-2.6.11.jar等必需类库复制到Web应用的WEB-INF/lib路径下。固然,若是你的Web应用须要使用Struts 2的更多特性,则须要将更多的JAR文件复制到Web应用的WEB-INF/lib路径下。若是须要在DOS或者Shell窗口下手动编译Struts 2相关的程序,则还应该将Struts2-core-2.0.6.jar和xwork-2.0.1.jar添加到系统的CLASSPATH环境变量里。

 提示  大部分时候,使用Struts 2的Web应用并不须要利用到Struts 2的所有特性,所以没有必要一次将该lib路径下JAR文件所有复制到Web应用的WEB-INF/lib路径下。

 编辑Web应用的web.xml配置文件,配置Struts 2的核心Filter。下面是增长了Struts 2的核心Filter配置的web.xml配置文件的代码:

<?xml version="1.0" encoding="GBK"?>

<!-- web-app是Web应用配置文件的根元素,指定Web应用的Schema信息 -->

<web-app 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">

                                 <!-- 定义Struts 2的FilterDispatcher的Filter -->

                                  <filter>

                                    <!-- 定义核心Filter的名字 -->

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

                                    <!-- 定义核心Filter的实现类 -->

                                  <filter-class>org.apache.Struts2.dispatcher.FilterDispatcher

                                        </ filter-class>

                                  </filter>

                                 <!-- FilterDispatcher用来初始化Struts 2而且处理全部的Web请求 -->

                                  <filter-mapping>

                                  <filter-name>Struts2</filter-name>

                                  <url-pattern>/*</url-pattern>

                                  </filter-mapping>

</web-app>

通过上面3个步骤,咱们已经能够在一个Web应用中使用Struts 2的基本功能了,下面将带领读者进入Struts 2 MVC框架的世界。

2.2  从用户请求开始

Struts 2支持大部分视图技术,固然也支持最传统的JSP视图技术,本应用将使用最基本的视图技术:JSP技术。当用户须要登陆本系统时,用户须要一个简单的表单提交页面,这个表单提交页面包含了两个表单域:用户名和密码。

下面是一个最简单的表单提交页面,该页面的表单内仅包含两个表单域,甚至没有任何动态内容,实际上,整个页面彻底能够是一个静态HTML页面。但考虑到须要在该页面后面增长动态内容,所以依然将该页面以jsp为后缀保存。下面是用户请求登陆的JSP页面代码:

<%@ page language="java" contentType="text/html; charset=GBK"%>

<html>

<head>

<title>登陆页面</title>

</head>

<body>

<!-- 提交请求参数的表单 -->

<form action="Login.action" method="post">

                                  <table align="center">

                                  <caption><h3>用户登陆</h3></caption>

                                  <tr>

                                        <!-- 用户名的表单域 -->

                                   <td>用户名:<input type="text" name="username"/></td>

                                  </tr>

                                  <tr>

                                        <!-- 密码的表单域 -->

                                   <td>密&nbsp;&nbsp;码:<input type="text" name="password"/></td>

                                  </tr>

                                  <tr align="center">

                                   <td colspan="2"><input type="submit" value="登陆"/><input

                                            type="reset" value="重填" /></td>

                                  </tr>

                                  </table>

</form>

</body>

</html>

正如前面介绍的,该页面没有包含任何的动态内容,彻底是一个静态的HTML页面。但咱们注意到该表单的action属性:login.action,这个action属性比较特殊,它不是一个普通的Servlet,也不是一个动态JSP页面。可能读者已经猜到了,当表单提交给login.action时,Struts 2的FilterDispatcher将自动起做用,将用户请求转发到对应的Struts 2 Action。

 注意  Struts 2 Action默认拦截全部后缀为.action的请求。所以,若是咱们须要将某个表单提交给Struts 2 Action处理,则应该将该表单的action属性设置为*.action的格式。

该页面就是一个基本的HTML页面,在浏览器中浏览该页面,看到如图2.1所示的界面。

整个页面就是一个标准的HTML页面,整个单独的页面尚未任何与用户交互的能力。下面咱们开始动手建立一个Struts 2的Web应用。

2.3  建立Struts 2Web应用

Struts 2的Web应用就是一个普通的Web应用,而后增长Struts 2功能,该应用就能够充分利用Struts 2的MVC框架了。

2.3.1  建立Web应用

笔者一直相信:要想成为一个优秀的程序员,应该从基本功练起,全部的代码都应该用简单的文本编辑器(包括EditPlus、UtraEdit等工具)完成。笔者常常见到一些有两三年开发经验的程序员,一旦离开了熟悉的IDE(集成开发环境,如Eclipse、JBuilder等),彻底不能动手写任何代码。而他们每每还振振有词:谁会不用任何工具来开发?

实际上,真正优秀的程序员固然可使用IDE工具,但即便使用VI(UNIX下无格式编辑器)、记事本也同样能够完成很是优秀的项目。笔者对于IDE工具的态度是:可使用IDE工具,但毫不可依赖于IDE工具。学习阶段,千万不要使用IDE工具;开发阶段,才去使用IDE工具。

 提醒  对于IDE工具,业内有一个说法:IDE工具会加快高手的开发效率,但会使初学者更白痴。

为了让读者更加清楚Struts 2应用的核心,笔者下面将“徒手”创建一个Struts 2应用。

创建一个Web应用请按以下步骤进行。

 在任意目录新建一个文件夹,笔者将以该文件夹创建一个Web应用。

 在第1步所建的文件夹内建一个WEB-INF文件夹。

 进入Tomcat,或任何Web容器内,找到任何一个Web应用,将Web应用的WEB-INF下的web.xml文件复制到第2步所建的WEB-INF文件夹下。

 修改复制的web.xml文件,将该文件修改为只有一个根元素的XML文件,修改后的web.xml文件代码以下:

<?xml version="1.0" encoding="GBK"?>

<!-- web-app是Web应用配置文件的根元素,指定Web应用的Schema信息 -->

<web-app 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">

</web-app>

 在第2步所建的WEB-INF路径下,新建两个文件夹:classes和lib,它们分别用于保存单个*.class文件和JAR文件。

通过上面步骤,已经创建了一个空Web应用。将该Web应用复制到Tomcat的webapps路径下,该Web应用将能够自动部署在Tomcat中。

将2.2节所定义的JSP页面文件复制到第1步所建的文件夹下,该JSP页面将成为该Web应用的一个页面。该Web将有以下文件结构:

Struts2qs

|-WEB-INF

|     |-classes

|     |-lib

|     |-web.xml

|-login.jsp

上面的Struts2qs是Web应用所对应文件夹的名字,能够更改;login.jsp是该Web应用下JSP页面的名字,也能够修改。其余文件夹、配置文件都不能够修改。

启动Tomcat,在浏览器中浏览2.2节定义的JSP页面,将看到如图2.1所示的页面。

2.3.2  增长Struts 2功能

为了给Web应用增长Struts 2功能,只须要将Struts 2安装到Web应用中便可。在Web应用中安装Struts 2框架核心只须要通过以下三个步骤。

 修改web.xml文件,在web.xml文件中配置Struts 2的核心Filter。

 将Struts 2框架的类库复制到Web应用的WEB-INF/lib路径下。

 在WEB-INF/classes下增长struts.xml配置文件。

下面是增长了Struts 2功能后Web应用的文件结构:

Struts2qs

|-WEB-INF

|     |-classes(struts.xml)

|     |-lib(commons-logging.jar,freemarker.jar,ognl.jar,struts2-core.jar,xwork.jar)

|     |-web.xml

|-login.jsp

在上面的文件结构中,lib下Struts 2框架的类库可能有版本后缀。例如commons-logging.jar,多是commons-logging-1.1.jar;struts2-core.jar多是struts2-core-2.0.6.jar。

修改后的web.xml文件在2.1节已经给出了,故此处再也不赘述。

此处须要给读者指出的是,Struts 2的Web应用默认须要Java 5运行环境,须要Web容器支持Servlet API 2.4和JSP API 2.0。若是读者须要使用更低版本的Java运行时环境,则须要使用Struts 2框架的JDK 1.4支持。为了简单起见,笔者建议读者使用Java 5运行时环境,使用Tomcat 5.5或者更高版本。

 注意  Struts 2应用默认须要Java 5运行时环境,须要支持Servlet API 2.4和JSP API 2.0的Web容器。

2.4  实现控制器

前面介绍MVC框架时,已经指出:MVC框架的核心就是控制器。当用户经过2.2节的页面提交用户请求时,该请求须要提交给Struts 2的控制器处理。Struts 2的控制器根据处理结果,决定将哪一个页面呈现给客户端。

2.4.1  实现控制器类

Struts 2下的控制器再也不像Struts 1下的控制器,须要继承一个Action父类,甚至能够无需实现任何接口,Struts 2的控制器就是一个普通的POJO。

实际上,Struts 2的Action就是一个包含execute方法的普通Java类,该类里包含的多个属性用于封装用户的请求参数。下面是处理用户请求的Action类的代码:

//Struts 2的Action类就是一个普通的Java类

public class LoginAction

{

                                 //下面是Action内用于封装用户请求参数的两个属性

                                  private String username;

                                  private String password;

                                  //username属性对应的getter方法

                                  public String getUsername()

                                 {

                                  return username;

                                  }

                                 //username属性对应的setter方法

                                  public void setUsername(String username)

                                  {

                                  this.username = username;

                                  }

                                  //password属性对应的getter方法

                                  public String getPassword()

                                 {

                                  return password;

                                  }

                                 //password属性对应的setter方法

                                  public void setPassword(String password)

                                 {

                                  this.password = password;

                                  }

                                 //处理用户请求的execute方法

                                 public String execute() throws Exception

                                 {

                                    //当用户请求参数的username等于scott,密码请求参数为tiger时,返回success

                                      字符串

                                    //不然返回error字符串

                                  if (getUsername().equals("scott")

                                        && getPassword().equals("tiger") )

                                    {

                                   return "success";

                                  }

                                    else

                                    {

                                   return "error";

                                  }

                                  }

}

上面的Action类是一个再普通不过的Java类,该类里定义了两个属性:username和password,并为这两个属性提供了对应的setter和getter方法。除此以外,该Action类里还包含了一个无参数的execute方法——这大概也是Action类与POJO惟一的差异。实际上,这个execute方法依然是一个很普通的方法,既没有与Servlet API耦合,也没有与Struts 2 API耦合。

 提示  表面上看起来,该Action的两个属性只提供了对应的setter和getter方法,很难理解请求参数在何时赋值给该Action的属性,事实上,由于Struts 2的拦截器机制,它们负责解析用户的请求参数,并将请求参数赋值给Action对应的属性。

2.4.2  配置Action

上面定义了Struts 2的Action,但该Action还未配置在Web应用中,还不能处理用户请求。为了让该Action能处理用户请求,还须要将该Action配置在struts.xml文件中。

前面已经介绍过了,struts.xml文件应该放在classes路径下,该文件主要放置Struts 2的Action定义。定义Struts 2 Action时,除了须要指定该Action的实现类外,还须要定义Action处理结果和资源之间的映射关系。下面是该应用的struts.xml文件的代码:

<?xml version="1.0" encoding="GBK"?>

<!-- 指定Struts 2配置文件的DTD信息 -->

<!DOCTYPE struts PUBLIC

        "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"

        "http://struts.apache.org/dtds/struts-2.0.dtd">

<!-- struts是Struts 2配置文件的根元素 -->

<struts>

                                 <!-- Struts 2的Action必须放在指定的包空间下定义 -->

                                 <package name="strutsqs" extends="struts-default">

                                    <!-- 定义login的Action,该Action的实现类为lee.Action类 -->

                                  <action name="Login" class="lee.LoginAction">

                                        <!-- 定义处理结果和资源之间映射关系。 -->

                                   <result name="error">/error.jsp</result>

                                   <result name="success">/welcome.jsp</result>       

                                  </action>

                                  </package>

</struts>

上面映射文件定义了name为login的Action,即:该Action将负责处理向login.action URL请求的客户端请求。该Action将调用自身的execute方法处理用户请求,若是execute方法返回success字符串,请求将被转发到/welcome.jsp页面;若是execute方法返回error字符串,则请求被转发到/error.jsp页面。

2.4.3  增长视图资源完成应用

通过上面步骤,这个最简单的Struts 2应用几乎能够运行了,但还须要为该Web应用增长两个JSP文件,两个JSP文件分别是error.jsp页面和welcome.jsp页面,将这两个JSP页面文件放在Web应用的根路径下(与WEB-INF在同一个文件夹下)。

这两个JSP页面文件是更简单的页面,它们只是包含了简单的提示信息。其中welcome.jsp页面的代码以下:

<%@ page language="java" contentType="text/html; charset=GBK"%>

<html>

    <head>

        <title>成功页面</title>

    </head>

    <body>

        您已经登陆!

    </body>

</html>

上面的页面就是一个普通的HTML页面,登陆失败后进入的error.jsp页面也与此彻底相似。

在如图2.1所示页面的“用户名”输入框中输入scott,在“密码”输入框中输入tiger,页面将进入welcome.jsp页面,将看到如图2.2所示的页面。

对于上面的处理流程,能够简化为以下的流程:用户输入两个参数,即username和password,而后向login.action发送请求,该请求被FilterDispatcher转发给LoginAction处理,若是LoginAction处理用户请求返回success字符串,则返回给用户welcome.jsp页面;若是返回error字符串,则返回给用户error.jsp页面。

图2.3显示了上面应用的处理流程。

 

图2.3  HelloWorld应用的处理流程

2.5  改进控制器

经过前面介绍,读者已经能够完成简单的Struts 2的基本应用了,但还能够进一步改进应用的Action类,例如该Action类能够经过实现Action接口,利用该接口的优点。前面应用的Action类没有与JavaBean交互,没有将业务逻辑操做的结果显示给客户端。

2.5.1  实现Action接口

表面上看起来,实现Struts 2的Action接口没有太大的好处,仅会污染该Action的实现类。事实上,实现Action接口能够帮助开发者更好地实现Action类。下面首先看Action接口的定义:

public interface Action

{

                                 //下面定义了5个字符串常量

                                  public static final String SUCCESS = "success";

                                  public static final String NONE = "none";

                                  public static final String ERROR = "error";

                                  public static final String INPUT = "input";

                                  public static final String LOGIN = "login";

                                 //定义处理用户请求的execute抽象方法

                                  public String execute() throws Exception;

}

在上面的Action代码中,咱们发现该Action接口里已经定义了5个标准字符串常量:SUCCESS、NONE、ERROR、INPUT和LOGIN,它们能够简化execute方法的返回值,并可使用execute方法的返回值标准化。例如对于处理成功,则返回SUCCESS常量,避免直接返回一个success字符串(程序中应该尽可能避免直接返回数字常量、字符串常量等)。

所以,借助于上面的Action接口,咱们能够将原来的Action类代码修改成以下:

//实现Action接口来实现Struts 2的Action类

public class LoginAction implements Action

{

                                 //下面是Action内用于封装用户请求参数的两个属性

                                  private String username;

                                 private String password;

                                 //username属性对应的getter方法

                                  public String getUsername()

                                 {

                                  return username;

                                  }

                                 //username属性对应的setter方法

                                  public void setUsername(String username)

                                 {

                                  this.username = username;

                                 }

                                 //password属性对应的getter方法

                                  public String getPassword()

                                 {

                                  return password;

                                  }

                                 //password属性对应的setter方法

                                  public void setPassword(String password)

                                 {

                                  this.password = password;

                                  }

                                 //处理用户请求的execute方法

                                 public String execute() throws Exception

                                 {

                                    //当用户请求参数的username等于scott,密码请求参数为tiger时,返回success

                                      字符串

                                    //不然返回error的字符串

                                  if (getUsername().equals("scott")

                                        && getPassword().equals("tiger") )

                                    {

                                   return SUCCESS;

                                  }

                                    else

                                    {

                                   return ERROR;

                                  }

                                  }

}

对比前面Action和此处的Action实现类,咱们发现两个Action类的代码基本类似,除了后面的Action类实现了Action接口。由于实现了Action接口,故Action类的execute方法能够返回Action接口里的字符串常量。

2.5.2  跟踪用户状态

前面的Action处理完用户登陆后,仅仅执行了简单的页面转发,并未跟踪用户状态信息——一般,当一个用户登陆成功后,须要将用户的用户名添加为Session状态信息。

为了访问HttpSession实例,Struts 2提供了一个ActionContext类,该类提供了一个getSession的方法,但该方法的返回值类型并非HttpSession,而是Map。这又是怎么回事呢?实际上,这与Struts 2的设计哲学有关,Struts 2为了简化Action类的测试,将Action类与Servlet API彻底分离,所以getSession方法的返回值类型是Map,而不是HttpSession。

虽然ActionContext的getSession返回的不是HttpSession对象,但Struts 2的系列拦截器会负责该Session和HttpSession之间的转换。

为了能够跟踪用户信息,咱们修改Action类的execute方法,在execute方法中经过ActionContext访问Web应用的Session。修改后的execute方法代码以下:

//处理用户请求的execute方法

public String execute() throws Exception

{

                                 //当用户请求参数的username等于scott,密码请求参数为tiger时,返回success字符串

                                 //不然返回error的字符串

                                  if (getUsername().equals("scott")

                                    && getPassword().equals("tiger") )

                                 {

                                    //经过ActionContext对象访问Web应用的Session

                                    ActionContext.getContext().getSession().put("user" , getUsername());

                                  return SUCCESS;

                                  }

                                 else

                                 {

                                  return ERROR;

                                  }

}

上面的代码仅提供了Action类的execute方法,该Action类的其余部分与前面的Action类代码彻底同样。在上面的Action类经过ActionContext设置了一个Session属性:user。为了检验咱们设置的Session属性是否成功,咱们修改welcome.jsp页面,在welcome.jsp页面中使用JSP 2.0表达式语法输出Session中的user属性。下面是修改后的welcome.jsp页面代码:

<%@ page language="java" contentType="text/html; charset=GBK"%>

<html>

    <head>

        <title>成功页面</title>

    </head>

    <body>

        欢迎,${sessionScope.user},您已经登陆!

    </body>

</html>

上面的JSP页面与前面的JSP页面没有太大改变,除了使用了JSP 2.0语法来输出Session中的user属性。关于JSP 2.0表达式的知识,请参看笔者所著的《轻量级J2EE企业应用实战》一书的第2章。

在如图2.1所示页面的“用户名”输入框中输入scott,在“密码”输入框中输入tiger,而后单击“登陆”按钮,将看到如图2.4所示的页面。

在上面登陆成功的页面中,已经输出登陆所用的用户名:scott,可见在Action经过ActionContext设置Session是成功的。

2.5.3  添加处理信息

到目前为止,Action仅仅控制转发用户请求,JSP页面并未得到Action的处理结果。对于大部分Web应用而言,用户须要得到请求Action的处理结果,例如,在线购物系统须要查询某个种类下的商品,则Action调用业务逻辑组件的业务逻辑方法获得该种类下的所有商品,而JSP页面则获取该Action的处理结果,并将所有结果迭代输出。

下面将为应用增长一个Action,该Action负责获取某个系列的所有书籍。为了让该Action能够获取这系列的书籍,咱们增长一个业务逻辑组件,它包含一个业务逻辑方法,该方法能够获取某个系列的所有书籍。

下面是系统所用的业务逻辑组件的代码:

public class BookService

{

                                 //以一个常量数组模拟了从持久存储设备(数据库)中取出的数据

                                 private String[] books =

                                    new String[]{

                                    "Spring2.0宝典" ,

                                    "轻量级J2EE企业应用实战",

                                    "基于J2EE的Ajax宝典",

                                    "Struts,Spring,Hibernate整合开发"

                                 };

                                 //业务逻辑方法,该方法返回所有图书

                                 public String[] getLeeBooks()

                                 {

                                    return books;

                                 }

}

上面的业务逻辑组件实际上就是MVC模式中的Model,它负责实现系统业务逻辑方法。理论上,业务逻辑组件实现业务逻辑方法时,必须依赖于底层的持久层组件,但此处的业务逻辑组件则只是返回一个静态的字符串数组——由于这只是一种模拟。

 注意  此处的业务逻辑组件只是模拟实现业务逻辑方法,并未真正调用持久层组件来获取数据库信息。

在系统中增长以下Action类,该Action类先判断Session中user属性是否存在,而且等于scott字符串——这要求查看图书以前,用户必须已经登陆本系统。若是用户已经登陆本系统,则获取系统中所有书籍,不然返回登陆页面。

新增的Action类的代码以下:

public class GetBooksAction implements Action

{

                                 //该属性并不用于封装用户请求参数,而用于封装Action须要输出到JSP页面信息

                                 private String[] books;

                                 //books属性的setter方法

                                 public void setBooks(String[] books)

                                 {

                                    this.books = books;

                                 }

                                 //books属性的getter方法

                                 public String[] getBooks()

                                 {

                                    return books;

                                 }

                                 //处理用户请求的execute方法

                                 public String execute() throws Exception

                                 {

                                    //获取Session中的user属性

                                    String user = (String)ActionContext.getContext().getSession().

                                        get("user");

                                    //若是user属性不为空,且该属性值为scott

                                    if (user != null && user.equals("scott"))

                                    {

                                        //建立BookService实例

                                        BookService bs = new BookService();

                                        //将业务逻辑组件的返回值设置成该Action的属性

                                        setBooks(bs.getLeeBooks());

                                        return SUCCESS;

                                    }

                                    else

                                    {

                                        return LOGIN;

                                    }

    }

}

经过上面的Action类,咱们发现Action类中的成员属性,并不必定用于封装用户的请求参数,也多是封装了Action须要传入下一个JSP页面中显示的属性。

 提示  Action中的成员属性,并必定用于封装用户的请求参数,也多是封装了Action须要传入下一个页面显示的值。实际上,这些值将被封装在ValueStack对象中。

当咱们的控制器须要调用业务逻辑方法时,咱们直接建立了一个业务逻辑组件的实例,这并非一种好的作法,由于控制器不该该关心业务逻辑组件的实例化过程。比较成熟的作法能够利用工厂模式来管理业务逻辑组件;固然,目前最流行的方式是利用依赖注入——这将在后面章节里介绍。

 注意  实际项目中不会在控制器中直接建立业务逻辑组件的实例,而是经过工厂模式管理业务逻辑组件实例,或者经过依赖注入将业务逻辑组件实例注入控制器组件。

该Action处理用户请求时,无需得到用户的任何请求参数。将该Action配置在struts.xml文件中,配置该Action的配置片断以下:

<!-- 定义获取系统中图书的Action,对应实现类为lee.GetBooksAction -->

<action name="GetBooks" class="lee.GetBooksAction">

                                 <!-- 若是处理结果返回login,进入login.jsp页面 -->

                                 <result name="login">/login.jsp</result>

                                 <!-- 若是处理结果返回success,进入showBook.jsp页面 -->

                                  <result name="success">/showBook.jsp</result>

</action>

当用户向getBooks.action发送请求时,该请求将被转发给lee.GetBooksAction处理。

2.5.4  输出处理信息

若是用户没有登陆,直接向getBooks.action发送请求,该请求将被转发到login.jsp页面。若是用户已经登陆,getBooks.action将从系统中加载到系统中的全部图书,并将请求转发给showBook.jsp页面,所以showBook.jsp页面必须负责输出所有图书。

下面笔者将以最原始的方式:JSP脚原本输出所有图书。

 注意  在实际应用中,几乎绝对不会使用笔者这种方式来输出Action转发给JSP输出的信息,但笔者为了让读者更清楚Struts 2标签库在底层所完成的动做,故此处使用JSP脚原本输出所有图书信息。

当Action设置了某个属性值后,Struts 2将这些属性值所有封装在一个叫作struts.valueStack的请求属性里。

 提示  读者可能感到奇怪:笔者是如何知道Struts 2将这些属性值封装在struts.valueStack请求属性里的?这一方面与编程经验有关,另外一方面能够经过查看Struts 2的各类文档,最重要的一点是能够在showBook.jsp页面中经过getAttributeNames方法分析请求中的所有属性。

为了在JSP页面中输出须要输出的图书信息,咱们能够经过以下代码来获取包含所有输出信息的ValueStack对象。

//获取封装输出信息的ValueStack对象

request.getAttribute("struts.valueStack");

上面代码返回一个ValueStack对象,该对象封装了所有的输出信息。该对象是 Struts 2使用的一个ValueStack对象,能够经过OGNL表达式很是方便地访问该对象封装的信息。

从数据结构上来看,ValueStack有点相似于Map结构,但它比Map结构更增强大(由于它能够根据表达式来查询值)。Action全部的属性都被封装到了ValueStack对象中,Action中的属性名能够理解为ValueStack中value的名字。

大体理解了ValueStack对象的结构后,咱们能够经过以下代码来获取Action中设置的所有图书信息。

//调用ValueStack的fineValue方法查看某个表达式的值

vs.findValue("books");

理解了上面关键的两步,整个JSP页面的代码就比较容易了解了。下面是showBook.jsp页面的代码:

<%@ page language="java" contentType="text/html; charset=GBK">

<% @page import="java.util.*,com.opensymphony.xwork2.util.*"%>

<html>

    <head>

        <title>做者李刚的图书</title>

    </head>

    <body>

                                 <table border="1" width="360">

                                 <caption>做者李刚的图书</caption>

                                 <%

                                 //获取封装输出信息的ValueStack对象

                                 ValueStack vs = (ValueStack)request.getAttribute("struts.valueStack");

                                 //调用ValueStack的fineValue方法获取Action中的books属性值

                                 String[] books = (String[])vs.findValue("books");

                                 //迭代输出所有图书信息

                                 for (String book : books)

                                 {

                                 %>

                                 <tr>

                                    <td>书名:</td>

                                    <td><%=book%></td>

                                 </tr>

                                 <%}%>

                                 </table>

    </body>

</html>

不能否认,上面JSP页面的代码是丑陋的,并且难以维护,由于里面镶嵌了大量的Java脚本。但它对于读者理解Struts 2如何处理封装在Action的ValueStack却颇有帮助。

在浏览器中向getBooks.action发送请求,将看到如图2.5所示的页面。

经过上面页面,咱们看到JSP页面已经输出了Struts 2控制器的返回信息。上面整个过程,已经彻底包括了Struts 2框架的3个部分:视图、控制器和模型。

 

图2.5  在JSP页面中输出Action的返回信息

2.6  改进视图组件

经过前面的几节的介绍,咱们已经明白了Struts 2 MVC框架的基本数据流,已经完成了Struts 2应用中模型、控制器、视图3个组件的开发。但应用中的视图组件:JSP页面很是丑陋,特别是输出Action返回信息的JSP页面,使用了大量的Java脚原本控制输出,下面将会使用Struts 2的标签来改善整个应用视图组件。

2.6.1  改善输出页面

为了控制输出Struts 2的ValueStack中封装的值,Struts 2提供了大量的标签。其中比较经常使用的标签有:

—  if:该标签支持标签体,若是if标签里判断的表达式返回真,则输出标签体内容。

—  else:该标签不能独立使用,它须要与if标签结合使用,若是if标签内判断的表达式返回假,则输出该标签里的标签体。

—  iterator:主要用于迭代输出某个集合属性的各个集合元素。

—  property:该标签用于输出指定属性值。

关于Struts 2标签库更深刻的使用,第10章还会深刻介绍,故此处再也不详细讲解。经过使用上面的几个标签,替换showBook.jsp页面中的Java脚本,修改后的showBook.jsp页面代码以下:

<%@ page language="java" contentType="text/html; charset=GBK" %>

<!-- 导入Struts 2的标签库 -->

<%@taglib prefix="s" uri="/struts-tags"%>

<html>

    <head>

        <title>做者李刚的图书</title>

    </head>

    <body>

                                 <table border="1" width="360">

                                 <caption>做者李刚的图书</caption>

                                 <!-- 迭代输出ValueStack中的books对象,其中status是迭代的序号 -->

                                 <s:iterator value="books" status="index">

                                 <!-- 判断序号是否为奇数 -->

                                 <s:if test="#index.odd == true">

                                     <tr style="background-color:#cccccc">

                                  </s:if>

                                 <!-- 判断迭代元素的序号是否不为偶数 -->

                                  <s:else>

                                  <tr>

     </s:else>

                                    <td>书名:</td>

                                    <td><s:property/></td>

                                 </tr>

                                 </s:iterator>

                                 </table>

    </body>

</html>

上面的JSP页面使用了Struts 2的标签库,所以必须在JSP页面的首部添加taglib指令,该taglib指令用于导入标签库。

 提示  若是须要使用某个标签库中的标签,则必须在页面的开始导入该标签库。

页面中使用Struts 2的iterator标签迭代输出ValueStack中的books数组,并为每一个数组元素定义了一个序号:index。经过判断序号是否为奇数,若是行序号为奇数,则输出一个有背景色的表格行;不然输出一个无背景色的表格行。

在浏览器中再次向getBooks.action发送请求(发送请求以前,必须先登陆本系统),将看到如图2.6所示的界面。

 

图2.6  使用Struts 2标签改善后的输出界面

上面页面的输出效果与图2.5并无太大的不一样,只是使用不一样颜色来分隔了记录行。这也得益于Struts 2标签库的简洁。

关键在于2.5.4节中的JSP页面代码与本节页面代码的差别:前面JSP页面使用了大量的Java脚本,让整个页面的代码看起来很是凌乱,下降了可阅读性、可维护性。但本页面中仅使用Struts 2脚本控制输出,彻底消除了页面中的Java脚本,下降了该页面的后期维护成本。

2.6.2  使用UI标签简化表单页面

前面已经提到过,Struts 2的一个重要组件就是标签库。Struts 2标签库中不只提供了前面所示的基本控制、数据输出等功能,还提供了很是丰富的UI组件,除了提供系列的主题相关标签外,还提供了一系列的表单相关的标签。

Struts 2为经常使用表单域都提供了对应的标签,下面是经常使用的表单域标签。

—  form:对应一个表单元素。

—  checkbox:对应一个复选框元素。

—  password:对应一个密码输入框。

—  radio:对应一个单选框元素。

—  reset:对应一个重设按钮。

—  select:对应一个下拉列表框。

—  submit:对应一个提交按钮。

—  textarea:对应一个多行文本域。

—  textfield:对应一个单行文本框。

关于这些界面相关的标签,一样将在第10章详细介绍。下面将使用Struts 2的表单相关标签简化用户登陆的login.jsp页面,修改的login.jsp页面的代码以下:

<%@ page language="java" contentType="text/html; charset=GBK"%>

<%@taglib prefix="s" uri="/struts-tags"%>

<html>

<head>

<title>登陆页面</title>

</head>

<body>

<!-- 使用form标签生成表单元素 -->

<s:form action="Login">

                                 <!-- 生成一个用户名文本输入框 -->

                                 <s:textfield name="username" label="用户名"/>

                                 <!-- 生成一个密码文本输入框 -->

                                 <s:textfield name="password" label="密  码"/>

                                 <!-- 生成一个提交按钮 -->

                                 <s:submit value="登陆"/>

</s:form>

</body>

</html>

将该页面与前面的表单页面进行对比,咱们发现该页面的代码简洁多了。由于使用了Struts 2的表单标签,定义表单页面也更加迅速。在浏览器中浏览该页面,看到如图2.7所示的界面。

 

图2.7  使用Struts 2表单标签后的表单页

固然,Struts 2的标签还有许多功能,此处先不详述,本书的第10章将会详细介绍Struts 2标签的用法。

2.7  完成程序国际化

由于一个企业应用常常须要面对多区域的用户,所以,程序国际化是一个企业应用必须实现的功能。Struts 2提供了很好的程序国际化支持。

2.7.1  定义国际化资源文件

Struts 2的程序国际化支持创建在Java程序国际化的基础之上,关于Java程序的国际化笔者将在第9章简要介绍。此处不会详细介绍,但咱们要明白一个概念:程序国际化的设计思想是很是简单的,其主要思想是:程序界面中须要输出国际化信息的地方,咱们不要在页面中直接输出信息,而是输出一个key值,该key值在不一样语言环境下对应不一样的字符串。当程序须要显示时,程序将根据不一样的语言环境,加载该key对应该语言环境下的字符串——这样就能够完成程序的国际化。

图2.8显示了程序国际化的示意图。

 

图2.8  程序国际化示意图

从图2.8能够看出,若是须要程序支持更多的语言环境,只须要增长更多语言资源文件便可。

为了给本应用增长程序国际化支持(支持英文和中文),则应该提供两份语言资源文件。下面是本应用所使用的中文语言环境下资源文件的代码。

loginPage=登陆页面

errorPage=错误页面

succPage=成功页面

failTip=对不起,您不能登陆!

succTip=欢迎,${0},您已经登陆!

viewLink=查看做者李刚已出版的图书

bookPageTitle=做者李刚已出版的图书

bookName=书名:

user=用户名

pass=密  码

login=登陆

由于该资源文件中包含了非西欧字符,所以必须使用native2ascii命令来处理该文件。将上面文件保存在WEB-INF/classes路径下,文件名为“messageResouce.properties”。保存该文件后,必须使用native2ascii命令来处理该文件,处理该文件的命令格式为:

native2ascii messageResouce.properties messageResouce_zh_CN.properties

上面命令将包含非西欧字符的资源文件处理成标准的ASCII格式,处理完成后生成了一份新文件:messageResouce _zh_CN.properties文件。这个文件的文件名符合资源文件的命名格式,资源文件的文件名命名格式为:

basename_语言代码_国家代码.properties

当请求来自简体中文的语言环境时,系统将自动使用这种资源文件中的内容输出。

 注意  对于包含非西欧字符的资源文件,必定要使用native2assii命令来处理该文件,不然将看到一堆乱码。

除此以外,还应该提供以下英文语言环境的资源文件。

loginPage=Login Page

errorPage=Error Page

succPage=Welcome Page

failTip=Sorry,You can't log in!

succTip=welcome,{0},you has logged in!

viewLink=View LiGang\'s Books

bookPageTitle=LiGang\'s Books

bookName=BookName:

user=User Name

pass=UserPass

login=Login

将上面资源文件保存在WEB-INF/classes路径下,文件名为“messageResouce_en_ US.properties”。当请求来自美国时,系统自动使用这份资源文件的内容输出。

2.7.2  加载资源文件

Struts 2支持在JSP页面中临时加载资源文件,也支持经过全局属性来加载资源文件。经过全局属性加载资源文件更简单,本应用使用全局属性加载Struts 2国际化资源文件。

加载资源文件能够经过struts.properties文件来定义,本应用的struts.properties文件仅有以下一行代码:

//定义Struts 2的资源文件的baseName是messageResource

struts.custom.i18n.resources=messageResource

在struts.properties文件中增长上面的代码定义后,代表该应用使用的资源文件的baseName为“messageResouce”——这与咱们前面保存资源文件的baseName是一致的。

Struts 2默认加载WEB-INF/classes下的资源文件,在上一节中,咱们就是将资源文件保存在该路径下的。若是将该资源文件保存在WEB-INF/classes的子目录下,例如保存在WEB-INF/classes/lee路径下,则须要修改struts.properties中的定义以下:

//定义Struts 2的资源文件的baseName是messageResource,且文件放在WEB-INF/

classes/lee路径下

struts.custom.i18n.resources=lee.messageResource

2.7.3  输出国际化信息

为了让程序能够显示国际化信息,则须要在JSP页面中输出key,而不是直接输出字符串常量。

Struts 2提供了以下两种方式来输出国际化信息:

—  <s:text name="messageKey"/>:使用s:text标签来输出国际化信息。

—  <s:property value="%{getText("messageKey")}"/>:使用表达式方式输出国际化信息。

所以,咱们再次修改表现层的JSP页面,使用国际化标签输出国际化信息。修改后的showBook.jsp页面代码以下:

<%@ page language="java" contentType="text/html; charset=GBK"%>

<%@taglib prefix="s" uri="/struts-tags"%>

<html>

                                 <head>

                                    <!-- 使用s:text输出国际化信息 -->

        <title><s:text name="bookPageTitle"/></title>

    </head>

    <body>

                                 <table border="1" width="360">

                                 <!-- 使用s:text输出国际化信息 -->

                                 <caption><s:text name="bookPageTitle"/></caption>

                                 <s:iterator value="books" status="index">

                                    <s:if test="#index.odd == true">

         <tr style="background-color:#cccccc">

       </s:if>

       <s:else>

         <tr>

       </s:else>

                                    <td><s:text name="bookName"/></td>

                                    <td><s:property/></td>

                                 </tr>

                                 </s:iterator>

                                 </table>

    </body>

</html>

咱们发现,上面的JSP页面再也不包含任何直接字符串,而是所有经过<s:text name="..."/>来输出国际化提示。

再次在浏览器浏览该页面,将看到与图2.7相同的界面。

从新设置浏览者所在的语言/区域选项,设置语言/区域选项请先进入“控制面板”,在控制面板中单击“区域和语言选项”,进入如图2.9所示的对话框。

若是咱们选择“英语(美国)”选项,而后单击“肯定”按钮,将设置本地的语言环境为美国英语。

再次向服务器请求login.jsp页面,将看到如图2.10所示的页面。

            

图2.9  设置语言/区域选项                  图2.10  程序国际化的效果

若是咱们使用FireFox浏览器来浏览该页面时,发现依然显示中文界面——这是由于FireFox的语言环境并不受Windows系统的控制。为了让FireFox也使用美国英语环境,单击FireFox浏览器菜单栏中的“工具”菜单,选择“选项”菜单项,将出现“选项”对话框,单击“高级”按钮,将看到如图2.11所示的界面。

在如图2.11所示的对话框中单击“选择”按钮,将出现“语言和字符编码”对话框,在该对话框下面的下拉列表框中选择“英语/美国 [en-us]”选项,如图2.12所示,而后单击下拉框右边的“添加”按钮,将添加了“英语/美国”的语言环境。并在该对话框上面的列表框中选择“英语/美国 [en-us]”,而后单击“上移”按钮,将该选项移至最上面,让整个页面优先使用英语/美国的环境。

      

图2.11  设置FireFox的语言环境         图2.12  设置FireFox的语言环境为英语/美国

再次使用FireFox浏览器浏览login.jsp页面,将看到该页面变成了英文界面。

2.8  增长数据校验

在上面应用中,即便浏览者输入任何用户名、密码,系统也会处理用户请求。在咱们整个HelloWorld应用中,这种空用户名、空密码的状况不会引发太大的问题。但若是数据须要保存到数据库,或者须要根据用户输入的用户名、密码查询数据,这些空输入可能引发异常。

为了不用户的输入引发底层异常,一般咱们会在进行业务逻辑操做以前,先执行基本的数据校验。

2.8.1  继承ActionSupport

ActionSupport类是一个工具类,它已经实现了Action接口。除此以外,它还实现了Validateable接口,提供了数据校验功能。经过继承该ActionSupport类,能够简化Struts 2的Action开发。

在Validatable接口中定义了一个validate()方法,重写该方法,若是校验表单输入域出现错误,则将错误添加到ActionSupport类的fieldErrors域中,而后经过OGNL表达式负责输出。

为了让Struts 2增长输入数据校验的功能,改写程序中的LoginAction,增长重写validate方法。修改后的LoginAction类代码以下:

//Struts 2的Action类就是一个普通的Java类

public class LoginAction

{

                                 //下面是Action内用于封装用户请求参数的两个属性

                                  private String username;

                                 private String password;

                                 //username属性对应的getter方法

                                  public String getUsername()

                                 {

                                  return username;

                                  }

                                 //username属性对应的setter方法

                                  public void setUsername(String username)

                                 {

                                  this.username = username;

                                 }

                                 //password属性对应的getter方法

                                  public String getPassword()

                                 {

                                  return password;

                                  }

                                 //password属性对应的setter方法

                                  public void setPassword(String password)

                                 {

                                  this.password = password;

                                  }

                                 //处理用户请求的execute方法

                                 public String execute() throws Exception

                                 {

                                    //当用户请求参数的username等于scott,密码请求参数为tiger时,返回success

                                      字符串

                                    //不然返回error的字符串

                                  if (getUsername().equals("scott")

                                        && getPassword().equals("tiger") )

                                    {

                                   return "success";

                                  }

                                    else

                                    {

                                   return "error";

                                  }

                                  }

                                 //完成输入校验须要重写的validate方法

                                 public void validate()

                                 {

                                    //若是用户名为空,或者用户名为空字符串

                                    if (getUsername() == null || getUsername().trim().equals(""))

                                    {

                                        //添加表单校验错误

                                        addFieldError("username", "user.required");

                                    }

                                    //当密码为空,或者密码为空字符串时,添加表单校验错误

                                    if (getPassword() == null || getPassword().trim().equals(""))

                                    {

                                        addFieldError("password", "pass.required");

                                    }

                                 }

}

上面的Action类重写了validate方法,该方法会在执行系统的execute方法以前执行,若是执行该方法以后,Action类的fieldErrors中已经包含了数据校验错误,请求将被转发到input逻辑视图处。

为了在校验失败后,系统能将视图转入input处,必须在配置该Action时配置input属性。下面是修改后login Action的配置片断:

<!-- 定义login的Action -->

<action name="Login" class="lee.LoginAction">

                                 <!-- 定义input的逻辑视图名,对应login.jsp页面 -->

                                 <result name="input">/login.jsp</result>

                                 <!-- 定义error的逻辑视图名,对应error.jsp页面 -->

                                  <result name=" success ">/error.jsp</result>

                                 <!-- 定义welcome的逻辑视图名,对应welcome.jsp页面 -->

                                  <result name="success">/welcome.jsp</result>       

</action>

对比上面的Action配置与前面的Action配置,咱们发现该Action配置片断中增长了input逻辑视图的配置,该逻辑视图映射到login.jsp页面。

前面已经提到:当用户提交请求时,请求获得execute方法处理以前,先会被validate方法处理,若是该方法处理结束后,Action的fieldErrors里的校验错误不为空,请求将被转发给input逻辑视图。若是咱们不输入用户名、密码而直接提交表单,将看到如图2.13所示的界面。

 

图2.13  输入校验的界面

看到这里也许读者以为很是神奇:咱们仅仅在Action添加了数据校验错误,并未在输入页面输出这些校验错误信息,但图2.13所示的页面,却能够看到页面已经输出了这些校验信息——这是由于Struts 2的标签,上面的JSP页面中表单使用的并非HTML表单,而是用了<s:form .../>标签,Struts 2的<s:form ... />标签已经具有了输出校验错误的能力。

 提示  Struts 2的<s:form .../>默认已经提供了输出校验错误的能力。

但上面的程序还存在一个问题:校验信息的国际化。查看上面的Action类代码发现:重写validate方法时,若是发生校验失败的问题,校验错误的提示信息是以硬编码方式写死了——这就失去了国际化的能力。

实际上,ActionSupport类已经提供了国际化信息的能力,它提供了一个getText(String key)方法,该方法用于从资源文件中获取国际化信息。为了让校验信息支持国际化,再次改写Action里的validate方法,改写后的validate方法代码以下:

//执行数据校验的validate方法

public void validate()

{

                                 //若是用户名为空,或者为空字符串

                                 if (getUsername() == null || getUsername().trim().equals(""))

                                 {

                                    //添加校验错误提示,使用getText方法来使提示信息国际化

                                    addFieldError("username", getText("user.required"));

                                 }

                                 if (getPassword() == null || getPassword().trim().equals(""))

                                 {

                                    addFieldError("password", getText("pass.required"));

                                 }

}

在上面的validate方法中,添加校验错误提示时,并非直接给出了错误提示的字符串,而是调用了getText方法来获取错误提示。由于在Action中,使用getText方法来获取了两个国际化提示:user.required和pass.required,所以应该在国际化资源文件中添加这两条提示信息。

 提示  ActionSupport增长了让提示信息国际化的能力,ActionSupport提供的getText方法能够根据资源文件加载得到国际化提示信息。

此时,若是没有任何输出,直接提交登陆表单,将看到如图2.14所示的界面。

 

图2.14  国际化数据校验的错误提示

2.8.2  使用Struts 2的校验框架

上面的输入校验是经过重写ActionSupport类的validate方法实现的,这种方法虽然不错,但须要大量重写的validate方法——毕竟,重复书写相同的代码不是一件吸引人的事情。

相似于Struts 1,Struts 2也容许经过定义配置文件来完成数据校验。Struts 2的校验框架其实是基于XWork的validator框架。

下面仍是使用原来的Action类(即不重写validate方法),却增长一个校验配置文件,校验配置文件经过使用Struts 2已有的校验器,完成对表单域的校验。Struts 2提供了大量的数据校验器,包括表单域校验器和非表单域校验器两种。

本应用主要使用了requiredstring校验器,该校验器是一个必填校验器——指定某个表单域必须输入。

下面是校验规则的定义文件:

<?xml version="1.0" encoding="GBK"?>

<!-- 指定校验规则文件的DTD信息 -->

<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator

                                 1.0.2//EN"

                                 "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
<!-- 校验规则定义文件的根元素 -->

<validators>

                                 <!-- 校验第一个表单域:username -->

                                 <field name="username">

                                    <!-- 该表单域必须填写 -->

                                  <field-validator type="requiredstring">

                                        <!-- 若是校验失败,显示user.required对应的信息 -->

                                   <message key="user.required"/>

                                  </field-validator>

                                  </field>

                                 <!-- 校验第二个表单域:password -->

                                  <field name="password">

                                  <field-validator type="requiredstring">

                                        <!-- 若是校验失败,显示pass.required对应的信息 -->

                                   <message key="pass.required"/>

                                  </field-validator>

                                  </field>

</validators>

定义完该校验规则文件后,该文件的命名应该遵照以下规则:

ActionName-validation.xml:其中ActionName就是须要校验的Action的类名。

所以上面的校验规则文件应该命名为“LoginAction-validation.xml”,且该文件应该与Action类的class文件位于同一个路径下。所以,将上面的校验规则文件放在WEB-INF/classes/lee路径下便可。

固然,在struts.xml文件的Action定义中,同样须要定义input的逻辑视图名,将input逻辑视图映射到login.jsp页面。

若是不输入用户名、密码而提交表单,将再次看到如图2.14所示的界面。在这种校验方式下,无需书写校验代码,只须要经过配置文件指定校验规则便可,所以提供了更好的可维护性。

2.9  本章小结

本章以一个HelloWorld应用为例,简要介绍了Struts 2 MVC框架的基本流程,从Action类基本流程控制讲起,详细介绍了如何开发一个Struts 2应用。本章的后面部分在基本Struts 2应用基础上,介绍了一些Struts 2的深刻应用,包括在Action中访问HttpSession状态,将Action处理结果传回JSP页面显示,本应用也综合应用了Struts 2的标签库、数据校验、程序国际化等经常使用功能。经过阅读本章的内容,读者应该对Struts 2框架有一个大体的掌握。

相关文章
相关标签/搜索