Struts 2配置详解
本章针对Struts2框架搭建, 项目结构的配置文件解析…及一些Action 配置文件更高级的操作…
web.xml
众所周知, Struts2框架是基于MVC模式。
基于MVC模式框架的核心就是控制器对所有请求进行统一处理.Struts2的控制器;
StrutsPrepareAndExecuteFilter由ServletAPI中的Filter充当。
当web容器的接收到登录请求后,将请求交由在web.xml中配置的过滤 StrutsPrepareAndExecuteFilter.
web.xml
目前无论哪种 MVC框架, 都离不开web.xml 文件的配置
(web.xml文件并不是 Struts2框架特有的文件, 只有在web应用中配置了web.xml 文件, MVC框架才可以真正与web应用融合…)
实例
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<!-- 省略了其它web.xml的基础配置... -->
<!-- Struts2过滤器 -->
<!-- 作用:启动加载struts.xml文件-->
<filter>
<filter-name>struts</filter-name>
<!-- Struts2核心控制器类:
早期还是:org.apache.struts2.dispatcher.FilterDispatcher
-->
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> <!-- 现在! -->
</filter>
<filter-mapping>
<filter-name>struts</filter-name>
<url-pattern>/*</url-pattern> <!-- /*: 任何请求都要经过.. -->
</filter-mapping>
</web-app>
<!--
StrutsPrepareAndExecuteFilter :
作为一个Filter(过滤器),在web应用中运行,它负责拦截所有用户的请求,过滤用户请求到对应的 Action中执行;
在根据,Action 返回的"逻辑视图名" 响应指定的页面...如果请求是以 ".action" 结尾,该请求会被输入到Struts2框架进行处理..
可以包含一些初始化参数,经常使用如 config 加载XML的形式配置文件。
如果没有设置 StrutsPrepareAndExecuteFilter ,默认加载Struts2的配置文件: struts-default.xml struts-plugin.xml struts.xml 进行讲解..
-->
Struts2 的核心控制器: web.xml 因为 Filter 基本不会变,所以个人对于这个文件基本都是学会了。后面直接cope;
Action控制器 和 Struts2配置文件; (本篇重点)
Action
在Struts2框架中,控制器是由两个部分组成的:
核心控制器:用于拦截用户请求,对请求进行处理。(web.xml)
业务控制器:调用相应的请求Model类,实现业务处理…返回结果; (定义的action Java类)
对于开发者来说:
Struts2的主要编码工作就是, Action类; (之前学习两种方式,实现Action接口 继承ActionSupport类常用
)
开发者每完成一个Action类, 都需要在struts.xml中配置对应的<action />
页面发送请求——经过web,xml过滤——Struts2配置文件: 处理——
找到对应的xxaction类 一系列操作后返回一个"逻辑视图名"——至Struts2配置文件根据result 找到对应响应页面…;
Struts2配置文件 (struts.xml)
struts.xml 就是 Struts2的核心配置文件 !
包含 action result 等配置, 主要负责对页面请求管理,分配到对应的 Action类中;
一个经典的Struts.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- struts.xml声明部分,工具没有配置的DTD文件,可以直接cope下面的... -->
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<!-- struts.xml根节点 -->
<struts>
<!-- 请求参数的编码方式 -->
<constant name="struts.i18n.encoding" value="UTF-8"/>
<!-- 文件上传最大值 -->
<constant name="struts.multipart.maxSize" value="104857600" />
<!-- 所有匹配*.action的请求都由struts2处理 -->
<constant name="struts.action.extension" value="action" />
<!-- ...省略其它... -->
<package name="one" namespace="/" extends="struts-default" >
<!-- action:用于接收页面的请求,指定对应的action类中执行...(package中可以配置多个)
name:根据页面请求根据name找到指定的action class:指定对于action java类进行执行;
-->
<action name="" class="" >
<result name="" >/响应页面</result> <!-- 根据 xxxaction类,返回的逻辑视图名指定对于的响应页面... -->
<!-- 都建议加个/ 不然默认是namespace="中指定路径下响应页面" /:表示根目录下响应页面; -->
</action>
</package>
<package name="tow" namespace="/" extends="one" > <!-- 包2继承了包1, -->
</package>
<package name="three" namespace="/" extends="struts-default" >
<action name="" class="" >
<result name="" >相应页面</result>
</action>
<!-- ...省略其它操作... -->
</package>
<!--不指定路径,默认在src下时的方式-->
<include file="struts01.xml"/>
<!--配置文件在具体包中时的方式-->
<include file="com/wsm/action/struts-02.xml"/> <!-- 假设在com.wsm.action包下; -->
</struts>
<!--
<struts> 元素是文件的根元素,所有其他元素都放在 <struts></struts> 中。
<constant> 元素用于进行常量配置。可以改变Struts2 框架的一些行为,从而满足不同应用的需求:name="常量名" value="常量值"
<package> 提供了将多个Action组织为一个模块的方式;
name package名称,必须是唯一的 package可以扩展,一个struts.xml中可以有多个package 执行时从上往下匹配...
namespace package命名空间,通常都是 "/"表示请求为 项目名/请求名; 进行匹配 如果为"/wsm"则页面请求只有为:项目名/wsm/请求名; 才能进入对应包中匹配;
假设: namespace="/wsm" 页面发送一个请求:localhost:8080/项目名/页面.jsp; 它会去struts.xml中寻找包,namespace="/" 的进行匹配; /:表示的就是项目根目录下的请求!
extends 继承:一般要求必须继承struts-default的包. 或一个包继承另一个包!(如上实例)
可在 struts2-core-2.3.16.3.jar中查看struts-default.xml 中声明Struts2核心功能; 一般不会轻易替换!
abstract 是否为抽象包,让别人继承用的,没有任何action子元素的包就可以声明为抽象包。
<include> 元素用于在一个 struts.xml 配置文件中包含其他的配置文件。(随着一个项目的时间...越来越大一个struts.xml必定会非常臃肿)
为了提高可读性,Struts2 允许将一个配置文件拆分为多个配置文件,但Struts程序默认只读:struts.xml名的文件;
所有都是在 struts.xml 中引入其它不同名字但是存在相同功能的配置文件:<include file="struts01.xml"/>
-->
同一个Action类 实现多个方法;
method属性:
在之前的程序中。
每实现一个功能都需要去创建一个 Action类, 并完成相应的方法();在struts.xml 中配置 < action> 太恶心了吧!
如何同一个Action类 实现多个方法
为了减少Action 的数量:通常在一个Action 中编写不同的方法,对应处理不同的请求;
这里我感觉不是很难!就不写实例了…
需要注意的是struts.xml`文件
<!-- 登录 -->
<action name="login" class="定义的JavaAction类" method="login" >
<result name="ok" >/index.jsp</result>
<result name="no" >/login.jsp</result>
<result name="err" >/err.jsp</result>
</action>
<!-- 注册 -->
<action name="register" class="定义的JavaAction类" method="register" >
<!-- 根据返回的逻辑视图匹配对应页面.. -->
<result name="ok" >/login.jsp</result>
<result name="no" >/login.jsp</result>
<result name="err" >/err.jsp</result>
</action>
<!--
观察上面两个 <action>
name="不同,表示页面不同的请求"
class="相同的Action类,根据不同的请求确指定同一个Action类"
method="不同,确定执行Action类中的具体的方法";
如果请求的url是 login 则执行类中的 login();方法
如果请求的url是 register 则执行类中的 register();方法
-->
好处:
减少了程序中的 Action类
一旦Action 中需要添加新的方法还需要在 struts.xml 中编写对应的 < action method=“指定方法名” > 即可…
小提示:Struts2根据action元素中的method属性查找执行方法的两种途径:
- 查找与 method属性值一致的方法名;
- 查找 doMethod();形式的方法名;
假设:
<action ... method="login" >
优先寻找 login(); 如果找不到会寻找 doLogin(); 方法, L 大写欸~
Action动态方法调用:
为了减少配置 Action类的数量, 还可以通过动态方法进行处理。
这个感觉更牛, 解决了定义多个 Action类 还有struts.xml 不用在频繁定义:< action/>
实现:
- 首先要在struts.xml 中开启动态方法调用:
<constant value="true" name="struts.enable.DynamicMethodInvocation"/>
默认是不开启的
且该Action中所有方法都是普通的 没有重载. 都返回值String…- 页面发送请求的方式也有一点变化!就是根据请求来确认请求的方法的!重点
页面请求方式:请求Action类名! 类中方法名;
形式进行请求- 该方式对 Action类 struts.xml 没有太大影响,而是对请求方式有
讲究
Action类中定义多个方法,对应多个不同的功能…
sturts.xml 只是对:<action name="action名" class="指定的action类" >
有讲究;
请求以:action名!方法名[.后缀]; 形式请求, 根据action名找到对应的Action类, 方法名指定对应的方法…[.后缀]可选:.action jsp…假设: 页面一条请求:userAction!login;
框架将调用 UserAction名对应类的 login(); 方法. struts.xml 根据方法返回"逻辑视图名" 响应对应页面!
Action中通配符的使用:
在配置 < action… /> 时候,一般需要指定 name class 和 method属性;
而 name属性, 使用支持通配符 在 class 和 method 也支持使用表达式…(另一种动态方法调用)
<action name="*User" class="com.zb.action.UserAction" method="{1}">
<result name="返回逻辑视图">/{1}_User.jsp</result> <!-- 响应页面,允许使用{1} 表达式; -->
<result name="err">/err.jsp</result>
</action>
<!--
name: 请求名,可以用通配符 *xxx 表示,一般都是 *Action类名;
class: 没啥变化就是指定对应的Action类,对于特殊的项目结构.. 它也支持使用 {1} 表达式...进行特殊操作;
method:执行的方法...一般都是用 {1};
假设: 以上面实例为例子发送一条请求: addUser
通过name进行比较请求符合条件 *User 结果: * 等于add
而{1} 表达式,表示的值就是 *: {1}等于*
所以:
method="{1}",就直接表示请求的是该 Action类中的 add();
通用如果对于不同请求,不同的 class="action类"; 的操作也可以通过该方法进行特殊处理..
要求:
使用该方法需要满足条件: 请求的URL是 方法名+固定name名;
正好对应的是 *name; 进行匹配Action类...
-->
配置默认的Action:
Struts2 对于请求, 如果请求了一个并不存在的请求, 则页面报错: HTTP 404错误!
Struts2 对于这种异常处理使用
<!-- 默认引用 -->
<package name="default" namespace="/" extends="struts-default" >
<default-action-ref name="defaultAction"></default-action-ref>
<!-- 默认action的配置, 用户输入不匹配的action地址, 则默认执行的路径 页面响应!-->
<action name="defaultAction">
<result>/err.jsp</result>
</action>
</package>
<!--
每个包都只能有一个 default-action-ref
default-action-ref 的name属性指定包下的一个 <action name="xx" >
如果一个struts.xml中有多个包~每个包下都有default-action-ref:
由字package —— 父package寻找,找到停止...
-->
Result配置:
Struts2 通过在 struts.xml 文件中使用< result …/> 元素配置结果:
Result 由两个部分组成:
- name=”页面返回的逻辑视图名“ 对应的一个结果页面;
<result name="逻辑视图" >/结果页面.jsp</result>
- Result的type 属性, 结果类型。。。
常用结果类类型:
dispatcher类型
- 最常用的结果类型, 默认类型;后台使用RequestDispatcher转发请求; (转发懂吧会携带参数那种…)
但是很多情况下, 转发并不一定实用!redirect类型
- redirect结果类型, 是指内部使用 HttpServletResponse对象的sendRedirect()将请求重定向至指定的URL
这意味着, 在页面重新发送一次请求: Action实例/属性 request作用域属性都将丢失~redirectAction类型
- redirectAction 与 redirect 类似,都是指重定向!
但使用 redirectAction 类型主要用于重定向到另一个 Action!!(不是页面! 且原请求中的数据将会丢失~)
也就是说:<result name="返回逻辑视图" type="redirectAction" >/action请求</result>
当前一次请求处理完成后, 重定向Action 相当于又发送了一条对应Action 的请求!持续操作…
动态结果
动态结果指:
你不指定执行后的结果是那一个情况下, 只有在运行时才知道结果…作为视图显示给用户…
即, 在配置时候使用表达式: 在运行时, 框架根据表达式的值确定要使用的结果集;
举例:
同一个登录页面, 却有两个不同的角色;
普通用户登录去到 user页面
管理员登录去到 admin页面
定义UserAction
public class UserAction extends ActionSupport {
//全局变量
private String nextDispose;
//登录方法
public String login() {
...
//判断是否 管理员
if(user.isManager()){
nextDispose = "admin";
}else{
nextDispose = "user";
}
return SUCCESS;
}
//get/set方法();
public String getNextDispose(){
return nextDispose;
}
...
}
struts.xml
<struts>
<package name="default" extends="struts-default">
<!-- 框架通过重定向Action 方式又对Action发送了一次请求!
而且请求的Action 来源于: ${nextDispose} 相当于调用Action中的getNextDispose方法,获取重定向Action
-->
<action name="login"
class="cn.houserent.action.UserAction" method="login">
<result name="success" type="redirectAction">${nextDispose}</result>
<result name="error">/page/error.jsp</result>
</action>
<!-- 请求或重定向请求 admin -->
<action name="admin" class="com.wsm.action.admin">
<result name="xxx">/响应页面.jsp</result>
</action>
<!-- 请求或重定向请求 user-->
<action name="user" class="com.wsm.action.user">
<result name="xxx">/响应页面.jsp</result>
</action>
</package>
</struts>
全局结果
在一些情况下,多个action 可能需要同一个 < result /> 返回结果!
例如:
每一个项目都有一个专门对异常处理的页面, 而实现方式是每一个Action类运行时出现异常。
返回error之类的字符, < result name=“error”>/err.jsp< /result > 指定一个结果异常页面;
对于这种需要频繁冗余的操作,可以设值为全局结果 来使用!
在包中定一个全局结果
任何一个action类返回对应字符,都指向全局结果指定的结果页面…一定程度上减少代码;
<struts>
<package name="default" extends="struts-default">
<!-- 全局的result配置,公共的配置: 只要java代码中的return: "error";
统一去err.jsp页面,减少每一个action的result的配置
-->
<global-results>
<result name="error">/err.jsp</result>
</global-results>
</package>
</struts>