1 struts 2入门 - tup.com.cn · 图1-1...

23
Struts 2 入门 Struts 2 最早是 Apache Jakarta 项目的组成部分,项目创立者希望通过对该项目的研究,改 进和提高 JSPServlet、标签库以及面向对象的技术水准。Struts 采用 MVC 模式,帮助 Java 开发者利用 J2EE 开发 Web 应用。和其他 Java 架构一样,Struts 也是面向对象的设计,充分发 挥了 MVC 模式“分离显示逻辑和业务逻辑”的优势。 本章首先介绍 Struts 的发展历程,让读者对 Struts 2 框架的技术发展历程有所了解,接 下来介绍 Struts 2,包括与其他框架相比 Struts 2 的优势、Struts 2 组成等基础知识。然后配 Struts 2 的运行环境,通过一个非常简单的实例向读者介绍使用 Struts 2 进行 Web 开发的 基本流程和步骤,最后讲解 Struts 2 各个组成部分的作用,以使读者对 Struts 2 有更清晰的 认知。 ¾ 了解 Struts 2 的发展历程 ¾ 熟悉 Struts 2 的项目组成 ¾ 掌握 Action 配置 ¾ 掌握配置 Struts 2 运行环境的方法 ¾ 熟悉 Struts 2 的开发流程 ¾ 掌握 Struts 2 各个部分的作用 ¾ 掌握 Struts 2 的基本配置 1.1 Struts 2 发展历程 进入 Struts 2 世界固然令人兴奋,但是 Struts 2 并不是一种完全独立的技术,而是建立在 其他 Web 技术之上的一个 MVC 框架,如果脱离了这些技术,Struts 2 框架也就无从谈起。因 此,本节首先介绍了 MVC,然后对 Struts 1 Struts 2 进行了概述。 1.1.1 MVC 概述 MVC 本来存在于桌面程序中,M 是指数据模型,V 是指用户界面,C 则是指控制器。 MVC 的目的是将 M V 的实现代码分离,从而使同一个程序可以使用不同的表现形式。例 1

Upload: others

Post on 21-May-2020

7 views

Category:

Documents


0 download

TRANSCRIPT

Struts 2 入门

Struts 2 最早是 Apache Jakarta 项目的组成部分,项目创立者希望通过对该项目的研究,改

进和提高 JSP、Servlet、标签库以及面向对象的技术水准。Struts 采用 MVC 模式,帮助 Java开发者利用 J2EE 开发 Web 应用。和其他 Java 架构一样,Struts 也是面向对象的设计,充分发

挥了 MVC 模式“分离显示逻辑和业务逻辑”的优势。 本章首先介绍 Struts 的发展历程,让读者对 Struts 2 框架的技术发展历程有所了解,接

下来介绍 Struts 2,包括与其他框架相比 Struts 2 的优势、Struts 2 组成等基础知识。然后配

置 Struts 2 的运行环境,通过一个非常简单的实例向读者介绍使用 Struts 2 进行 Web 开发的

基本流程和步骤,最后讲解 Struts 2 各个组成部分的作用,以使读者对 Struts 2 有更清晰的

认知。

了解 Struts 2 的发展历程 熟悉 Struts 2 的项目组成 掌握 Action 配置 掌握配置 Struts 2 运行环境的方法 熟悉 Struts 2 的开发流程 掌握 Struts 2 各个部分的作用 掌握 Struts 2 的基本配置

1.1 Struts 2 发展历程

进入 Struts 2 世界固然令人兴奋,但是 Struts 2 并不是一种完全独立的技术,而是建立在

其他 Web 技术之上的一个 MVC 框架,如果脱离了这些技术,Struts 2 框架也就无从谈起。因

此,本节首先介绍了 MVC,然后对 Struts 1 和 Struts 2 进行了概述。

1.1.1 MVC 概述

MVC 本来存在于桌面程序中,M 是指数据模型,V 是指用户界面,C 则是指控制器。

MVC 的目的是将 M 和 V 的实现代码分离,从而使同一个程序可以使用不同的表现形式。例

第1章

Struts 2 入门1 第 章

3

如一批统计数据,可以分别用柱状图和饼

图来表示。C 存在的目的则是确保 M 和 V的同步,一旦 M 改变,V 应该同步更新,

其工作模式如图 1-1 所示。 此种模式的 MVC 又称为经典 MVC,

用户与视图(View)进行交互,写入数据

并提交,控制器(Controller)接收到来自

视图的事件并对模型(Model)进行操作,

根据用户输入的数据来更新模型,将更新

的结果显示给用户。这种模式有以下两个

优点。 实现了视图与业务逻辑的分离,提高了代码重用率,减少了数据表达、数据描述和应

用操作的耦合度。 使得软件可维护性、可重用性、可扩展性、灵活性以及封装性大大提高。

图 1-1 这种经典模式在单机且实时更新的应用程序中可以起到很好的作用。

在 Web 应用中,图 1-1 这种经典的 MVC 模式就不适合了,其缺点主要体现在以下几个

方面。 因为在 Web 世界中,视图是位于客户端浏览器上的,而控制器和模型则是位于服务

器端的,视图无法通过 HTTP 像经典 MVC 那样直接调用控制器。 视图不是一个可以更新的对象,而是在客户端发送一个新的请求,随之获得一个全新

的 Web 页面。 模型不能将自身的改变通知视图,因为视图在另一台计算机的浏览器中。

由于存在以上几点劣势,人们不得不对 MVC 设计模式进行重新设计,因此就诞生了在

Web 应用程序中通过前端控制器来实现 MVC 应用程序的模型。 在这种模型中包含了一个“分发器”(在 Java 的 Web MVC 中分发器使用 Servlet 来实现),

分发器可以将一个请求 URL 映射成一个需要被执行的

命令,然后去执行相应的命令实例(例如 Struts 2 中的

命令实例就是 Action,Action 与后台的服务程序进行交

互,这个后台服务程序又叫模型(M))。当命令实例执

行完相应的业务逻辑后就会返回一个码值,此码值又会

被映射到相应的视图(通常是一个 Web 页面模板,例如

JSP)中。最后结合控制器和模型,映射到的视图将会

被发送到客户端的浏览器呈现,此过程的图解如图 1-2所示。

这种模式对于设计一个系统有很多令人惊喜的好

处,如下所示。 多个视图可以对应一个模型,这样,可以减少代码的复制及代码的维护量,一旦模型

图 1-1 经典 MVC 模式图解

图 1-2 Web 应用中的 MVC 模型

模块一

Struts 2+Hibernate+Spring 整合开发技术详解

4

发生改变,也易于维护。 模型返回的数据与显示逻辑分离,这样,模型数据就可以应用任何的显示技术,例如,

使用 JSP 页面、Velocity 模板或者直接产生 Excel 文档等。 应用被分隔为层,降低了各层之间的耦合度,提供了应用的可扩展性。 控制层可以发挥更大的作用,由于它把不同的模型和不同的视图组合在一起,可以完

成不同的请求,因此,控制层可以包含对用户请求权限的限制。 更符合软件工程化管理的精神。不同的层各司其职,每一层的组件具有相同的特征,

有利于通过工程化和工具化管理程序代码。

MVC 的缺点是没有明确的定义,所以完全理解 MVC 并不是很容易。使用

MVC 需要精心地去设计,由于它的内部原理比较复杂,所以需要花费一些时

间去思考。 常见 MVC 组件有如下几个。 Struts 最流行的 MVC 组件,Apache Jakarta 项目组的一个开源项目。 Struts 2 Apache 用 Struts 和 WebWork 组合出来的新产品,目前上升势头强劲。 WebWork 这是老牌的 MVC 组件,后来组合成了 Struts 2。 Spring MVC Spring Framework 自己整合自己 Spring 的优势推出的 MVC 组件。 JSF 这是一个规范。用户量很大,大多数 IDE 都支持。

1.1.2 Struts 1 概述

在过去,Struts 1 是所有 MVC 框架中不容辩驳的胜利者,不管是市场占有率,还是所拥

有的开发人群,Struts 1 都拥有其他 MVC 框架不可比拟的优势。Struts 1 的成功得益于它丰富

的文档和活跃的开发群体,当然,Struts 1 是 Web 应用的第一个 MVC 框架,这一点也是它得

到如此广泛拥戴的一个重要原因。 对于整个 Struts 1 框架而言,控制器就是它的核心(大部分 Web MVC 框架也都是如此),

Struts 1 的控制器由两个部分组成:核心控制器和业务逻辑控制器。其中核心控制器就是

ActionServlet,由 Struts 1 框架提供;业务逻辑控制就是用户自定义的 Action,由应用开发者

提供。

当用户发送一个需要得到服务器处理的请求时,该请求被 ActionServlet 拦截到,

ActionServlet 将该请求转发给对应的业务逻辑控制器,业务逻辑控制器调用模型

来处理用户请求;如果用户请求只是希望得到某个 URL 资源,则由 ActionServlet将被请求的资源转发给用户。

Struts 1 是一个 Web 的 MVC 框架(后面如果再提到 MVC 就默认是指 Web 的 MVC 模型),

那么它的“MVC 三角色”又分别是什么呢?

1.Model 部分

Struts 1 的 Model 部分主要由底层的业务逻辑组件充当,这些业务逻辑组件封装了底层数

Struts 2 入门1 第 章

5

据库访问、业务逻辑方法实现。实际上,对于一个成熟的企业应用而言,Model 部分也不是一

个简单的 JavaBean 所能完成的,它可能是一个或多个 EJB 组件,也可能是一个 WebService 服

务。总之,Model 部分封装了整个应用的所有业务逻辑,但整个部分并不是由 Struts 1 提供的,

Struts 1 也没有为实现 Model 组件提供任何支持。

2.View 部分

Struts 1 的 View 部分采用 JSP 实现。Struts 1 提供了丰富的标签库,通过这些标签库可以

最大限度地减少脚本的使用。这些自定义的标签库可以输出控制器的处理结果。 虽然 Struts 1 提供了与 Tiles 框架的整合,但 Struts 1 所支持的表现层技术非常单一:既不

支持 FreeMarker、Velocity 等模板技术,也不支持 JasperReports 等报表技术。

3.Controller 部分

Struts 1 的 Controller 由两个部分组成:核心控制器和业务逻辑控制器。 核心控制器

由 Struts 1 框架提供,就是系统中的 ActionServlet。它继承自 HttpServlet 类,因此可以配

置成一个标准的 Servlet,该控制器负责拦截所有 HTTP 请求,然后根据用户请求决定是否需

要调用业务逻辑控制器,如果需要调用业务逻辑控制器,则将请求转发给 Action 处理,否则

直接转向请求的 JSP 页面。 业务逻辑控制器

不是由 Struts 1 框架提供的,而是用户自己实现的 Action 实例。业务逻辑控制器负责处理

用户请求,但业务逻辑控制器本身并不具有处理能力,而是调用 Model 来完成处理。 Struts 1 不但提供了系统所需要的核心控制器,也为实现业务逻辑控制器提供了许多支持。

因此,控制器部分就是 Struts 1 框架的核心。对于任何的 MVC 框架而言,其实只实现了 C(控

制器)部分,但它负责用控制器调用业务逻辑组件,并负责控制器与视图技术(JSP、FreeMarker和 Velocity 等)的整合。

当客户端向服务器发送请求时,请求首先被 Struts 1 的核心控制器 ActionServlet 拦截,

ActionServlet 根据请求决定需要调用哪个业务逻辑控制器 Action 来处理客户端请求。

Action 本身并没有处理能力,只是进行业务逻辑控制,它还需要调用响应的模型来完成

处理。当处理完客户端请求后 Action 就将处理结果通过 JSP 页面呈现给用户,如图 1-3所示。

图 1-3 Struts 1 的程序运行流程

模块一

Struts 2+Hibernate+Spring 整合开发技术详解

6

1.1.3 Struts 2 概述及优势

随着 Web 技术的不断发展和 Web 应用的不断扩大,Struts 1 的诸多缺陷和局限性也逐渐表

现出来,如下所示。 Struts 1 所支持的表现层技术比较单一

Struts 1 只支持 JSP 作为其表现层技术,没有提供对目前流行的 FreeMarker、Velocity 等表

现层的支持,这一点严重限制了 Struts 1 的使用。 Struts 1 与 Servlet API 耦合严重,难于测试

Struts 1 完全基于 Servlet API,并在 Struts 1 的业务逻辑控制器内充满了大量的 Servlet API。而 Servlet API 通常由 Web 服务器来负责实例化,所以 Struts 1 严重依赖于 Web 服务器,一旦

脱离了 Web 服务器,Action 的测试将变得非常困难。 Struts 1 属于侵入式设计

Struts 1 的 Action 中包含了大量的 Struts 1 API,这种侵入式的设计影响了代码重用,一旦

系统需要重构,这种侵入式的设计将会带来很多的问题。

由于 Struts 1 存在诸多缺陷,而 WebWork 框架具有优秀的设计理念,于是基于

Struts 1 和 WebWork 的 Struts 2 就诞生了。 Struts 2 虽然是在 Struts 1 的基础上发展起来的,但它以 WebWork 为核心,采用 WebWork

的设计理念,跟 Struts 1 有很大差别,所以接下来简单介绍一下 WebWork。 WebWork 和 Struts 1 一样也是诸多 MVC 开源框架中的一员,来自一个非常优秀的开源组

织—opensymphony。WebWork 项目在 2002 年 3 月发布,对 Struts 1 的框架进行了革命性改

进,引进了不少新的思想、概念和功能,但和原 Struts 1 代码并不兼容。相对于 Struts 1 的那

些缺陷和局限性,WebWork 则更加优秀。 WebWork 支持更多的表现层技术,如 FreeMarker、Velocity 以及 XSLT 等,有广泛的

适应性。 WebWork 采用了一种更加松耦合的设计,使 Action 不再与 Servlet 耦合。WebWork 的

Action 更像一个普通的 Java 对象,该控制器代码中没有耦合任何 Servlet API,这也使

单元测试变得更加方便。 Action 无须与 WebWork 耦合,提高了代码重用率。

虽然经过多年的发展,Struts 1 已经成为了一个高度成熟的框架,其稳定性和可靠性也得

到了广泛的认可,但由于它太“老”了,一些设计上的缺陷已经慢慢适应不了目前 Web 技术

的发展和需求。同时,出现了一些新的优秀的 MVC 框架,带来了很多新的、优秀的设计理念,

Struts 1 也终于开始了更新。

Struts 已经分化成两个框架,一个是 Shale,一个全新的框架,与 Struts 联系很少。

另一个是 Struts 1 和 WebWork 结合后的 Struts 2,在 Struts 1 基础上发展起来,实

质上以 WebWork 为核心,为 Struts 1 引入了 WebWork 优秀的设计理念。Struts 2兼容 Struts 1 和 WebWork 两个框架。

Struts 2 入门1 第 章

7

通过上面的介绍不难看出,Struts 2 已经有了很大的改进,接下来以表格的形式来比较

Struts 2 与 Struts 1 的特性。通过比较这些特性能够很容易地看出 Struts 2 的优势和一些新特性,

如表 1-1 所示。

表 1-1 Struts 2 与 Struts 1 比较

特性 Struts 1 Struts 2

Action 类 Struts 1 要求 Action 类要扩展自一个抽

象基类。Struts 1 的一个共有的问题是面

向抽象类编程而不是面向接口编程

Struts 2 的 Action 类实现了一个 Action 接口,连

同其他接口一起来实现可选择和自定义的服务。

当然 Struts 2 的 Action 接口并不是必需的。任何

使用 execute()方法的 POJO 对象都可以被当做

Struts 2 的 Action 对象来使用

线程模型 Struts 1 的 Action 类是单例类,因为只有

一个实例来控制所有的请求。单例类策

略造成了一定的限制,并且给开发者带

来了额外的烦恼。Action 资源必须是线

程安全或者同步

Struts 2 的 Action 对象为每一个请求都实例化对

象,所以没有线程安全的问题

Servlet 依赖 Struts 1 的 Action 类依赖于 Servlet API,当 Action 被调用时,以 HttpServletRequest和 HttpServletResponse 作为参数传给

execute()方法

Struts 2 的 Action 和容器无关。Servlet 上下文被

表现为简单的 Maps,允许 Action 被独立地测试。

Struts 2 的 Action 可以访问最初的请求。但是,

应 该 尽 可 能 避 免 其 他 元 素 直 接 访 问

HttpServletRequest 或 HttpServletResponse

易测性 测试 Struts 1 的主要问题是 execute()方法暴露了 Servlet API,这使得测试要依

赖于容器

Struts 2 的 Action 可以通过初始化、设置属性和

调用方法来测试。依赖注入的支持也使测试变得

更简单

捕获输入 Struts 1 使用 ActionForm 对象来捕获输

入。和 Action 一样,所有的 ActionForm必须扩展基类。因为其他的 JavaBean 不

能作为 ActionForm 使用,开发者经常创

建多余的类来捕获输入

Struts 2 直接使用 Action 属性作为输入属性,消

除了对第二个输入对象的需求。Action 属性能够

通过 Web 页面上的 taglibs 访问。Struts 2 也支持

ActionForm 模式,简化了 taglib 对 POJO 输入对

象的引用

表达式语言 Struts 1 整合了 JSTL,所以使用 JSTL 的

表达式语言。表达式语言支持基本的图

形对象移动,但是对集合和索引属性的

支持很弱

Struts 2 使用 JSTL,但是还支持一个更强大和灵

活的表达式语言 Object Graph Notation Language(OGNL)

类型转换 Struts 1 的 ActionForm 属性经常都是

String。Struts 1 使用 Commons-Beanutils来进行类型转换。转换每一个类,而不

是为每一个实例进行配置

Struts 2 内置了转换器,对于日期、整数或浮点数

等类型会自动去调用相应的转换器进行类型转

换,为编程带来极大的方便

视图支持 Struts 1 只支持 JSP 作为其表现层技术,

没有提供对目前流行的 FreeMarker、Velocity 等表现层的支持

Struts 2 提供了对 FreeMarker、Velocity 等模板技

术的支持,并且配置很简单

1.2 配置 Struts 2 运行环境

要使用 Struts 2 框架进行 Web 开发或者运行 Struts 2 的程序就必须先配置好 Struts 2 的运

模块一

Struts 2+Hibernate+Spring 整合开发技术详解

8

行环境。

配置 Struts 2 运行环境首先就是配置 JDK 环境变量,然后下载并安装 Struts 2 框

架。至于 Web 服务器则选择开源的 Tomcat,这些都是准备工作,在下一小节将

使用 Struts 2 进行一个简单实例的开发。 Java 官方网站是 http://java.sun.com,可以直接在该网站下载 JDK。JDK 的安装很简单,这

里不再多述。在安装和配置好 JDK 后,配置 JDK 环境变量,然后就可以安装 Java Web 服务器

了,这里选择开源的 Tomcat 作为服务器。Tomcat 服务器的官方网站是 http://tomcat.apache.org/,该网站提供了 Tomcat 下载链接,目前最新版本是 Tomcat 6.x。

http://struts.apache.org/是 Struts 的官方网站,提供了 Struts 2 框架的下载链接,目前最新版

本是 Struts 2.x。下载时有多个选项可供选择,本书选择 Full Distribution 选项,即 Struts 2 的完

整版。 下载完毕后,将下载的压缩包进行解压,然后找到 lib 文件夹。该文件夹内存放的就是 Struts

2 的核心库和第三方插件库,开发 Struts 2 需要的 API 就是这些类库,也就是把需要的相关类

库复制到 Web 应用的 WEB-INF/lib 文件夹中。这里把 struts2-core-2.1.6.jar、xwork-2.1.2.jar、ognl-2.6.11.jar、freemarker-2.3.13.jar、commons-fileupload-1.2.1.jar 以及 commons-logging-1.0.4.jar复制到 Web 应用的 WEB-INF/lib 文件夹中,这几个包的作用如下所示。

struts2-core-2.1.6.jar Struts 2 的核心库。 xwork-2.1.2.jar WebWork 的核心库,需要它的支持。 ognl-2.6.11.jar OGNL 表达式语言,Struts 2 支持该 EL 表达式。 freemarker-2.3.13.jar 表现层框架,定义了 Struts 2 的可视组件主题。 commons-logging-1.0.4.jar 日志管理。 commons-fileupload-1.2.1.jar 文件上传与下载。

由于 Struts 2 的版本不同,分发包中的目录结构以及类库可能不完全相同,不过

基本上都变化不大,读者可视具体情况而定。 至此 Struts 2 框架就被安装到 Web 项目中,然后就可以开始应用 Struts 2 框架进行 Web 开

发了。

1.3 Struts 2 第一个例子

本实例实现了一个简单的登录功能,用户打开

一个登录页面输入登录名称和登录密码,如果登录

名称和登录密码输入正确就进入欢迎页面,否则就

重新回到登录页面。图 1-4 所示为已经开发好的

Struts 2 第一个例子的目录结构图,将该项目命名

为 demo1。

图 1-4 demo1 的目录结构图

Struts 2 入门1 第 章

9

web.xml 文件存储在 WEB-INF 目录下,struts.xml 存储在 classes 目录下,lib 下存

储的是所必需的类库包,如 Struts 2 核心类库包等。

demo1 实例的工作流程如图 1-5 所示。

图 1-5 demo1 实例的工作流程

1.Struts 2 拦截用户请求

首先在 web.xml 文件中配置 Struts 2 的核心控制器,用来拦截客户端请求,并把请求转发

到相应的 Action 类来处理,如代码 1.1 所示。

代码 1.1 web.xml:配置 Struts 2 核心控制器

<?xml version="1.0" encoding="UTF-8"?> <web-app> <display-name>first Struts 2 Project</display-name> <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> </web-app>

2.创建视图页面 login.jsp

Struts 2 的标签库是 Struts 2 的重要组成部分,提供了既丰富又强大的功能,这些标签库不

仅为表现层提供了数据处理能力,而且也提供了基本的流程控制功能以及对国际化、Ajax 的

支持等诸多功能。通过使用 Struts 2 的标签库可以最大限度地减少视图页面的编码量。

login.jsp 使用 Struts 2 标签库实现了一个表单,如代码 1.2 所示。

模块一

Struts 2+Hibernate+Spring 整合开发技术详解

10

代码 1.2 login.jsp:使用 Struts 2 标签库实现一个表单

<%@ page language="java" pageEncoding="UTF-8"%> <%@ taglib prefix="s" uri="/struts-tags" %> <!--导入 Struts 2标签库--> <style type="text/css">*{font-size:12px;}</style> <html><body> <div style=" margin:30px 50px 20px 50px; text-align:center"> <div style="font-size:14px; font-weight:bold">用户登录</div> <div> <s:form action="checkLogin" namespace="/login"> <s:textfield name="username" style="font-size:12px;width: 120px;"

label="登录名称" /> <s:passwordname="password"style="font-size:12px;width:120px;"

label="登录密码" /> <s:submit value=" 登 录 " /> </s:form> </div> </div></body></html>

3.创建欢迎页面 index.jsp

index.jsp 为登录成功后显示的欢迎页面,代码如下所示: <%@ page language="java" pageEncoding="UTF-8"%> <html><body><div style="margin:40px; font-weight:bold"> 登录成功,欢迎您! </div></body></html>

4.创建业务控制器 LoginAction

上面两个页面文件是本实例的视图组件,现在来创建本实例的逻辑控制器组件 Action,如代码 1.3 所示。

代码 1.3 LoginAction 类:逻辑控制器组件

package act; import com.opensymphony.xwork2.ActionSupport; public class LoginAction extends ActionSupport{ private String username; //定义登录名称属性 private String password; //定义登录密码属性 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 checkLogin(){ //登录验证 if(this.username.equals("admin")&&this.password.equals("acc")) return SUCCESS; //登录成功返回 SUCCESS

Struts 2 入门1 第 章

11

else return LOGIN; //登录失败返回 LOGIN } }

5.配置 LoginAction

当 Action 处理完客户端请求后就会返回一个字符串,每个字符串都对应一个视图。 在 struts.xml 文件中配置 Action 时,用 name 属性定义该 Action 的名称,用 class 定义这

个 Action 的实际实现类,method 表示 checkLogin 这个 Action 由实际实现类 LoginAction 的

checkLogin()方法来处理。 配置 Action 时,为每个 Action 都指定了 result 元素,每个 result 元素都定义了一个逻辑视

图,而用 name 定义了 Action 所返回的字符串,如代码 1.4 所示。

代码 1.4 struts.xml:配置 LoginAction

<?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> <include file="struts-default.xml"/> <package name="struts2_login" extends="struts-default" namespace="/login"> <action name="checkLogin" class="act.LoginAction" method="checkLogin"> <result name="success">/index.jsp</result> <result name="login">/login.jsp</result> </action> </package> </struts> struts.xml 文件应放在 WEB-INF\classes 目录下,至此就创建了本实例的所有文件,把本实

例部署到 Tomcat 服务器上后打开 login.jsp 页面,在两个文本框中都输入 admin,如图 1-6 所示。 单击【登录】按钮,登录成功后会转向 index.jsp 页面,如图 1-7 所示。

图 1-6 登录页面 图 1-7 登录成功

1.4 Struts 2 各个部分的作用

上一节只讲述了如何实现一个 Struts 2 的登录实例,这一节将对这个实例进行剖析,其处

模块一

Struts 2+Hibernate+Spring 整合开发技术详解

12

理流程如下所示。 (1)在图 1-6 中单击【登录】按钮,向服务器提交登录请求。 (2)由于在 web.xml 文件中配置了 Struts 2 核心控制器 FilterDispatcher,此时 Struts 2 就会

拦截这个登录请求。 (3)由于表单的 action 值为 checkLogin,所以 FilterDispatcher 就会在 struts.xml 配置文件

中查找 name 为 checkLogin 的 Action 配置,找到后就会将已经拦截的登录请求转发给这个

LoginAction 来处理。 (4)由于在 struts.xml 配置文件中 Action 的 method 属性的值是 checkLogin,所以 LoginAction

就会调用自身的 checkLogin()方法完成对客户端的登录请求的处理。如果登录成功就返回

SUCCESS,登录失败就返回 LOGIN。

LoginAction 类的 SUCCESS 和 LOGIN 继承自 Struts 2 的 ActionSupport 类,分别

对应字符串 success 和 login。 (5)由于在 struts.xml 配置文件中配置 LoginAction 时指定了<result name = "success">/index.jsp

</result>,所以当 LoginAction 返回 success 时则转向 index.jsp 页面,否则转向 login.jsp 页面。 以上 5 步概述了上一节实现登录请求的处理流程,如图 1-8 所示。

图 1-8 处理流程

1.FilterDispatcher

FilterDispatcher 是 Struts 2 的核心控制器,负责拦截所有的客户端请求,作为一个 Filter通过 web.xml 文件被加入到了 Web 应用当中,当有客户端请求到达时,它就会进行拦截,然

后将客户端请求转发给响应的业务逻辑控制器 Action 进行处理。

2.struts.xml

struts.xml 文件是 Struts 2 框架的配置文件,主要负责配置业务逻辑控制器 Action,以及用

Struts 2 入门1 第 章

13

户自定义的拦截器等,可以说是 Struts 2 各个组件之间的纽带。FilterDispatcher 在拦截客户端

请求后就是通过读取 struts.xml 文件来决定该把客户端请求转发给哪个 Action 进行处理的。下

面是上一节实例的 struts.xml 文件的代码: <include file="struts-default.xml"/> <package name="struts2_login" extends="struts-default" namespace="/login"> <action name="checkLogin" class="act.LoginAction" method= "checkLogin"> <result name="success">/index.jsp</result> <result name="login">/login.jsp</result> </action> </package> 在上述代码中通过 include 标签引入了 struts-default.xml 这个文件,此文件是 Struts 2 默认

的核心配置文件,其中配置了 Struts 2 框架自身所提供的拦截器、类型转换器和数据校验等。

而在 Web 应用当中经常要用到这些拦截器、类型转换器、数据校验等组件,所以就先通过

include 标签引入了 struts-default.xml 这个文件。

3.Action

Action 是 Struts 2 的业务逻辑控制器,负责处理客户端请求并将处理结果输出给客户端。

要想处理客户端请求就必须获得请求字符串的参数或从表单提交的数据。 Struts 2 采用了 JavaBean 的风格,即要访问数据,就要给每个属性都提供一个 getter 和

setter 方法,要获得请求字符串的参数和表单提交的数据也是一样的道理。每一个请求字符串

的参数和从表单提交的数据都可以作为 Action 的属性,所以可以通过提供 setter 方法来获得请

求字符串的参数或从表单提交的数据。现在把上一节实例中的代码复制过来进行分析,下面是

登录页面 login.jsp 的表单代码: <s:form action="checkLogin" namespace="/login"> <s:textfield name="username" style="font-size:12px; width:120px;"label="登录名称"/> <s:password name="password" style="font-size:12px; width:120px;"label="登录密码"/> <s:submit value=" 登 录 " /></s:form> 表单中包含了一个用来输入登录名称的文本框,该文本框的 name 属性的值为 username,

包含了一个用来输入登录密码的密码文本框,该文本框的 name 属性的值为 password。 在代码 1.3 中,LoginAction 中有两个属性,一个是 username,一个是 password,分别对

应了登录页面表单中两个元素的 name 属性的值,还为这两个属性提供了 getter 和 setter 方法。

当客户端发送的表单请求被 FilterDispatcher 转发给该 Action 时,该 Action 就自动通过 setter方法获得从表单提交的数据信息。

4.视图组件

Action 在处理完客户端请求后会通过视图组件把处理结果显示出来,包括如下两种情况。 一种是 Action 向视图组件输出数据信息,然后由视图组件把这些数据信息显示出来,

例如 Action 执行了查询数据库的操作,并把查询到的数据输出给视图组件,然后由视

图组件把这些数据信息显示出来。 另一种是 Action 并没有向视图组件输出数据信息,只是根据处理结果进行简单的页面

模块一

Struts 2+Hibernate+Spring 整合开发技术详解

14

跳转。例如在上一节的实例中,当登录成功的时候就跳转到 index.jsp 页面;当登录失

败的时候就重新跳转到登录页面 login.jsp。 这些都是在 struts.xml 文件中进行配置的,如下所示: <result name="success">/index.jsp</result> <result name="login">/login.jsp</result> 通过上述代码可以看到在 Action 中配置了两个 result,即两个视图。一个是登录成功后的

视图,一个是登录失败后的视图。这里 result 的 name 属性的值与 Action 的返回值相对应。

Struts 2 除了支持传统的 JSP 视图外,也提供了对 FreeMarker、Velocity 等视图的

支持。 要想使用这些视图只需设置一下 result 的 type 属性即可,要使用 FreeMarker,就设置 type

属性的值为 freemarker,例如: <result name="success" type="freemarker">newsList.ftl</result> 要使用 Velocity 视图就设置 type 属性的值为 velocity,例如: <result name="success" type="velocity">newsList.vm</result>

1.5 配置 Struts 2

之所以使用框架,是因为框架可以为程序提供良好的管理机制。这样,开发者就可以脱离

繁杂的管理工作而专心于业务。然而框架是“死”的,不可能知道开发者的业务,只有开发者

把自己的业务注册给了框架,框架才知道自己要管理的资源是什么。对于 Struts 2 框架,开发

者通过配置文件把业务注册给框架(其实多数框架的原理都是这样的)。本章将详细介绍 Struts 2 中的 web.xml、struts.properties 文件的配置。

1.5.1 配置 web.xml

通常,所有的 MVC 框架都需要给 Web 应用加载一个核心控制器,对于 Struts 2 框架而言

也不例外,需要加载 FilterDispatcher,它就是 Struts 2 的核心控制器,只要 Web 应用加载了

FilterDispatcher,就可以获得整个 Struts 2 框架所提供的服务。 一旦理解了 Struts 2 框架被 Web 应用加载的原理,那么配置起来也就相当轻松了。在最简

单的情况下 web.xml 文件如代码 1.5 所示。

代码 1.5 web.xml

<web-app> <display-name>Struts 2 的配置</display-name> <filter> <filter-name>Struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.FilterDispatcher

Struts 2 入门1 第 章

15

</filter-class> </filter> <filter-mapping> <filter-name>Struts2</filter-name> <url-pattern>*</url-pattern> </filter-mapping> </web-app> <filter>元素用来指定要加载 Struts 2 框架的核心控制器 FilterDispatcher;<filter-mapping>

元素用来指定让 Struts 2 框架来处理用户的哪些请求(URL),当它的子元素<url-pattern>的值

为“*”时表示用户的所有请求都使用此框架来处理。

<filter>元素与<filter-mapping>元素都有一个子元素<filter-name>,它们的值可以

不必是“Struts 2”,但要求必须相同。 以上的配置是最简单的情况,其实当配置 FilterDispatcher 类时,还可以指定一系列的初始

化参数,其中两个初始化参数有特殊的意义。第一个是 actionPackages 参数,用来配置 Struts 2框架默认加载的 Action 包结构。参数的值是一个字符串类型的包空间,如果有多个包空间,

可以用英文(,)符号隔开,这样,Struts 2 框架将扫描指定的包空间下的所有 Action 类。配置

示例如下: <filter><init-param> <param-name>actionPackages</param-name> <param-value>my.test.action</parm-value> </init-param></filter> 第二个是 configProviders 参数。如果用户需要实现自己的 ConfigurationProvider 类,用户

可以提供一个或多个实现了 ConfigurationProvider 接口的类,然后将这些类的类名设置为该参

数的值,多个类名之间以英文逗号(,)隔开。配置示例如下: <filter><init-param> <param-name>configProviders</param-name> <param-value>lee.MyConfigurationProvider</param-value> </init-param></filter> 此外另有 config 参数,该参数的值是一个以英文逗号(,)隔开的字符串,每个字符串都

是一个 XML 配置文件的位置。Struts 2 框架将自动加载该属性指定的系列配置文件。还可在

此处配置 Struts 2 常量,每个<init-param>元素配置一个 Struts 2 常量,其中<param-name>子元

素指定了常量名,而<param-value>子元素指定了常量值。

1.5.2 配置 struts.properties

Struts 2 框架有两个核心配置文件:struts.xml 和 struts.properties。本节介绍的重点是

struts.properties 文件,struts.properties 文件用来定义 Struts 2 框架的一些属性,可以通过改变这

些属性来满足开发者的 Web 应用的需求。 struts.properties 文件是一个标准的 Properties 文件,该文件是由一系列的 key-value 对组成

模块一

Struts 2+Hibernate+Spring 整合开发技术详解

16

的,每个 key 就是一个 Struts 2 的属性,该 key 对应的 value 就是一个 Struts 2 的属性值。该文

件通常放在 Web 应用的 WEB-INF/classes 目录下,Struts 2 框架会加载这个文件。 下面将该文件的配置参数详细地列举出来。 struts.configuration 设置加载Struts 2配置文件的管理器。其默认值是org.apache.Struts2.

config.DefaultConfiguration,此为 Struts 2 默认的配置文件管理器。如果需要实现自己

的配置管理器,开发者则可以实现一个实现 Configuration 接口的类。 struts.locale 设置 Web 应用程序的默认 Locale。 struts.i18n.encoding 设置 Web 应用程序的默认编码集。此属性对于处理中文请求参

数很有用,对于获取中文请求参数值,应该将该属性值设置为 GBK 或者 GB2312。 struts.objectFactory 设置 Struts 2 默认的 ObjectFactory Bean,该属性的默认值是

spring。 struts.objectFactory.spring.autoWire 设置 Spring 框架的自动装配模式,该属性的默

认值是 name,即默认根据 Bean 的 name 属性自动装配。 struts.objectFactory.spring.useClassCache 设置整合 Spring 框架时,是否缓存 Bean实例,该属性只允许使用 true 和 false 两个属性值,默认值是 true。 struts.objectTypeDeterminer 设置 Struts 2 的类型检测机制,通常支持 tiger 和 notiger两个属性值。 struts.multipart.parser 设置处理 multipart/form-data 的 MIME 类型请求的框架,该

属性支持 cos、pell 和 jakarta 等属性值,即分别对应使用 cos 的文件上传框架、pell上传及 common-fileupload 文件上传框架。该属性的默认值为 jakarta。 struts.multipart.saveDir 设置上传文件的临时保存路径,该属性的默认值是

javax.servlet.context.tempdir。 struts.multipart.maxSize 设置 Struts 2 文件上传中整个请求内容允许的最大字节数。 struts.custom.properties 设置 Struts 2 应用加载用户自定义的属性文件,此自定义属

性文件指定的属性不覆盖在 struts.properties 文件中指定的属性。如果需要加载多个自

定义属性文件,多个自定义属性文件的文件名以英文逗号(,)隔开。 struts.mapper.class 设置将 HTTP 请求映射到指定 Action 的映射器,Struts 2 提供了

默认的映射器:org.apache.struts2.dispatcher.mapper.DefaultActionMapper。默认映射器

根据请求的前缀与 Action 的 name 属性完成映射。 struts.action.extension 设置需要 Struts 2 处理的请求后缀,该属性的默认值是 action,即所有匹配*.action 的请求都由 Struts 2 处理。如果用户需要指定多个请求后缀,则多

个后缀之间以英文逗号(,)隔开。 struts.serve.static 设置是否通过 JAR 文件提供静态内容服务,该属性只支持 true 和

false 属性值,该属性的默认值是 true。 struts.serve.static.browserCache 设置浏览器是否缓存静态内容。当应用处于开发阶

段时,如果希望每次请求都获得服务器的最新响应,则可设置该属性为 false。 struts.enable.DynamicMethodInvocation 设置 Struts 2 是否支持动态方法调用,该属

性的默认值是 true。如果需要关闭动态方法调用,则可设置该属性为 false。 struts.enable.SlashesInActionNames 设置 Struts 2 是否允许在 Action 名中使用斜线,

该属性的默认值是 false。如果开发者希望可以在 Action 名中使用斜线,则可设置该

Struts 2 入门1 第 章

17

属性为 true。 struts.tag.altSyntax 指定是否允许在 Struts 2 标签中使用表达式语法,因为通常都需

要在标签中使用表达式语法,故此属性应该设置为 true,该属性的默认值是 true。 struts.devMode 设置 Struts 2 应用是否使用开发模式。如果设置该属性为 true,则可

以在应用出错时显示更多、更友好的出错提示。该属性只接受 true 和 false 两个值,

该属性的默认值是 false。通常,在开发阶段,将该属性设置为 true,当进入产品发布

阶段后,则将该属性设置为 false。 struts.i18n.reload 设置是否每次 HTTP 请求到达时,系统都重新加载资源文件。该

属性的默认值是 false。在开发阶段将该属性设置为 true 会更有利于开发,但在产品发

布阶段应将该属性设置为 false。 struts.ui.theme 指定视图标签默认的视图主题,该属性的默认值是 xhtml。 struts.ui.templateDir 指定视图主题所需要模板文件的位置,该属性的默认值是

template,即默认加载 template 路径下的模板文件。 struts.ui.templateSuffix 指定模板文件的后缀,该属性的默认值是 ftl。该属性还允许

使用 ftl、vm 或 jsp,分别对应 FreeMarker、Velocity 和 JSP 模板。 struts.configuration.xml.reload 设置当 struts.xml 文件改变后,系统是否自动重新加

载该文件。该属性的默认值是 false。 struts.velocity.configfile 设置 Velocity 框架所需的 velocity.properties 文件的位置。该

属性的默认值为 velocity.properties。 struts.velocity.contexts 设置 Velocity 框架的 Context 位置,如果该框架有多个

Context,则多个 Context 之间以英文逗号(,)隔开。 struts.velocity.toolboxlocation 设置 Velocity 框架的 toolbox 的位置。 struts.url.http.port 设置 Web 应用所在的监听端口。该属性通常没有太多的用户,只

是当 Struts 2 需要生成 URL 时(例如 URL 标签),该属性才提供 Web 应用的默认端口。 struts.url.https.port 作用类似于 struts.url.http.port 属性,区别是该属性指定的是 Web应用的加密服务端口。 struts.url.includeParams 指定 Struts 2 生成 URL 时是否包含请求参数。该属性接受

none、get 和 all 这 3 个属性值,分别对应于不包含、仅包含 GET 类型请求参数和包

含全部请求参数。 struts.custom.i18n.resources 指定 Struts 2 应用所需要的国际化资源文件,如果有多

份国际化资源文件,则多个资源文件的文件名以英文逗号(,)隔开。 struts.dispatcher.parametersWorkaround 对于某些 Java EE 服务器,不支持

HttpServlet Request 调用 getParameterMap()方法,此时可以设置该属性值为 true 来解

决该问题。该属性的默认值是 false。对于 WebLogic、Orion 和 OC4J 服务器,通常应

该设置该属性为 true。 struts.freemarker.manager.classname 指定 Struts 2 使用的 FreeMarker 管理器。该属

性的默认值是 org.apache.struts2.views.freemarker.FreemarkerManager,这是 Struts 2 内

建的 FreeMarker 管理器。 struts.freemarker.wrapper.altMap 只支持 true 和 false 两个属性值,默认值是 true。通常无须修改该属性值。

模块一

Struts 2+Hibernate+Spring 整合开发技术详解

18

struts.xslt.nocache 指定 XSLT Result 是否使用样式表缓存。当应用处于开发阶段时,

该属性通常被设置为 true;当应用处于产品使用阶段时,该属性通常被设置为 false。 struts.configuration.files 指定 Struts 2 框架默认加载的配置文件,如果需要指定默认

加载多个配置文件,则多个配置文件的文件名之间以英文逗号(,)隔开。该属性的默

认值为 struts-default.xml、struts-plugin.xml、struts.xml,看到该属性值,读者应该就能

明白为什么 Struts 2 框架默认加载 struts.xml 文件了。

其实,struts.properties 文件的内容均可在 struts.xml 中以<constant name = "" value = ""></constant>加载(使用常量)。struts.xml 将在下一节中详细介绍。

1.6 配置 struts.xml

struts.xml 文件主要负责管理 Web 应用中业务控制器 Action 的映射,以及 Action 包含的

result 定义,还有 Bean 的配置、常量的配置、包的配置和拦截器的配置等。在默认情况下,

Struts 2 会自动加载 Web 应用 WEB-INF/classes 目录下的 struts.xml 文件,并对文件中配置的资

源进行扫描。

1.6.1 文件结构

前面几节中对 struts.xml 的配置方法做过简单介绍,例如 Action 配置,但是并不全面,其

大概结构如代码 1.6 所示。

代码 1.6 struts.xml 基本结构

<?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> <constant name="struts.i18n.reload" value="false" /> <!-- 常量配置 --> <constant name="struts.devMode" value="false" /> <!--常量配置 --> <include file="struts-chat.xml" /> <!--包含文件的配置--> <include file="struts-hangman.xml" /> <!--包含文件的配置--> <package name="default" extends="struts-default"> <!--包的配置--> <interceptors> <!--拦截器的配置--> <interceptor-stack name="crudStack"> <interceptor-ref name="checkbox" /> <interceptor-ref name="params" /> </interceptor-stack> </interceptors> <action name="showcase"> <!--Action的配置--> <result>showcase.jsp</result> </action> </package>

Struts 2 入门1 第 章

19

<!--Bean的配置--> <bean type="org.apache.struts2.viw=ews.TagLibrary" class="com.company.my.

ObjectFactory"name="myFactory" scope="default" /> </struts>

在 struts.xml 文件中,有很多元素是可以重复的,以配置不同的内容,代码 1.6 中

只给出示例。

1.6.2 Bean 配置

Struts 2 是一个具有高度可扩展性的框架,其大部分的核心组件都不是以直接编码的方式

写在代码中的,而是通过一个配置文件来注入到框架中的。这样,就使得这些核心组件具有可

插可拔的功能,降低了代码的耦合度。 通过在 struts.xml 文件中配置 Bean,把核心组件的一个实例注入到框架中。当向框架注入

一个核心组件的实例时,还需要告诉框架这个实例的作用,也就是说告诉框架注入的此组件实

现了哪个接口(接口通常用于定义注入的组件必须遵守的规范)。例如,需要在框架中注入自

定义组件,可以使用如下形式的代码: <struts> <bean type="组件实现的接口" name="Bean实例的名字" class="自定义组件" /> </struts> 其实,Bean 除了可以向框架注入一个核心组件的实例外,还可以为框架注入一个静态方

法或者常量,这样,不用创建 Bean 的实例,就可以获得方法或常量。在这种情况下,通常要

设置<bean>元素的 static 属性值为 true。配置形式如下: <struts> <bean class="自定义类" static="true" /> </struts> 此外,<bean>元素的一些常用属性如下。 class 这是一个必需的属性,用来指定此配置的 Bean 对应的实现类。 name 这是一个可选的属性,用来指定 Bean 实例的名字,对于相同类型的多个 Bean,它们的 name 值不允许相同。 type 这是一个可选的属性,用来指定 Bean 实例实现的 Struts 2 的规范,如果配置的

Bean 作为框架的一个核心组件来使用,那么就应该指定这个属性的值。 scope 这是一个可选的属性,用来指定 Bean 实例的作用范围,其值只能是 default、

singleton、request、session 与 thread 之一。 static 这是一个可选属性,用来指定 Bean 是否使用静态方法注入,通常,当指定了

type 属性后,就不应该再把此属性设置为 true 了。 optional 用来指定 Bean 是否是一个可选的 Bean。

1.6.3 常量配置

通过 struts.xml 文件中的常量配置,可以指定 Struts 2 框架的属性。其实这些属性也可以

模块一

Struts 2+Hibernate+Spring 整合开发技术详解

20

在其他配置文件中指定,例如在 web.xml 配置文件的<init-param>元素中可以指定常量; struts.properties 配置文件中的内容均可在 struts.xml 中加载(使用常量),反过来也就是说,

struts.xml 文件的常量也可在 struts.properties 配置文件中配置。

Struts 2 扫描常量的顺序是:struts.xml、struts.properties、web.xml,所以,如果在

这 3 个文件中对某个变量有重复的配置,则后一个文件中配置的常量值总会覆盖

前一个文件常量的值。 常量在 struts.xml 文件中通过 constant 元素来配置,看如下代码片段: <struts> <!-- 一些常量的配置 --> <constant name="struts.i18n.encoding" value="GBK" /> <constant name="struts.devMode" value="false" /> </struts> 在这里配置常量需要指定如下两个必需的属性。 name 用来指定常量的名称。 value 用来指定常量的值。

例如:在上述的代码片段中,设置 Web 应用的默认编码集为 GBK。每一个常量都使用

<constant name="???" value="???" />来指定,非常方便。 尽管常量在 struts.xml、web.xml 文件中都可以配置,但是,Struts 2 之所以允许使用

struts.properties 来配置常量,主要是为了保持与 WebWork 向后的兼容性;而在 web.xml 文件

中定义常量,需要的代码量较多,会降低文件的可读性。所以在通常情况下建议在 struts.xml文件中集中配置常量。

1.6.4 包配置

通过包的配置,可以实现对某包中的所有 Action 的统一管理,如权限的限制等。在

struts.xml 文件中包是通过 package 元素来配置的,如代码 1.7 所示。

代码 1.7 包配置示例

<struts> <package name="default" extends="struts-default"> <!--包的配置--> <interceptors> <!--拦截器的配置--> <interceptor-stack name="crudStack"> <interceptor-ref name="checkbox" /> <interceptor-ref name="params" /> </interceptor-stack> </interceptors> <action name="showcase"> <!--Action的配置--> <result>showcase.jsp</result> </action> </package> </struts> 可以看到在包元素里面有大量 Action 和拦截器集合,其实,Struts 2 框架就是使用包来管

Struts 2 入门1 第 章

21

理 Action 与拦截器的。配置包时必须指定 name 属性,只有指定了这个属性后此包才可以被引

用,extends 属性用来指定该包继承其他的包,它的值必须是另一个包的 name。这样,通过继

承,子包就可以继承父包在配置的拦截器、action 等。上述代码片段定义了一个名为 default的包,继承了 Struts 2 框架的默认包:struts-default。配置 package 元素时可以指定如下属性。

name 是一个必需的属性,指定包的名字,是被其他包继承的 key。 extends 是一个可选的属性,指定要继承的包,通过继承就可以继承在其他包中定义

的 action、拦截器等。 namespace 是一个可选的属性,定义该包的命名空间。 abstract 是一个可选的属性,指定该包是否是一个抽象包,如果是一个抽象包,那

么就不能在此包中定义 action 了。

1.6.5 命名空间配置

在前几节的小例子中,在 struts.xml 文件中配置了 Action,并没有关心命名空间的问题,

这是因为需要配置的 Action 很少,没有必要关心 Action 的重名问题。但是,如果是在一个大

系统中,需要配置的 Action 可能会变得数不胜数,而且系统是由多个开发人员合作开发的,

此时 Action 就有很大的几率出现重名的问题。为了解决这个问题,命名空间的概念就被提出

来了。Struts 2 并不支持为单独的 Action 设置命名空间,而是通过为 Action 所在的包指定

namespace 属性来为该包下的所有 Action 指定共同的命名空间。 把下载的 Struts 2 分发包解压后,可以找到 apps 文件夹,这下面放置的是一些 struts 2 框

架的 Web 应用的例子,在此文件夹下找到 struts2-showcase-2.1.6.war 这个 Web 应用的 struts.xml配置文件,打开后如代码 1.8 所示。

代码 1.8 命名空间配置示例

<struts> <package name="default" extends="struts-default"> <interceptors> <interceptor-stack name="crudStack"> <interceptor-ref name="checkbox" /> <interceptor-ref name="params" /> <interceptor-ref name="static-params" /> <interceptor-ref name="defaultStack" /> </interceptor-stack> </interceptors> <action name="showcase"> <result>showcase.jsp</result> </action> <action name="viewSource" class="org.apache.struts2.showcase.source.

ViewSourceAction"> <result>viewSource.jsp</result> </action> <action name="date" class="org.apache.struts2.showcase.DateAction"

method="browse"> <result name="success">/date.jsp</result> </action>

模块一

Struts 2+Hibernate+Spring 整合开发技术详解

22

</package> <package name="skill" extends="default" namespace="/skill"> <default-interceptor-ref name="crudStack"/> <action name="list" class="org.apache.struts2.showcase.action.

SkillAction" method="list"> <result>/empmanager/listSkills.jsp</result> <interceptor-ref name="basicStack"/> </action> <action name="edit" class="org.apache.struts2.showcase.action.

SkillAction"> <result>/empmanager/editSkill.jsp</result> <interceptor-ref name="params" /> <interceptor-ref name="basicStack"/> </action> <action name="save" class="org.apache.struts2.showcase.action.

SkillAction" method="save"> <result name="input">/empmanager/editSkill.jsp</result> <result type="redirect">edit.action?skillName=${currentSkill.

name}</result> </action> <action name="delete" class="org.apache.struts2.showcase.action.

SkillAction" method="delete"> <result name="error">/empmanager/editSkill.jsp</result> <result type="redirect">edit.action?skillName=${currentSkill.

name}</result> </action> </package> </struts> 代码片段显示在 struts.xml 文件中配置了两个包:default 与 skill。当配置 skill 包时为此包

指定了 namespace 属性,如果没有指定该属性,则表示使用的是默认的命名空间:""。当为包

指定了命名空间后,那么此包下的所有 Action 处理的 URL 就应该是“命名空间+Action”,如

包 skill 下名为 list 的 Action 处理的 URL 为: http://localhost:8080/ struts2-showcase-2.0.11.1/skill/list.action

在上述的 URL 中,8080 为 Tomcat 端口号,struts2-showcase-2.1.6.war 为 Struts 分发包中例子的 Web 应用。

这样,通过为包指定不同的命名空间,就算在不同的包中配置了 name 相同的 Action,框

架依然可以根据请求的 URL 知道使用哪个 Action 来处理。如果为一个包指定了默认的命名空

间,那么此包下的所有 Action 就可以处理任何 URL 中相应的 Action 请求,例如如下配置: <struts><package name="test" extends="struts-default"> <action name="login" class="my.test.LoginAction"> <result "successs">welcome.jsp</result> <result "error">error.jsp</result> </action> </package></struts> 这样,name 为 login 的 Action 就可以处理如下的请求 URL:

Struts 2 入门1 第 章

23

http://localhost:8080/struts/login.action 也可以处理如下的请求 URL: http://localhost:8080/struts/acc/login.action 总之,所有最后名为“/login.action”的 URL 请求都可以处理。这样问题又出来了,假如

struts.xml 有如代码 1.9 所示的配置。

代码 1.9 struts.xml 配置示例

<struts> <package name="test" extends="struts-default"> <action name="login" class="my.test.LoginAction"> <result "successs">welcome.jsp</result> <result "error">error.jsp</result> </action> </package> <package name="test2" extends="struts-default" namespace="/acc"> <action name="login" class="my.test.LoginAction2"> <result "successs">welcome.jsp</result> <result "error">error.jsp</result> </action> </package> </struts> 此时使用如下的 URL 请求: http://localhost:8080/struts/acc/login.action 那么这个请求是会被 test包下的name为 login的Action处理呢,还是会被 test2包下的name

为 login 的 Action 处理呢?其实,当请求到来的时候,Struts 2 框架首先会到命名空间为“/acc”的包下去寻找有没有对应的 Action,如果有,则使用寻找到的 Action 来处理;如果没有,框

架才会到默认命名空间下去寻找对应的 Action,如果寻找到对应的 Action 就使用此 Action 来

处理,否则框架会报错。框架是不会直接到默认的包下去寻找 Action 的。 另外值得一提的是根命名空间,当为一个包的 namespace 属性指定值为“/”时,那么这

个命名空间就是根命名空间,根命名空间与一般的命名空间没有什么区别,只是使用了根命名

空间的包下的 Action 只能处理形如“/XX.action”的 URL 请求,例如: http://localhost:8080/struts/login.action 与默认命名空间有区别,它不能处理如下的 URL 请求: http://localhost:8080/struts/acc/login.action

1.6.6 包含配置

观察下载好的 Struts 2 框架附带实例中的 struts.xml 文件时,读者可能已经发现,大部分

文件并不是像人们想象的那样:把大量的 Action、Bean、常量、拦截器等都配置在 struts.xml文件中,使此文件变得臃肿而复杂。相反,struts.xml 文件中并不是大量的 Action、package 等

模块一

Struts 2+Hibernate+Spring 整合开发技术详解

24

元素,取而代之的却是一些简短清晰的 include 元素,甚至在一些情况下,仅有一些 include元素。例如,在 Struts 2 附带的例子中有一个 struts2-portlet-2.1.6.war 的例子,找到其 struts.xml文件打开后,内容如代码 1.10 所示。

代码 1.10 包含配置示例

<?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> <include file="struts-view.xml"/> <include file="struts-edit.xml"/> <include file="struts-help.xml"/> </struts> Struts 2 框架允许使用 include 元素在 struts.xml 文件中包含其他配置文件,这样,就可以

把大量的配置按照模块划分,分而治之,配置在多个 XML 文件中,当框架自动加载 struts.xml文件时,也同时加载了其他被包含的文件,这样就大大提高了 struts.xml 文件的可读性,减少

了维护的麻烦。 要在 struts.xml 文件中包含其他文件,只需为 include 元素指定其 file 属性值即可,这个值

就是一个简单的被包含的文件名,在通常情况下,被包含的文件与 struts.xml 文件一样被放置

在站点的 WEB-INF/classes 目录下。