Struct(二)

struct2 权威指南html

这一节经过一个详细的实例来说解Struct2框架的应用java

 

1 下载和安装Struts 2框架web

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

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

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

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

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

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

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

—  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框架的所有源代码。

(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环境变量里。

 

(3)编辑Web应用的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>

2 建立一个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>

 

3. 建立WEB应用

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

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

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

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

 (3) 修改复制的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>

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

(5)通过上面步骤,已经创建了一个空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页面的名字,也能够修改。其余文件夹、配置文件都不能够修改。

 

4. 增长Struct2的功能

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

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

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

 (3) 在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节已经给出了,故此处再也不赘述。

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";

                                  }

                                  }

}

4.2  配置Action

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

-----------------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页面。

 

 

 

 

 

 

 

咱们再增长两个页面 error.jsp和welcome.jsp也就完成了基本属性的配置

 

第二部分 功能扩展:

5. 改进控制器

5.1  实现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接口里的字符串常量。

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是成功的。

 

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处理。

相关文章
相关标签/搜索