SSH Chapter 09 Struts2 配置详解

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 分析登录程序

为了实现用户登录的功能 , 需要经过一下几个步骤 :

  1. 获取Struts 2资源
  2. 在应用程序中导入Struts 2的类库
  3. web.xml文件中配置StrtusPrepareAndExecuteFilter
  4. 编写Action类并进行配置
  5. 配置返回结果与物理视图资源的关系
  6. 编写结果视图

众所周知 , Struts 2框架是基于MVC模式的 . 基于MVC模式框架的核心就是控制器对所有请求进行统一处理 . Struts 2的控制器StrutsPrepareAndExecuteFilterServlet 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作为一个FilterWeb应用中运行 , 它负责拦截所有的用户请求 , 当用户请求到达时 , 该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.ActionSupport类 , 以便简化开发.

问答:

问题: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应用的整个过程都是按照请求/响应的过程执行的 , 这个过程如下所示:

  1. Web容器接收到请求之后 , 将请求交由在web.xml中配置的Struts 2框架的控制器StrutsPrepareAndExecuteFilter(核心控制器).
  2. StrutsPrepareAndExecuteFilter(核心控制器)确定请求对应的Action(业务控制器).
  3. 框架根据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属性类似Javaextends关键字 , 指定要扩展的包.

经验 : 在开发过中中 , 除非有令人信服的理由 , 否则所定义的包总是扩展struts-default包 . struts-default包由Struts 2框架定义 , 其中配置了大量常用的Struts 2特性 . 若没有这些特性 , 则连简单的在action中获取请求数据都无法完成

namespace是一个可选属性,该属性定义该包中action的命名空间,如果没有该属性 , 则action被放入默认命名空间中.Struts 2框架使用action的名称和它所在包的命名空间来标识一个action . 默认的命名空间用“ ”表示 , 也可以使用"/"定义一个根命名空间 , 二者是有区别的 .

当请求Web应用程序根路径下的action , 框架在根命名空间中查找对应的action, 如果在根路径下未找到 , 则再到默认的命名空间中去查找.

解释 : 当Struts 2接收到一个请求时 , 框架会将URL分为namespaceaction名称两部分 , 框架首先在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文件中配置ActionAction类里包含了对用户请求的处理逻辑,Action类也被称为业务控制器。

Action主要有三个作用:

  1. action最重要的作用是为给定的请求封装需要做的实际工作(调用特定的业务处理类);
  2. 为数据的转移提供场所;
  3. Action必须帮助框架决定由哪个结果呈现请求响应 .

下面来看Action是如何实现这三个作用的 .

1. 封装工作单元

可以把Action看作控制器的一部分,其主要职责就是控制逻辑业务,通常使用Actionexecute()方法实现这一功能。如示例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对象中获取请求数据) , 并且使我们开发的ActionServlet 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时 , 框架将会调用UserActionlogin()方法 , 当请求http://localhost:8080/user!register.action时 , 框架将调用UserActionregister()方法.

**因为动态的方法调用可能会带来安全隐患(通过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 , classmethod属性 , 其中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 , 将由UserActionlogin()方法执行 .

关于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 2Action处理用户请求结束后,返回一个普通字符串-逻辑视图名,必须在struts.xml文件中完成逻辑视图和物理视图资源的映射,才可让系统转到实际的视图资源。

Struts2通过在struts.xml文件中使用<result …/>元素来配置结果。Result的配置由两部分组成 : 一部分是Result所代表的实际资源的位置及Result名称 ; 另一部分是Result的类型,由 result元素的type属性进行设定;

Struts 2框架中调用Action对请求处理之后 , 就要向用户呈现结果视图 . Struts 2支持多种类型的视图 , 这些视图是由不同的结果类型来管理的 .

3.1 常用结果类型

1. dispatcher 类型

dispatcher:最常用的结果类型也是默认的结果类型。Struts2在后台使用Servlet APIRequestDispatcher来转发请求 . 代码如示例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 类型

redirectAction类型与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.jspcommon.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中无法找到与逻辑视图对应的结果时 , 才会去全局结果中寻找并执行

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值