SSH Chapter 09 Struts2 配置详解
本章目标 :
- 掌握
Struts 2
的基本架构 - 掌握
Struts 2
的各项内容 - 掌握
action
元素和result
元素的配置
1 . Struts 2 执行过程解析
在之前的学习过程中 , 我们使用Struts 2
框架实现用户登录功能 , 使用Struts 2
标签和OGNL
表达式简化了视图的开发 , 利用Struts 2
提供的特性对输入数据进行验证 , 以及访问Servlet API
实现用户会话跟踪 , 其简单的运行流程如图所示 .
下面通过分析登录程序 , 带领大家深入了解Strut 2
.
1.1 分析登录程序
为了实现用户登录的功能 , 需要经过一下几个步骤 :
- 获取
Struts 2
资源 - 在应用程序中导入
Struts 2
的类库 - 在
web.xml
文件中配置StrtusPrepareAndExecuteFilter
- 编写
Action
类并进行配置 - 配置返回结果与物理视图资源的关系
- 编写结果视图
众所周知 , Struts 2
框架是基于MVC
模式的 . 基于MVC
模式框架的核心就是控制器对所有请求进行统一处理 . Struts 2
的控制器StrutsPrepareAndExecuteFilter
由Servlet API
中的Filter
充当 , 当Web
容器接受到登录请求后 , 将请求交由在Web.xml
中配置的过滤器StrutsPrepareAndExecuteFilter
.
我们首先来看StrutsPrepareAndExecuteFilter
的配置 .
1. web.xml
:
任何一个Web
应用程序都是基于请求/响应模式进行构建的 , 无论采用哪种MVC
框架 , 都离不开web.xml
文件的配置 . 换句话说:web.xml
并不是Struts 2
框架特有的文件 , 只有在Web
应用中配置了web.xml
文件 , MVC
框架才能真正的与Web
应用融合起来 . 因此 , web.xml
文件是所有Java Web
应用程序都需要的核心文件。
Struts 2
框架需要在web.xml
中配置其核心控制器 ---- StrutsPrepareAndExecuteFilter
, 用于对框架进行初始化 , 以及处理所有的请求 . 对StrutsPrepareAndExecuteFilter
的配置如示例1所示:
示例1:
<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0"
metadata-complete="true">
<!--Struts2 配置-->
<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
StrutsPrepareAndExecuteFilter
可以包含一些初始化参数 , 经常使用的如config
—要加载的xml
形式的配置文件列表(多个配置文件以逗号分隔) , 如果没有设置这个参数 , Struts 2
框架将默认加载struts-default.xml , struts-plugin.xml 和 struts.xml
, 这些配置文件将在后面的内容中进行讲解 .
StrutsPrepareAndExecuteFilter
作为一个Filter
在Web
应用中运行 , 它负责拦截所有的用户请求 , 当用户请求到达时 , 该Filter
会过滤用户请求 . 如果用户以".action"
结尾 , 该请求将被输入Struts 2
框架进行处理 .
2. Action
:
实际上 , 在Struts 2
框架中 , 控制器是由两个部分组成 , 分别如下:
- 核心控制器(Filter) : 用于拦截用户请求 , 对请求进行处理
- 业务控制器(Action) : 调用相应的
Model
类来实现业务处理 , 返回结果
对开发人员来说 , 使用
Struts 2
框架 , 主要编码工作就是编写Action
类 .
在之前学习工程中我们介绍了com.opensymphony.xwork2.Action
接口和com.opensymphony.xwork2.ActionSupport
类 .
Struts 2
并不要求编写Action
类定义要实现Action
接口 , 可以编写一个普通的Java
类作为Action
类 , 只要该类含有一个返回字符串的无参的public
方法即可.
在实际开发中 , Action
类通常都继承自Struts2
提供的com.opensymphony.xwork2.ActionSuppor
t类 , 以便简化开发.
问答:
问题:Action
是如何获取用户请求并进行处理的?
解答:回想一下再学习Servlet
时,Servlet
是如何实现业务控制的 . 用户提交请求后 , 各种业务并没有在Servlet
中直接完成 , 而是通过调用不同的JavaBean
组件来实现的 . 在Struts 2
中也是如此 , Filter
用来接收用户的请求 , 在对数据进行简单处理后创建Action
实例 , 然后调用Action
的方法 . 而Action
实例的创建就由struts.xml
中的配置来决定
开发完成一个Action
类后 , 就需要在struts.xml
中配置Action
了 . 处理登录的Action
类 , 配置代码如示例2所示:
示例2:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<!--设置用户界面主题 , 默认值为XHTML风格-->
<constant name="struts.ui.theme" value="simple"/>
<package name="deafault" namespace="/" extends="struts-default">
<action name="login" class="cn.strutsdemo.action.LoginAction">
<!--返回结果为success时,跳转到success.jsp-->
<result name="success">success.jsp</result>
<!--返回结果为error时,跳转到fail.jsp-->
<result name="error">fail.jsp</result>
<!--返回结果为input时,即校验结果失败,跳转到登录页面-->
<result name="input">login.jsp</result>
</action>
</package>
</struts>
在配置文件中将一个请求的URL(action的名字)
对应到一个Action
类 , 当一个请求匹配到某个Action
名字时 , 框架就会使用这个Action
类处理请求 . action
元素中的name
属性是必需的 , 表示action
名字 , 用于匹配请求的URL
. class
属性表示Action
类的全限定类名 , 即决定该action
的实现类 .
3. Result
:
result
元素的作用是实现结果视图的调用,并决定视图以哪种形式展示给客户端。简单地说,就是用来设定在Action
处理结束后,系统下一步将要做什么。
Action
类在处理完用户请求后,会返回一个处理结果。这个结果是一个简单的字符串,框架根据这个字符串选择对应的Result
,所以我们又将称为逻辑视图名称。
这个逻辑视图名称由result
元素的name
属性来表示。result
元素的值用来指定这个逻辑视图对应的物理视图资源的位置。
需要特别指出的是,逻辑视图名称只有与物理视图资源联系在一起,才能发挥作用,所以必须要在配置文件中设置二者之间的对应关系。
通过对Struts 2
执行过程的分析 , 可以发现Struts 2
应用的整个过程都是按照请求/响应的过程执行的 , 这个过程如下所示:
- 当
Web
容器接收到请求之后 , 将请求交由在web.xml
中配置的Struts 2
框架的控制器StrutsPrepareAndExecuteFilter(核心控制器)
. - 由
StrutsPrepareAndExecuteFilter(核心控制器)
确定请求对应的Action(业务控制器)
. - 框架根据
Action
返回的结果字符串 , 由StrutsPrepareAndExecuteFilter(核心控制器)
选择对应的result
, 将结果呈现给用户 .
注意:
(1) Action 作为业务控制器 , 只负责返回结果 , 而不与视图相关联 , 这样做的优势在于 , 当视图发生变化时 , 无须修改Action
类的代码 , 仅需要修改配置文件即可.
(2) 当StrutsPrepareAndExecuteFilter(核心控制器)
调用相应的视图时 , 默认采用转发形式跳转到指定的JSP
页面 , 其他跳转形式将在下文中介绍
在学习这部分内容的过程中 , 涉及很多Struts 2
的配置 , 下面将详细介绍Struts 2
的配置文件
1.2 Struts 2
的配置文件
1. struts.xml
Struts 2
的核心配置文件就是struts.xml
配置文件 , 由开发人人员编写 , 包含action
,result
等配置 , 主要负责管理Struts 2
框架的业务控制器Action
.
一个典型的struts.xml
文件代码如下示例3所示:
示例3
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<constant name="" value=""/>
<package name="" namespace="" extends="">
<action name="" class="">
<result name=""></result>
</action>
</package>
</struts>
首先了解constant
元素 . constant
元素用于配置常量 , 通过常量的配置 , 可以改变Struts 2
框架的一些行为 , 从而满足不同应用的需求 .
constant
元素包含两种属性 , 其中name
属性表示常量的名称 , value
属性表示常量的值 .
**资料:**处理中文乱码问题时 , 可以通过在struts.xml
中设置常量的方式解决 .
<constant name="struts.i18n.encoding" value="UTF-8"/>
可配置的常量均在struts2-core-2.5.16.jar
下的org/apache/struts2/default.properties
文件中找到 , 部分常量会在下面讲解 .
通过<constant>
元素是配置常量的一种方式 , 另外一种方式是在源文件根目录下创建struts.properties
来覆盖default.properties
中的设置 , 格式和default.properties
相同 , 都属于properties
文件.
constant
元素中的name
属性与value
属性介绍如下:
<!-- 指定Web应用的默认编码集,相当于调用 HttpServletRequest的setCharacterEncoding方法 -->
<constant name="struts.i18n.encoding" value="UTF-8" />
<!-- 该属性指定Struts 2应用所需要的国际化资源文件,如果有多份国际化资源文件,则多个资源文件的文件名以英文逗号(,)隔开 -->
<constant name="struts.custom.i18n.resources" value="application"/>
<!-- 默认的国际化地区信息 -->
<constant name="struts.locale" value="zh_CN"/>
<!-- 该属性设置是否每次HTTP请求到达时,系统都重新加载资源文件。该属性默认值是false。
在开发阶段将该属性设置为true会更有利于开发, 但在产品发布阶段应将该属性设置为false。 -->
<constant name="struts.i18n.reload" value="false"/>
<!-- 该属性指定需要Struts 2处理的请求后缀,该属性的默认值是action,即所有匹配*.action的请求都由Struts 2处理。
如果用户需要指定多个请求后缀,则多个后缀之间以英文逗号(,)隔开。 -->
<constant name="struts.action.extension" value="action" />
<!-- 当struts 2的配置文件修改后,系统是否自动重新加载该文件,默认值为false,开发阶段最好打开 -->
<constant name="struts.configuration.xml.reload" value="false" />
<!-- 该属性指定Struts 2框架默认加载的配置文件,如果需要指定默认加载多个配置文件,
则多个配置文件的文件名之间以英文逗号(,)隔开。该属性的默认值为struts- default.xml,struts-plugin.xml, struts.xml,
看到该属性值,读者应该明白为什么Struts 2框架默认加载struts.xml文件了。 -->
<constant name="struts.configuration.files" value="struts-default.xml,struts-plugin.xml,struts.xml"/>
<!-- 指定加载struts2配置文件管理器,默认为org.apache.struts2.config.DefaultConfiguration,
开发者可以自定义配置文件管理器,该类要实现Configuration接口,可以自动加载struts2配置文件。 -->
<constant name="struts.configuration" value="org.apache.struts2.config.DefaultConfiguration"/>
<!-- 含有Actions的完整连续的package名称。 -->
<constant name="struts.continuations.package" value=""/>
<!-- 该属性设置浏览器是否缓存静态内容。当应用处于开发阶段时,我们希望每次请求都获得服务器的最新响应,
所以最好关闭,可设置该属性为false。 默认值为true-->
<constant name="struts.serve.static.browserCache" value="false"/>
<!-- 该属性设置Struts 2是否支持动态方法调用,该属性的默认值是false。如果需要关闭动态方法调用,则可设置该属性为false。 -->
<constant name="struts.enable.DynamicMethodInvocation" value="false"/>
<!-- 该属性设置Struts 2是否允许在Action名中使用斜线,该属性的默认值是false。
如果开发者希望允许在Action名中使用斜线,则可设置该属性为true。 -->
<constant name="struts.enable.SlashesInActionNames" value="false"/>
<!-- 该属性指定是否允许在Struts 2标签中使用表达式语法,因为通常都需要在标签中使用表达式语法,
故此属性应该设置为true,该属性的默认值是true。 -->
<constant name="struts.tag.altSyntax" value="true"/>
<!-- 该属性设置Struts 2应用是否使用开发模式。如果设置该属性为true,则可以在应用出错时显示更多、更友好的出错提示。
该属性只接受true和flase两个值,该属性的默认值是false。
通常,应用在开发阶段,将该属性设置为true,当进入产品发布阶段后,则该属性设置为false。 -->
<constant name="struts.devMode" value="false"/>
<!-- 该属性指定视图标签默认的视图主题,该属性的默认值是xhtml,可以为simple,xhtml或ajax。 -->
<constant name="struts.ui.theme" value="xhtml"/>
<!-- 该属性指定视图主题所需要模板文件的位置,该属性的默认值是template,即默认加载template路径下的模板文件。 -->
<constant name="struts.ui.templateDir" value="template"/>
<!-- 该属性指定模板文件的后缀,该属性的默认属性值是ftl。该属性还允许使用ftl、vm或jsp,
分别对应FreeMarker、 Velocity和JSP模板。 -->
<constant name="struts.ui.templateSuffix" value="ftl"/>
<!-- 该属性指定Velocity框架所需的velocity.properties文件的位置。该属性的默认值为 velocity.properties。 -->
<constant name="struts.velocity.configfile" value="velocity.properties"/>
<!-- 该属性指定Velocity框架的Context位置,如果该框架有多个Context,则多个Context之间以英文逗号(,)隔开。 -->
<constant name="struts.velocity.contexts" value=""/>
<!-- 该属性指定Velocity框架的toolbox的位置。 -->
<constant name="struts.velocity.toolboxlocation" value=""/>
<!-- 该属性指定Web应用所在的监听端口。该属性通常没有太大的用处,就拿Tomcat服务器举个例子,监听端口取决于Tomcat的
conf/server.xml配置文件,而非该struts 2 常量,
只是当Struts 2需要生成URL时(例如Url标签),该属性才提供Web应用的默认端口。 -->
<constant name="struts.url.http.port" value="80"/>
<!-- 该属性类似于struts.url.http.port属性的作用,区别是该属性指定的是Web应用的加密服务端口。 -->
<constant name="struts.url.https.port" value="443"/>
<!-- 该属性指定Struts 2生成URL时是否包含请求参数。该属性接受none、get和all三个属性值,
分别对应于不包含、仅包含GET类型请求参数和包含全部请求参数。 -->
<constant name="struts.url.includeParams" value="none|get|all"/>
<!-- 对于某些Java EE服务器,不支持HttpServletRequest调用getParameterMap()方法,
此时可以设置该属性值为true来解决该问题。该属性的默认值是false。
对于 WebLogic、Orion和OC4J服务器,通常应该设置该属性为true。 -->
<constant name="struts.dispatcher.parametersWorkaround" value="false"/>
<!-- 该属性指定Struts 2使用的FreeMarker管理器。
该属性的默认值是org.apache.struts2.views.freemarker.FreemarkerManager,
这是 Struts 2内建的FreeMarker管理器。 -->
<constant name="struts.freemarker.manager.classname" value=""/>
<!-- 该属性只支持true和false两个属性值,默认值是true。通常无需修改该属性值。 -->
<constant name="struts.freemarker.wrapper.altMap" value="true"/>
<!-- 设置是否对freemarker的模板设置缓存,效果相当于把template拷贝到 WEB_APP/templates. -->
<cosntant name="struts.freemarker.templatesCache" value="false" />
<!-- 该属性指定XSLT Result是否使用样式表缓存。当应用处于开发阶段时,该属性通常被设置为true;
当应用处于产品使用阶段时,该属性通常被设置为false。 -->
<constant name="struts.xslt.nocache" value="false"/>
<!-- 指定Struts2应用加载用户自定义的属性文件,该自定义属性文件指定的属性不会覆盖struts.properties文件中指定的属性。
如果需要加载多个自定义属性文件,多个自定义属性文件的文件名以英文逗号(,)隔开。(也就是说不要改写struts.properties!) -->
<constant name="struts.custom.properties" value="application,org/apache/struts2/extension/custom"/>
<!-- 指定请求url与action映射器,默认为org.apache.struts2.dispatcher.mapper.DefaultActionMapper -->
<constant name="struts.mapper.class" value="org.apache.struts2.dispatcher.mapper.DefaultActionMapper"/>
<!-- 设定是否一直在最后一个slash之前的任何位置选定namespace -->
<cosntant name="struts.mapper.alwaysSelectFullNamespace" value="false" />
<!-- multipart请求信息的最大尺寸(文件上传用,该属性指定Struts 2文件上传中整个请求内容允许的最大字节数)。 -->
<constant name="struts.multipart.maxSize" value="2097152"/>
<!-- 该属性指定处理 MIME-type multipart/form-data,文件上传(cos、pell、jakarta)
专为multipart请求信息使用的org.apache.struts2.dispatcher.multipart.MultiPartRequest解析器接口(文件上传用)。 -->
<constant name="struts.multipart.parser" value="cos"/>
<!-- 指定上传文件时的临时目录,默认使用 javax.servlet.context.tempdir。文件上传的时候都会先在服务器创建缓存 -->
<constant name="struts.multipart.saveDir" value="/tmpuploadfiles"/>
<!-- 该属性指定Struts 2中的Action由Spring容器创建。 -->
<constant name="struts.objectFactory" value="spring" />
<!-- 指定spring框架的装配模式,装配方式有: name, type, auto, and constructor (name 是默认装配模式) -->
<constant name="struts.objectFactory.spring.autoWire" value="name"/>
<!-- 该属性指定整合spring时,是否对bean进行缓存,值为true or false,默认为true。 -->
<constant name="struts.objectFactory.spring.useClassCache" value="true"/>
<!-- 指定类型检查,包含tiger和notiger -->
<cosntant name="struts.objectTypeDeterminer" value="tiger" />
<!--配置静态资源的路径-->
<constant name="struts.action.excludePattern" value="/static/.*?" />
下面了解package
元素 . Struts 2
框架会把action
,result
等组织在一个名为package(包)
的逻辑单元中 , 从而简化维护工作 , 提高重用性 . 每个包都包含了将要用到的action
,result
等的定义 .
Struts 2
中的包很像Java
中的包 , 但与Java
包不同的是 ,Struts 2
中的包可以"继承"
已经定义好的包 , 从而继承原有包的所有定义(包括action
,result
等配置) , 并可以添加自己包的配置 .
在struts.xml
中使用package
元素定义包 . package
元素包含多种属性 , 其中:
name
属性为必需的并且是唯一的 , 用来指定包的名称(被其他包引用) .extends
属性类似Java
中extends
关键字 , 指定要扩展的包.
经验 : 在开发过中中 , 除非有令人信服的理由 , 否则所定义的包总是扩展
struts-default
包 .struts-default
包由Struts 2
框架定义 , 其中配置了大量常用的Struts 2
特性 . 若没有这些特性 , 则连简单的在action
中获取请求数据都无法完成
namespace
是一个可选属性,该属性定义该包中action
的命名空间,如果没有该属性 , 则action
被放入默认命名空间中.Struts 2
框架使用action
的名称和它所在包的命名空间来标识一个action
. 默认的命名空间用“ ”
表示 , 也可以使用"/"
定义一个根命名空间 , 二者是有区别的 .
当请求
Web
应用程序根路径下的action
, 框架在根命名空间中查找对应的action
, 如果在根路径下未找到 , 则再到默认的命名空间中去查找.
解释 : 当Struts 2
接收到一个请求时 , 框架会将URL
分为namespace
和action
名称两部分 , 框架首先在namespace
命名空间中查找这个action
, 若没有找到则再在默认命名空间中查找 . 例如:请求URL
为/myspace/somespace/some.action
, 框架首先会在/myspace/somespace
命名空间中查找some.action
, 若没有找到 , 框架将会到默认的命名空间中查找 .
总结:
- package元素:类似于包.
- name属性:为必须并且是唯一的,用来指定包的名称,被其他包所引用.
- namespace:命名空间,可选属性.用来定义该包中action的命名空间.如果没有定义该属性,则action会被放入默认的空间中. 默认空间用””表示,也可以使用/定义根命名空间,二者是有本质区别的, 可以理解为访问路径的前缀
package元素中包含action元素 和 result元素
管理action namespace为action指定了一个访问路径的前缀 , 完整的URL路径 : struts项目名+/+package 元素中的namespace属性+/+action元素中的name属性的值.action
2. 拆分配置文件
随着项目的规模越来越大 , 将所有的配置都放在一个配置文件中必然会导致struts.xml
文件变得非常臃肿 .
为了提高
struts.xml
文件的可读性 ,Struts 2
允许将一个配置文件拆分成多个配置文件 , 但默认只加载WEB-INF/classes
下的struts.xml
文件 .
一旦拆分后 , 还要能够将拆分过的文件整合在一起 , 可以在struts.xml
文件中通过include
元素将其他配置文件包含进来 . include
元素提供file
属性 , 该属性指定了被包含配置文件的文件名 , 如示例4所示:
示例4
<struts>
<include file="struts-user.xml"/>
<include file="struts-house.xml"/>
</struts>
被包含的struts-user.xml
, struts-house.xml
是标准的Struts 2
的配置文件 , 被保存在WEB-INF/classes
下 , 与struts.xml
的结构完全一样 .
当系统加载struts.xml
后便会自动加载所包含的所有配置文件 .
3.struts-default.xml
struts-default.xml
文件是struts2
框架默认加载的配置文件 , 为框架提供默认的配置 , 该配置文件会自动加载。它定义struts2一些核心的bean和拦截器。这些拦截器是以key-value
对的形式配置在struts-default.xml
中,其中name
是拦截器名字,就是后面使用该拦截器的引用点,value
则指定拦截器的实现类。
前面提到的
struts-default
包在struts-default.xml
文件中定义
4.struts-plugin.xml
struts-plugin.xml
文件是Struts 2
插件使用的配置文件 , 如果不是开发插件 , 则不需要编写这个配置文件.
2 . Action的配置
2.1 Action
的作用
对于Struts 2
应用的开发者而言,Action
才是应用的核心,开发者需要提供大量的Action
类,并在struts.xml
文件中配置Action
。Action
类里包含了对用户请求的处理逻辑,Action类也被称为业务控制器。
Action
主要有三个作用:
- action最重要的作用是为给定的请求封装需要做的实际工作(调用特定的业务处理类);
- 为数据的转移提供场所;
- Action必须帮助框架决定由哪个结果呈现请求响应 .
下面来看Action
是如何实现这三个作用的 .
1. 封装工作单元
可以把Action
看作控制器的一部分,其主要职责就是控制逻辑业务,通常使用Action
的execute()
方法实现这一功能。如示例5所示:
示例5
public class HelloWorldAction implements Action {
/**用户输入的姓名*/
private String name;
/**向用户显示的信息*/
private String message;
//省略属性的getter/setter
/**
* execute方法 , 当Struts 2处理用户请求时,在默认配置下调用的方法
* @return
* @throws Exception
*/
@Override
public String execute() throws Exception {
//根据用户输入的姓名,进行Hello,xxx的封装
this.setMessage("Hello,"+this.getName()+"!!");
//处理完毕,返回helloWorld
return "helloWorld";
}
}
这个程序很简单 , 是前面章节中完成HelloWorld
程序中用于处理"Hello,XXXX !!"
的Action
, 它的execute()
方法只是简单构建问候语 , 如果业务逻辑很复杂 , 则会把业务逻辑构建为业务类 , 再在Action
中调用这个业务类 .
现在 , 只需要谨记Action
控制业务逻辑或者作为业务逻辑的入口点 , 并且我们编写的Action
应该可能的让业务逻辑纯粹和简洁 .
2. 数据转移的场所
Action
作为数据转移的场所 , 也许有人认为这会使用Action
变得复杂 , 实际上这使得Action
更加简洁 . 由于数据保存在Action
中 , 在控制业务逻辑的过程中可以非常方便的访问它们。
如示例6所示:
public class HelloWorldAction implements Action {
/**用户输入的姓名*/
private String name;
/**向用户显示的信息*/
private String message;
//省略属性的getter/setter
/**
* execute方法 , 当Struts 2处理用户请求时,在默认配置下调用的方法
* @return
* @throws Exception
*/
@Override
public String execute() throws Exception {
//根据用户输入的姓名,进行Hello,xxx的封装
this.setMessage("Hello,"+this.getName()+"!!");
//处理完毕,返回helloWorld
return "helloWorld";
}
}
或许一系列的JavaBean
属性增加Action
的代码量 , 但执行execute()
方法时引用这些属性中保存的数据 , 会使Action
的代码变得简洁(不需要从request对象中获取请求数据) , 并且使我们开发的Action
与Servlet API
解耦.
3. 返回结果字符串
Action
的最后一个作用是返回结果字符串。
Action
根据业务逻辑执行的返回结果判断返回何种结果字符串 , 框架根据Action
返回的结果字符串选择对应的视图组件呈现给用户。
4. 总结:关于Action
的三种写法:
1. 普通的POJO
类(没有继承有没有实现) – 基本不用
public class DemoAction1 {
public String execute(){
System.out.println("DemoAction1是普通的POJO类...");
return null;
}
}
struts.xml
配置文件中action
元素的关键代码如下:
<!-- 普通的POJO类 -->
<action name="action1" class="cn.strutsdemo.web.action.DemoAction1"/>
部署并运行项目,浏览器输入地址:localhost:8080/action1
,控制台打印如下语句:
DemoAction1是普通的POJO类..
2. 实现Action接口–基本不使用
/**
* action类的编写2:实现action接口
*/
public class DemoAction2 implements Action {
@Override
public String execute() throws Exception {
System.out.println("DemoAction2是一个实现了Action接口的类...");
return null;
}
}
struts.xml
配置文件中action
元素的关键代码如下:
<!-- 实现了Action接口 -->
<action name="action2" class="cn.strutsdemo.web.action.DemoAction2" />
部署并运行项目,浏览器输入地址:localhost:8080/action2
,控制台打印如下语句:
DemoAction2是一个实现了Action接口的类...
- Action接口中定义了5个常量,5个常量的值对应的是5个逻辑视图跳转页面(跳转的页面还是需要自己来配置),还定义了一个方法,execute方法。
- 5个逻辑视图的常量
- SUCCESS – 成功
- INPUT – 用于数据表单校验.如果校验失败,跳转INPUT视图
- LOGIN – 登录
- ERROR – 错误.
- NONE – 执行成功,但是不会显示一个视图。通常产生这种情况的原因是被其他视图重定向了。
3. 继承ActionSupport类–经常使用
/**
* action编写3:继承ActionSupport类
*/
public class DemoAction3 extends ActionSupport {
private static final long serialVersionUID = 1L;
@Override
public String execute() throws Exception {
System.out.println("DemoAction3是一个继承了ActionSupport的类...");
return null;
}
}
struts.xml
配置文件中action
元素的关键代码如下:
<!-- 继承了ActionSupport类 -->
<action name="action3" class="cn.strutsdemo.web.action.DemoAction3"/>
部署并运行项目,浏览器输入地址:localhost:8080/action3
,控制台打印如下语句:
DemoAction3是一个继承了ActionSupport的类...
ActionSupport本身继承了许多的类,利于编写代码
开发中经常使用这种方式
接下来 , 将介绍一些Action
的常用特性 , 以便在编写Action
时灵活运用 .
2.2 method 属性
在之前的程序中 , 每实现一个功能都回去创建一个Action
, 并完成相应的方法 , 那么是否可以在同一个Action
中实现不同的功能呢 ? 答案是可定的 , 这也是我们将要学习的另一种Action
应用 . 即使用method
属性实现在同一个Action
中处理不同的请求 .
在实际应用中,随着应用程序的不断扩大,我们不得不管理数量庞大的
Action
。
例如:一个系统中用户的操作可分为登录和注册两部分 , 如果一个请求对应一个Action
, 将要编写两个Action
用于处理用户的请求 .
在具体开发过程中 , 为了减少Action
的数量 , 通常在一个Action
中编写不同的方法 (必须遵守execute()
方法相同的格式)处理不同的请求 , 如编写UserAction
, 其中login()
方法处理登录请求 , register()
方法处理注册请求 , 此时就可以通过配置action
元素的method
属性来实现 , 如示例7代码所示:
示例7:
创建UserAction
类 , 关键代码如下:
/**
* 此类只为演示使用method属性实现用户登录和注册
*/
public class UserAction {
/**
* 演示使用method属性进入登录方法
* @return
*/
public String login() {
//此处省略业务逻辑 只为演示效果
return "success";
}
/**
* 演示使用method属性进入注册方法
* @return
*/
public String register() {
//此处省略业务逻辑 只为演示效果
return "success";
}
}
struts.xml
配置文件内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<!--设置用户界面主题 , 默认值为XHTML风格-->
<constant name="struts.ui.theme" value="simple"/>
<package name="user" namespace="/user" extends="struts-default">
<!--演示method属性-->
<action name="login" class="cn.strutsdemo.action.UserAction" method="login">
<result>/login.jsp</result>
</action>
<action name="register" class="cn.strutsdemo.action.UserAction"
method="register">
<result>/register.jsp</result>
</action>
</package>
</struts>
在上面的代码中 , 可以看到配置文件中分别定义了两个action
元素 , 每个action
元素的name属性不同 , 但是指向的实现类的引用却是相同的 , Struts 2
在接收请求后通过method
属性确定该执行同一个Action
的哪一个方法 .
也就是说如果用户的请求是
localhost:8080/项目名/user/login.action
, 那么就会调用UserAction
类中的login()
方法 , 如果是localhost:8080/项目名/user/register.action
, 则会调用UserAction
类中的register()
方法 .
这样配置的结果可以使程序中Action
数量减少 . 一旦在Action
中需要添加新的方法 , 则只需要修改配置文件中的设置即可 .
同时,需要强调的是 , 使用method
属性可以指定任意方法处理请求(只要该方法和execute()
方法具有相同的格式).
2.3 Action中动态方法调用
为了减少配置Action
的数量 , 还可以使用动态方法进行处理 .
动态方法调用(Dynamic Method Invocation,DMI)是指表单元素的Action并不是直接等于某个Action的名称,而是通过在Action的名称中使用感叹号(!)来标识要调用的方法名称,格式为
actionName!methodName.action
。
下面举例说明 , 加入配置文件中的Action
配置如示例8所示:
示例8:
修改UserAction.java
, 代码如下:
/**
* 此类只为演示使用method属性实现用户登录和注册
*/
public class UserAction {
/**
* 演示使用method属性进入登录方法
* @return
*/
public String login() {
//此处省略业务逻辑 只为演示效果
return "doLogin";
}
/**
* 演示使用method属性进入注册方法
* @return
*/
public String register() {
//此处省略业务逻辑 只为演示效果
return "doRegister";
}
}
修改struts.xml
, 代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<!--设置用户界面主题 , 默认值为XHTML风格-->
<constant name="struts.ui.theme" value="simple"/>
<!--启用动态方法的调用-->
<constant name="struts.enable.DynamicMethodInvocation" value="true"/>
<package name="user" namespace="/" extends="struts-default">
<!--演示动态方法的调用-->
<action name="user" class="cn.strutsdemo.action.UserAction">
<result name="doLogin">/login.jsp</result>
<result name="doRegister">/register.jsp</result>
</action>
</package>
</struts>
当请求http://localhost:8080/user!login.action
时 , 框架将会调用UserAction
的login()
方法 , 当请求http://localhost:8080/user!register.action
时 , 框架将调用UserAction
的register()
方法.
**因为动态的方法调用可能会带来安全隐患(通过URL可以Action中的任意方法) , 所以在确定使用动态方法调用时 , 应该确保Action中的所有方法都是普通的,开放的方法 . **
基于这个原因 , Struts 2
框架禁止动态方法的调用 , 由于前面提过的default.properties
中的struts.enable.DynamicMethodInvocation
属性配置 , 默认为false
. 可以在strut.xml
文件中 , 通过constant
元素将其设置true
启用动态方法调用。
如示例9所示:
示例9:
<!--启用动态方法的调用-->
<constant name="struts.enable.DynamicMethodInvocation" value="true"/>
使用method
属性调用不同方法与动态方法调用的适用条件如下:
- 如果同一个
Action
的不同方法要处理的请求使用相同的配置(result等) , 则使用动态方法调用. - 如果不同的方法调用需要不同的配置 , 那么就要使用
action
元素的method
属性 , 为同一个Action
配置多个名称 , 但使用method
属性会导致配置文件中存在大量的Action
配置 .
**从安全角度出发 , 建议采用method
属性来实现同一个Action
的不同方法处理不同的请求 . 但是新的问题随之而来 , 即随着Action
的逐渐增多 , 导致在struts.xml
文件中存在大量的Action
配置 .
虽然减少了
Action
的数量 , 但是如果能够降低Action
配置数量 , 那就更好了。
备注:Struts 2.5
之后关于Action
中动态的方法的调用 , 会出现以下异常信息:
dispatcher.Dispatcher (Dispatcher.java:611) - Could not find action or result: /user!login.action
com.opensymphony.xwork2.config.ConfigurationException: Method login for action user is not allowed!
这是因为 Struts 2.5
为了提升安全性,添加了 allowed-methods
这么个属性。
解决方法是在struts.xml
配置文件中的<package>
元素下添加<global-allowed-methods>
元素 , 代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<!--设置用户界面主题 , 默认值为XHTML风格-->
<constant name="struts.ui.theme" value="simple"/>
<!--启用动态方法的调用-->
<constant name="struts.enable.DynamicMethodInvocation" value="true"/>
<package name="user" namespace="/" extends="struts-default">
<!-- 使用此标签之后,系统就不会再到你具体的Action中去找相对应result了-->
<global-allowed-methods>regex:.*</global-allowed-methods>
<action name="user" class="cn.strutsdemo.action.UserAction">
<result name="doLogin">/login.jsp</result>
<result name="doRegister">/register.jsp</result>
</action>
</package>
</struts>
使用<global-allowed-methods>
标签之后,系统就不会再到你具体的Action
中去找相对应result
了 , 而是去找调用对应的方法 , 这是第一种方法 .
这种方法针对的是该
<package>
元素下所有的<action>
元素中动态方法的调用。
第二种方式也可以是针对某一个<action>
元素配置allowed-methods
属性 , 代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<!--设置用户界面主题 , 默认值为XHTML风格-->
<constant name="struts.ui.theme" value="simple"/>
<!--启用动态方法的调用-->
<constant name="struts.enable.DynamicMethodInvocation" value="true"/>
<package name="user" namespace="/" extends="struts-default">
<action name="user" class="cn.strutsdemo.action.UserAction">
<result name="doLogin">/login.jsp</result>
<result name="doRegister">/register.jsp</result>
<!--根据路径中!后的名字匹配action中方法,
若匹配单个方法,请写方法名比如:login,register-->
<allowed-methods>regex:.*</allowed-methods>
</action>
</package>
</struts>
或者同样也支持在你的 action
上使用 @AllowedMethods
注解
具体的可查找官方文档 :
https://struts.apache.org/getting-started/wildcard-method-selection.html
.
Struts 2
中还提供了使用通配符的方式 , 解决Action
配置过多的问题.
2.4 Action中通配符的使用
在配置<action.../>
元素时 , 需要指定name
, class
和method
属性 , 其中name
属性支持通配符 . 在class
, method
属性中可以使用表达式 .
这种使用通配符的方式是另一种形式的动态方法调用 , 通配符用星号(
*
)表示 , 用于配置0个或多个字符串 .
在配置Action
时 , 可以在action
元素的name
属性中使用星号来匹配任意的字符串 , 如示例10所示:
示例10:
修改UserAction.java
, 代码如下:
/**
* 此类只为演示使用method属性实现用户登录和注册
*/
public class UserAction {
/**
* 演示使用method属性进入登录方法
* @return
*/
public String login() {
//此处省略业务逻辑 只为演示效果
System.out.println("调用登录方法......");
return "input";
}
/**
* 演示使用method属性进入注册方法
* @return
*/
public String register() {
//此处省略业务逻辑 只为演示效果
System.out.println("调用注册方法......");
return "input";
}
}
修改struts.xml
, 代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<!--设置用户界面主题 , 默认值为XHTML风格-->
<constant name="struts.ui.theme" value="simple"/>
<!--启用动态方法的调用-->
<constant name="struts.enable.DynamicMethodInvocation" value="true"/>
<package name="user" namespace="/" extends="struts-default">
<global-allowed-methods>regex:.*</global-allowed-methods>
<!-- 演示通配符的使用 -->
<action name="*User" class="cn.strutsdemo.action.UserAction"
method="{1}">
<result name="input">/{1}.jsp</result>
</action>
</package>
</struts>
在action
元素的name
属性中使用星号(*
) , 允许这个Action
拼配所有以User
结束的URI
, 如:http://localhost:8080/loginUser.action
。
配置该action
元素时 , 还指定了method
属性 , 该属性使用了一个表达式{1}
, 该表达式的值就是name
属性值中的第一个"*"
的值。
例如 : 当请求为:
http://localhost:8080/loginUser.action
, 通配符匹配的是login
, 那么这个值将替换{1}
, 最终请求loginUser.action
, 将由UserAction
的login()
方法执行 .
关于Struts 2
解决Action
配置过多的问题 , 框架并不建议使用第一种动态方法进行处理 , 而是建议使用第二种通配符的方式
2.5 配置默认的Action
如果请求一个不存在的Action
, 那么将会在页面上呈现HTTP 404
错误 , 为了解决这个问题 , Struts 2
框架允许指定一个默认的Action
, 即如果没有一个Action
匹配请求 , 那么默认的Action
的将被执行 .
配置默认的
Action
通过<default-action-ref .../>
元素完成
在每个<package>
下只能有一个<default-action-ref.../>
元素 . 指定其name
属性当前package
, 子package
, 父package
三者中的一个Action name
, 如果在某一继承树上的各package
中分别定义了多个<default-action-ref .../>
元素 , 则搜索顺序为:由子package
往父package
寻找 , 找到即停止 , 默认Action
的配置如示例11所示:
示例11:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<!--设置用户界面主题 , 默认值为XHTML风格-->
<constant name="struts.ui.theme" value="simple"/>
<!--启用动态方法的调用-->
<constant name="struts.enable.DynamicMethodInvocation" value="true"/>
<package name="user" namespace="/" extends="struts-default">
<!-- 演示配置默认的Action -->
<default-action-ref name="defaultActioin"/>
<global-allowed-methods>regex:.*</global-allowed-methods>
<action name="defaultActioin">
<result>error.jsp</result>
</action>
<action name="*User" class="cn.strutsdemo.action.UserAction"
method="{1}">
<result name="input">/{1}.jsp</result>
</action>
</package>
</struts>
webapp
下新建error.jsp
, 页面内容如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>错误页面</title>
</head>
<body>
<h1>页面错误</h1>
</body>
</html>
部署项目 , 浏览器输入地址http://localhost:8080
, 显示错误页面
经验: 在配置文件中 , 如果将
action
元素的class
属性省略 , 默认将使用ActionSupport
类 ,ActionSupport
类实现了Action
接口 , 并给出了execute()
方法的默认实现 . 这个实现只是简单的返回"success"
字符串 .
3 . Result的配置
Struts 2
的Action
处理用户请求结束后,返回一个普通字符串-逻辑视图名,必须在struts.xml
文件中完成逻辑视图和物理视图资源的映射,才可让系统转到实际的视图资源。
Struts2
通过在struts.xml
文件中使用<result …/>
元素来配置结果。Result
的配置由两部分组成 : 一部分是Result
所代表的实际资源的位置及Result
名称 ; 另一部分是Result
的类型,由result
元素的type
属性进行设定;
在Struts 2
框架中调用Action
对请求处理之后 , 就要向用户呈现结果视图 . Struts 2
支持多种类型的视图 , 这些视图是由不同的结果类型来管理的 .
3.1 常用结果类型
1. dispatcher 类型
dispatcher
:最常用的结果类型也是默认的结果类型。Struts2
在后台使用Servlet API
的RequestDispatcher
来转发请求 . 代码如示例12所示:
示例12:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<!--设置用户界面主题 , 默认值为XHTML风格-->
<constant name="struts.ui.theme" value="simple"/>
<!--启用动态方法的调用-->
<constant name="struts.enable.DynamicMethodInvocation" value="true"/>
<package name="user" namespace="/" extends="struts-default">
<default-action-ref name="defaultActioin"/>
<global-allowed-methods>regex:.*</global-allowed-methods>
<action name="defaultActioin">
<result>error.jsp</result>
</action>
<action name="*User" class="cn.strutsdemo.action.UserAction"
method="{1}">
<!--演示result元素中的dispatcher类型-->
<result name="input" type="dispatcher">/{1}.jsp</result>
</action>
</package>
</struts>
dispatcher
类型属于result
元素默认的结果类型,采用转发的形式请求指定的视图资源,请求中的数据信息不会丢失;
如果在
result
元素中没有配置type
属性 , 那么Action
的结果将自动以dispatcher(转发)
方式请求指定的视图资源 .
使用dispatcher
类型其实是通过转发来完成页面的跳转 , 但是在实际的应用开发中 , 有很多情况需要使用重定向来完成页面的跳转,这就需要介绍另一种结果类型 ----redirect
类型
2. redirect 类型
redirect类型 采用重定向的方式指定的视图资源,通过HttpServletResponse对象的sendRedirect()方法重新生成一个请求,原请求中的数据信息会丢失;
在使用redirect时,用户完成一次与服务器之间的交互,浏览器需要发送两次请求。
工作过程如下:
- 浏览器发送一个请求,Struts2框架调用对应的action实例对请求进行处理
- Action返回“success”结果字符串,框架根据这个结果选择对应的结果类型,这里使用的是redirect结果类型。
- ServletRedirectResult在内部使用HttpServletResponse的sendRedirect()方法将请求重新定向到目标资源。
- 浏览器重新发起一个针对目标资源的新请求
- 目标资源作为响应呈现给用户
关键代码如下:
<!--演示result元素中的redirect类型-->
<result type="redirect">error.jsp</result>
3. redirectAction 类型
redirectActio
n类型与redirect
类型相似 , 都是使用HttpResponse
对象的sendRedirect()
方法将请求重定向到指定的URL
. 但redirectAction
类型主要用于重定向到另一个Action
.
也就是说 , 当请求处理完成后 , 需要在另一个
Action
中继续处理请求时 , 就需要使用redirectAction
结果类型重定向到指定的Action
.
因此对于redirect
类型而言 , 二者虽然都会生成一个新的请求 , 但是redirect
类型常用于指定一个具体的资源(如视图)的请求 , 而后者则主要用于执行对一个Action
的请求.
关键代码如下:
<!--演示result元素中的redirectAction类型-->
<result type="redirectAction">loginUser</result>
提示:
既然redirect
类型与redirectAction
类型都是执行重定向 , 那么两种结果类型都会丢失请求中包含的参数 , 属性以及前一个Action
处理结果
对
Result
配置常用的三种结果类型总结如下:
- dispatcher类型:Action默认的结果类型,采用转发的形式请求指定的视图资源,请求中的数据信息不会丢失;
- redirect类型:采用重定向的方式指定的视图资源,通过HttpServletResponse对象的sendRedirect()方法重新生成一个请求,原请求中的数据信息会丢失;
- redirectAction类型:采用重定向的方式请求一个新的Action,原请求中的数据信息会丢失;
3.2 动态结果
动态结果就是指在配置时 , 不知道执行后的结果是哪一个,只有在运行时才知道哪个结果作为视图显示给用户 , 即在配置时使用表达式 , 在运行时 , 框架根据表达式的值来确定要使用哪个结果 .
例如 , 用户角色分为管理员和普通用户 , 用户登录时根据用户的角色决定用户能够浏览的资源 , 用户登录依然由
UserAction
处理 , 普通用户访问资源由OrdinaryUserAction
处理 , 管理员可访问资源由ManagerAction
处理 , 如示例13所示:
示例13:
修改User
类 , 代码如下:
/**
* 用户信息
*/
public class User implements Serializable {
/**用户名 , 用户登录时输入*/
private String username;
/**密码, 用户登录时输入*/
private String password;
/**是否为管理员*/
private boolean manager;
//省略getter setter
}
修改UserAction
类 , 代码如下:
/**
* 此类只为演示使用method属性实现用户登录和注册
*/
public class UserAction {
private User user;
private String nextDispose;
//省略getter setter
/**
* 演示动态结果
* @return
*/
public String doLogin(){
//此处省略业务逻辑 只为演示效果
user = new User();
if (user.isManager()) {
nextDispose = "manager";
}else{
nextDispose = "common";
}
return "success";
}
}
在用户登录成功后 , 判断用户的权限 , 根据不同用户设置变量nextDispose
的值 . 具体配置如示例14所示:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<!--设置用户界面主题 , 默认值为XHTML风格-->
<constant name="struts.ui.theme" value="simple"/>
<package name="user" namespace="/" extends="struts-default">
<!--演示动态结果-->
<action name="doLogin" class="cn.strutsdemo.action.UserAction"
method="doLogin">
<!--使用重定向至action-->
<result type="redirectAction">${nextDispose}</result>
</action>
<action name="manager">
<result>/page/manager.jsp</result>
</action>
<action name="common">
<result>/page/common.jsp</result>
</action>
</package>
</struts>
在示例14中 , 使用${nextDispose}
来获取Action
中的nextDispose
属性值 , 这个值要子啊运行时才能知道 , 框架在运行时解析出${nextDispose}
的值 , 然后将请求重定向到指定的Action
.
需要注意的是 , 使用
${属性名}
语法访问的属性一定要在Action
中存在 , 并且Action
要提供该属性的getter()
方法 .
在webapp
目录下 , 先创建page
目录 , 并在page
目录下 , 创建manager.jsp
和common.jsp
文件 , 代码分别如下:
manager.jsp
:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>管理员界面</title>
</head>
<body>
<h1>欢迎管理员</h1>
</body>
</html>
common.jsp
:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>普通用户界面</title>
</head>
<body>
<h1>欢迎普通用户</h1>
</body>
</html>
部署项目 , 浏览器输入地址 : http://localhost:8080/doLogin.action
, 浏览器重定向至http://localhost:8080/common.action
, 并输出普通用户界面的内容
3.3 全局结果
之前我们配置的结果都在action
元素内部 , 这些结果不能被其他Action
使用 . 在一些情况下 , 多个Action
可能需要访问同一个结果 , 这时需要配置全局结果来满足多个Action
共享一个结果的要求 .
全局结果也在包中定义 , 这个包中所有的
Action
都可以共享这个结果 . 全局结果定义如示例15所示:
示例15:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<!--设置用户界面主题 , 默认值为XHTML风格-->
<constant name="struts.ui.theme" value="simple"/>
<!--启用动态方法的调用-->
<constant name="struts.enable.DynamicMethodInvocation" value="true"/>
<!--<include file="struts-user.xml"/>
<include file="struts-house.xml"/>-->
<package name="deafault" namespace="/" extends="struts-default">
<action name="helloWorld"
class="cn.strutsdemo.controller.HelloWorldAction">
<result name="helloWorld">helloWorld.jsp</result>
</action>
<action name="login" class="cn.strutsdemo.action.LoginAction">
<result name="success">success.jsp</result>
<result name="error">fail.jsp</result>
<!--返回结果为input时,即校验结果失败,跳转到登录页面-->
<result name="input">login.jsp</result>
</action>
<action name="iterator"
class="cn.strutsdemo.action.IteratorAction">
<result name="success">iterator.jsp</result>
</action>
</package>
<package name="user" namespace="/" extends="struts-default">
<default-action-ref name="defaultActioin"/>
<!--配置全局action的error请求 -->
<global-results>
<result name="error">/error.jsp</result>
</global-results>
<global-allowed-methods>regex:.*</global-allowed-methods>
<action name="defaultActioin">
<result type="redirectAction">loginUser.action</result>
</action>
<action name="*User" class="cn.strutsdemo.action.UserAction"
method="{1}">
<result name="input" type="dispatcher">/{1}.jsp</result>
</action>
<!--演示动态结果-->
<action name="doLogin" class="cn.strutsdemo.action.UserAction"
method="doLogin">
<!--使用重定向至action-->
<result type="redirectAction">${nextDispose}</result>
</action>
<action name="manager">
<result>/page/manager.jsp</result>
</action>
<action name="common">
<result>/page/common.jsp</result>
</action>
</package>
</struts>
UserAction
类中的关键代码如下:
/**
* 此类只为演示使用method属性实现用户登录和注册
*/
public class UserAction {
private User user;
private String nextDispose;
//省略getter setter
/**
* 演示全局结果的error
* @return
*/
public String update(){
//此处省略业务逻辑 只为演示全局结果
System.out.println("调用修改方法,演示全局结果");
return "error";
}
/**
* 演示动态结果
* @return
*/
public String doLogin(){
//此处省略业务逻辑 只为演示效果
user = new User();
System.out.println("调用执行登录的方法");
if (user.isManager()) {
nextDispose = "manager";
}else{
nextDispose = "common";
}
return "error";//返回error 演示全局结果
}
/**
* 演示使用method属性进入登录方法
* @return
*/
public String login() {
//此处省略业务逻辑 只为演示效果
System.out.println("调用登录方法......");
return "input";
}
/**
* 演示使用method属性进入注册方法
* @return
*/
public String register() {
//此处省略业务逻辑 只为演示效果
System.out.println("调用注册方法......");
return "input";
}
}
部署项目 , 浏览器中输入地址:http://localhost:8080/updateUser.action
, 由于update()
方法返回的是"error"
, 所以框架根据返回的字符串 找到全局配置的result
结果 , 所以浏览器转发至异常页面 .
全局结果也同样使用result
元素配置 , 与action
配置result
元素的区别在于 , 全局结果需要在<global-results>
元素中嵌套<result>
元素 , 如果在Action
中的result
元素名称与全局结果的名称相同时 , Action
中的result
元素将会覆盖全局的result
结果
也就是说 , 当
Action
处理用户请求结束后 , 会首先在本Action
中的result
结果中,搜索与逻辑视图名称对应的结果 , 只有在Action
中无法找到与逻辑视图对应的结果时 , 才会去全局结果中寻找并执行