struts2 发展历史
经过很多年发展,Struts1 已经成为了高度成熟的框架,但随着时间的发展,Struts1 的局限性和缺点不断的暴露出来. 现在Struts 已经分化成了两个框架
- 第一个是在 Struts1 的基础上,融合了另一个 web 框架 Webwork 的 Struts2。Struts2 实质上是以 Webwork 为核心的,和 Struts1 有很大区别。
- 第二个是 Shale,与原有 Struts1 关联很少,使用了全新的设计思想。
MVC 思想概述
java web 动态编程技术,经历了 Model 和 Model2 时代。
Model1 时代:整个 Web 应用几乎全部由 jsp 页面组成,jsp 页面接收处理客户端请求,对请求处理后直接做出响应,用少量的 JavaBean 来处理数据库连接访问等操作。Model1 的局限性非常明显,jsp 页面同时担任 View 和 Controller 两种角色,将页面表现和逻辑处理混杂在一起,代码重用性极低,增加了扩展和维护难度。
Model2 时代:已经采用了 MVC 的设计。在 Model 2 架构中,Servlet 作为 Controller,负责接收用户请求,只包含控制逻辑,然后调用后端来进行具体的逻辑处理。最后转发到相应的 jsp 页面负责显示。
MVC由Model(模型),View(视图),Controller(控制器)组成。
javaWeb中的三层架构
表现层:MVC,struts2框架其实是对表现层的MVC作了优化
业务层:service
持久层:dao
Struts2 环境的搭建
(1)下载 Struts2
目录结构
apps:该文件夹下包含了基于Struts2的示例应用
docs:包含了Struts2的相关文档
lib:包含了Struts2的核心类库,以及Struts2的第三方类库
src:包含了Struts框架的所有源代码
(2)创建 web 项目,导入 struts2 所需jar包,lib 中有 struts2 的所有 jar 包,但是我们不需要那么多。
我们只把必需的添加到项目即可。将 apps 目录下 struts2-blank.war 压缩包中的 lib 目录下的 jar 包添加到我们项目中即可。这是 struts2 必需的jar包。
Struts2 架构
struts 使用拦截器作为增强处理,以用户的逻辑控制器为目标,创建一个控制器代理,控制器代理回调业务控制器的 execute 方法处理用户请求,该方法的返回值决定 struts2 将怎样的视图资源呈现给用户
struts2 大致处理流程:
(1)浏览器发送请求
(2)核心控制器根据请求决定是否调用相应的 Action
(3)struts2 内置的拦截器链会自动对请求进行一些操作
(4)回调 Action 的 execute 方法,执行操作。
(5)Action 会将处理结果存入 stack Context 中,并返回字符串,核心控制器根据字符串跳转到 指定的视图资源。
(6)视图资源会读取 Stack Context 中的信息,向浏览器生成响应数据。
Struts2 入门案例
只需跟着做即可,先不必了解为何这样做。
(1)编辑 web 应用的 web.xml 配置文件,配置 struts2 的核心拦截器。
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2)从用户请求开始,我们实现一个登陆表单
这里的action属性比较特殊,不是普通的servlet。
当表单提交给login时,struts的拦截器会起作用,调用用户开发的Action处理用户请求
<body>
<form action="login" method="post">
用户名:<input type="text" name="username"><br>
密 码:<input type="password" name="password"><br>
<input type="submit" value="登录">
</form>
</body>
3)实现控制器 Action 类处理用户请求
我们已经指出,MVC 框架的核心就是控制器,控制器处理具体用户请求。
这个类实现Action接口,并实现接口的execute方法。
该类包含的多个属性用于封装用户的请求参数。 我们可能现在很难理解,我们请求的参数是怎么赋值给这个类的。
我们说过,在调用Action方法之前,struts2的内置拦截器会自动负责解析用户请求参数,并赋值给Action相应的参数
public class LoginAction extends Action{
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 execute(){
if(getUsername().equals("cad")&&getPassword().equals("123456")){
return "success";
}else
{
return "error";
}
}
}
4)配置 Action
我们用户发送 login 请求,那么如果根据 login 请求去调用相应的Action实现类呢?这就需要我们去配置 Action。
配置struts.xml ,struts.xml应该放在src的classes路径下
<?xml version="1.0" encoding="UTF-8"?> //直接复制
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts> //根元素
<package name="demo" extends="struts-default"> //包 name随便取,extends照写就ok
<action name="login" class="com.cad.struts2.LoginAction"> //action name为login,即为负责处理login的请求,action默认调用自身的execute方法处理请求
<result name="success">/welcome.jsp</result> //根据返回的字符串转发到相应页面
<result name="error">/error.jsp</result>
</action>
</package>
</struts>
Struts2 两个重要组成部分
struts2 核心就是核心控制器和业务控制器。
核心控制器 StrutsPrepareAndExecuteFilter
StrutsPrepareAndExecuteFilter作为一个filter运行在web应用中,负责拦截所有用户请求,该filter 会过滤用户请求,然
后将请求都交给struts2框架处理。拦截器会默认拦截扩展名为.action的请求,什么后缀名都不写也可以。例如
hello.action或者hello都会进行拦截。xxx.jsp就不会进行拦截,直接放行。
(1)启动 Tomcat,tomcat 加载 web.xml 文件。同时加载和初始化核心过滤器,查看 struts2 源码,发现核心过滤器的初始化方法中会加载 struts.xml 等 struts2 配置文件。
(2)当用户请求到达时,核心过滤器拦截用户请求,将请求交给 struts2 框架来处理,即去匹配 struts.xml 的内容。
struts2 框架获取用户请求后,根据请求的名字来决定调用哪个业务逻辑组件,实例化相应的类。例如,对于 login 请求,调用名为 login 的 Action 处理。
(3)struts2 的所有 Action 都被定义在 struts.xml 文件中,Action 有 name 和 class 属性,name 决定了该 Action 处理哪个用户请求,class 决定了该 Action 的实现类。
(4)Struts2 用户处理用户请求的 Action 实例,并不是用户实现的业务控制器,而是 Action 代理,他会回调用户的处理方法,因为用户实现的业务控制器没有与 Servlet API 有任何关系,所以根本没办法进行获取参数等请求处理,而 struts2 定义了一系列拦截器,会对请求参数解析,传入到 Action 中,回调 execute 方法。
我们每次请求都会实例化相应的类,所以不会出现线程不安全的情况。而 Servlet 为单例,会出现线程不安全。
业务控制器:
业务控制器就是用户实现的Action类,Action类中通常包含一个execute方法,
该方法返回一个字符串,字符串与struts.xml中的result的name相对应,跳转到不同页面。
struts2 内部运行流程
(1)客户端发出 HTTP 请求
(2)然后请求被核心过滤器 StrutsPrepareAndExecuteFilter 拦截
(3)核心过滤器将请求转发到 Action 映射器,Action映射器负责识别当前的请求是否需要交由 Struts2 处理。
(4)Action 映射器返回需要 struts2 处理的信息,StrutsPrepareAndExecuteFilter 会创建一个 Action 代理
(5)Action 代理并不知道执行哪一个 Action,它会向配置管理器询问调用哪一个 Action,配置管理器会从 struts.xml 读取我们配置的 Action 信息。
(6)Action 代理创建相关请求的 Action 对象,调用相关的方法之前,struts2 的一系列拦截器会帮我们做一些操作,例如获取请求参数等。
(7)然后调用 execute 方法根据返回的字符串去匹配相应的页面,
(8)页面可以获取一些页面模板,然后生成最终页面,再倒序的执行拦截器的后续操作
(9)最后生成 HTTP 响应内容
Struts2 配置文件
Struts2核心配置文件是struts.xml,该文件主要负责管理业务控制器Action。
struts2有很多配置文件,按照以下顺序加载配置
(在服务器开启时,加载web.xml文件,然后初始化核心过滤器,核心过滤器的init初始化方法中,
提供了加载配置文件的方法。所以服务器一启动,这些配置文件就已经加载到内存中了。 )
default.properties:该文件保存在struts2-core-2.3.32.jar中的org.apache.struts2包里面
里面保存一些常量。
struts-default.xml :该文件保存在struts2-core-2.3.32.jar中
定义了一些struts2的基础Bean和struts2内建支持的结果类型,还有struts2内建的拦截器(拦截器有很多,分为一系列的拦截器块,我们默认使用defaultStack拦截器块)
struts-plugin.xml :该文件保存在struts-xxx-2.3.32.jar等struts2插件jar包中
我们整合spring等框架时,都需要这种插件的jar包。
struts.xml:是web应用默认的自己的struts2配置文件
struts.properties :是struts2的默认配置文件
web.xml:web应用的配置文件
如果多个文件配置了同一个struts2常量,则后一个文件中配置的常量值会覆盖前面文件中配置的常量值。
配置文件中常用的常量
struts.i18n.encoding:该常量指定struts2应用默认使用的字符集。
struts.objectFactory.spring.autoWire:和spring框架整合有关。
struts.multipart.parser:指定文件上传用的组件。默认为jakarta(即common-fileupload上传组件)
struts.multipart.saveDir:指定上传文件的临时保存路径
struts.multipart.maxSize:指定上传中整个请求所允许上传的最大字节数。
struts.action.extension:指定struts2需要处理的请求后缀。默认值为.action或者什么都不写
struts.serve.static.browserCache:设置浏览器是否缓存静态内容,当应用处于开发阶段时,我们希望不缓存,可设置为false
struts.enable.DynamicMethodInvocation:设置struts2是否支持动态方法调用,默认值为true
struts.devMode:设置struts2是否使用开发模式。如果设置为true,为开发模式,修改struts.xml配置文件不需要重启服务器,会显示更多更友好的错误提示。
struts.ui.theme:指定视图主题。
struts.url.includeParams:指定struts2生成url时是否包含请求参数。有none,get和all三个值。分别对应不包含,仅包含get类型请求参数和包含全部请求参数。
struts.xml 文件中配置和修改常量
在struts.xml文件中配置,使用<constant .../>配置常量。
name:常量名
value:常量值
<constant name="" value=""/>
例子:我们修改请求后缀为.abc
在struts.xml文件中配置
<package name="demo" extends="struts-default">
<action name="hello" class="com.cad.struts2.Hello" method="sayHello">
<result name="success">/welcome.jsp</result>
<result name="error">/error.jsp</result>
</action>
</package>
//修改请求后缀为abc
<constant name="struts.action.extension" value="abc"></constant>
编写jsp页面
<body>
//使用默认请求后缀
<a href="${pageContext.request.contextPath }/hello.action">后缀为.action</a>
<a href="${pageContext.request.contextPath }/hello">没有后缀</a>
<a href="${pageContext.request.contextPath }/hello.abc">后缀为.abc</a>
</body>
结果为前两个都出现404
最后一个超链接访问成功
在 web.xml 文件中配置常量
//修改请求后缀为do
<init-param>
<param-name>struts.action.extension</param-name>
<param-value>do</param-value>
</init-param>
jsp页面
<body>
<a href="${pageContext.request.contextPath }/hello.action">后缀为.action</a>
<a href="${pageContext.request.contextPath }/hello">没有后缀</a>
<a href="${pageContext.request.contextPath }/hello.abc">后缀为.abc</a>
<a href="${pageContext.request.contextPath }/hello.do">后缀为.do</a>
</body>
前三个都请求失败,最后.do结尾的请求成功。这也验证了我们说的配置文件的加载顺序。
深入 struts2 配置文件
struts2是一个高度可扩展的框架。框架的大部分核心组件,并不是硬编码写在代码中,而是以自己的IOC容器管理框架的核心组件。
struts2以可配置的方式来管理核心组件,从而允许开发者很方便的扩展该框架的核心组件,当开发者需要扩展,替换核心组件时,只需要提供自己组件的实现类,将其部署在struts2的IoC容器中即可。
struts-default.xml文件中配置了大量的struts2框架的内置Bean。
我们在struts.xml中定义Bean时,通常有两个作用
-创建该Bean的实例,将该实例作为struts2框架的核心组件使用。
-Bean包含的静态方法需要注入一个值。可以很方便地允许不创建某个类的实例,却可以接受框架常量。
这个部分只需要了解即可,百分之九十九的struts2应用都不用我们去定义核心组件和去配置Bean。
使用<bean />元素在struts.xml定义Bean
属性:
class:必填属性。指定了Bean实例的实现类
type:可选属性,制定了Bean实例实现的struts2规范,该规范通过某个接口实现。
name:可选属性。Bean实例的名字
scope:可选属性。指定Bean实例的作用域
static:可选属性。指定Bean是否使用静态方法注入。
optional:可选属性。指定该Bean是否是一个可选Bean。
例如
使用自定义的ObjectFactory,实现了ObjectFactory接口。实现类是MyObjectFactory
<bean type="com.opensymphony.xwork2.ObjectFactory" name="myfactory" class="com.my.MyObjectFactory"/>
了解即可,不需要深入。
package 包配置
struts2框架的核心组件就是Action,拦截器等。struts2使用包来管理Action,拦截器等。
属性
name:配置包时,必须指定name属性,是包的唯一标识。
extends:属性值必须是另一个包的name属性。指定extends属性表示继承其他包。子包可以集成一个或多个父包中的拦截器,拦截器栈,action等配置。
例如我们前面项目中定义的 <package name="demo" extends="struts-default"> ,就继承struts-default.xml中的struts-default包。
abstract:可选属性。指定该包是否是抽象包,抽象包不能包含Action定义。
namespace:该属性是一个可选属性,定义该包的命名空间。一个web应用中可能出现同名Action。同一个命名空间中不能有同名Action
某个包指定命名空间后,该包下的所有action的url地址必须是 命名空间+action
例如我们加一个命名空间,则访问这个动作的时候必须加上命名空间。例如 http://localhost:8080/Struts2Demo/user/hello.action
<package name="demo" extends="struts-default" namespace="/user">
<action name="hello" class="com.cad.struts2.Hello" method="sayHello">
<result name="success">/welcome.jsp</result>
<result name="error">/error.jsp</result>
</action>
</package>
如果包没有指定命名空间,则默认的命名空间为""
根命名空间为"/"
包的执行顺序
例如 http://localhost:8080/Struts2Demo/user/my/hello.action
(1)搜索配置文件所有package的namespace
(2)先去匹配命名空间/user/my,如果匹配到,就查找Action,查找到就执行,没查找到会到默认命名空间查找Action,查找到执行,没找到报错。
(3)如果没匹配到该命名空间,就接着匹配命名空间/user,如果匹配到,就查找Action,查找到就执行,没查找到会到默认命名空间查找Action,查找到执行,没找到报错。
(4)没匹配到就去根命名空间(”/“)查找action,没查找到会到默认命名空间查找Action,查找到执行,没找到报错。
(5)没匹配到任何命名空间直接报错。
Struts2 的 Action
开发者需要提供大量的 Action,并在 struts.xml 中配置 Action.Action 类里包含了对用户请求的处理逻辑,因为我们也称 Action 为业务控制器。
编写 Action 处理类
第一种创建处理类方法 :
struts2采用了低侵入式的设计,struts2不要求Action类继承任何的struts基类,也不需要实现任何接口。Action类只是一个普通的POJO(Plain Ordinary Java Object简单的java对象)
第二种:创建一个类实现 Action 接口,该接口定义了五个字符串常量。还包含一个 String execute() 方法
public interface Action{
//五个字符串常量
public static final String ERROR="errror";
public static final String INPUT="input";
public static final String LOGIN="login";
public static final String NONE="none";
public static final String SUCCESS="success";
//处理用户请求的execute方法
public String execute()throws Exception;
}
第三种:继承 Action 接口的实现类 ActionSupport,该类提供了很多的默认方法,包括获取国际化信息,数据校验的方法等。大大简化了 Action 的开发。我们开发中选择第三种
配置 Action
在struts.xml文件中配置。struts2使用包来组织action。所以action定义放在包定义的下面 。
<action.../>
属性
name:action的名字
class:指定该action的实现类,class属性并不是必须的,如果我们不指定class属性,系统默认使用ActionSupport类
配置Action的默认处理类
如果我们不指定<action>中的class属性,默认使用ActionSupport类。
我们可以使用<default-class-ref class=""></default-class-ref>来指定默认的动作处理类。
Action 的方法调用
我们继承的 ActionSupport,当我们执行 Action 的时候,默认执行他的 execute 方法,现在我们来执行自己的方法。< action > 中有一个 method 属性,可以指定用户调用哪个方法。
例子:
我们写一个Action类,类里有四个方法。
public class Hello extends ActionSupport{
public String addUser(){
System.out.println("添加用户");
return SUCCESS;
}
public String updateUser(){
System.out.println("修改用户");
return SUCCESS;
}
public String selectUser(){
System.out.println("查询用户");
return SUCCESS;
}
public String deleteUser(){
System.out.println("删除用户");
return SUCCESS;
}
}
我们在struts.xml中配置我们的action
<package name="demo" extends="struts-default">
<action name="addUser" class="com.cad.struts2.Hello" method="addUser">
<result name="success">/welcome.jsp</result>
<result name="error">/error.jsp</result>
</action>
<action name="updateUser" class="com.cad.struts2.Hello" method="updateUser">
<result name="success">/welcome.jsp</result>
<result name="error">/error.jsp</result>
</action>
<action name="selectUser" class="com.cad.struts2.Hello" method="selectUser">
<result name="success">/welcome.jsp</result>
<result name="error">/error.jsp</result>
</action>
<action name="deleteUser" class="com.cad.struts2.Hello" method="deleteUser">
<result name="success">/welcome.jsp</result>
<result name="error">/error.jsp</result>
</action>
</package>
在jsp页面中请求action
<body>
<a href="${pageContext.request.contextPath }/addUser">添加用户</a>
<a href="${pageContext.request.contextPath }/updateUser">修改用户</a>
<a href="${pageContext.request.contextPath }/selectUser">查看用户</a>
<a href="${pageContext.request.contextPath }/deleteUser">删除用户</a>
</body>
我们发现这种方式写的很多代码类似,相当冗余,为了解决这个问题,struts2 提供了通配符的配置方式帮我们解决这个问题。
使用通配符
我们在struts.xml文件中配置
<package name="demo" extends="struts-default">
<action name="*" class="com.cad.struts2.Hello" method="{1}">
<result name="success">/{1}.jsp</result>
<result name="error">/error.jsp</result>
/action>
</package>
action 的 name 中可以使用通配符 * , * 可以匹配所有的 action, * 的值为传入的 action 名字,例如传入了 addUser.action,那么 * 的值就为 addUser。method 属性中可以使用表达式来获取 * 的值,{第几个*}
例如 ” * _ * “,我们传递 add_User,那么 {1} 的值就是 add,{2}的值就是 User。
动态方法调用
使用动态调用前要先将动态调用的常量更改成true,动态调用默认是false,因为不安全。
<constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>
我们使用动态方法调用我们需要的方法。
格式 :动作名称!方法名称
我们配置struts.xml文件 ,不写method值,也不用通配符
<package name="demo" extends="struts-default">
<action name="user" class="com.cad.struts2.Hello" >
<result name="success">/welcome.jsp</result>
<result name="error">/error.jsp</result>
</action>
</package>
我们更改jsp页面按照动态方法调用的格式,就可以调用相关的方法。
<body>
<a href="${pageContext.request.contextPath }/user!addUser">添加用户</a>
<a href="${pageContext.request.contextPath }/user!updateUser">修改用户</a>
<a href="${pageContext.request.contextPath }/user!selectUser">查看用户</a>
<a href="${pageContext.request.contextPath }/user!deleteUser">删除用户</a>
</body>
管理处理结果
当Action处理完用户请求时,处理结果应该通过视图资源实现,但将哪个视图呈现给浏览者呢。由<result.../>来决定
Action处理完用户请求后,返回一个普通字符串。整个普通字符串就是一个逻辑视图名。
通过配置文件将逻辑视图和物理视图联系起来。一旦系统收到Action返回的逻辑视图名,就把对应的物理视图呈现给浏览者。
struts2支持多种视图技术。当一个Action处理用户请求后,仅仅返回一个字符串,这个字符串只是逻辑视图名
逻辑视图名可以和很多视图资源关联。例如 JSP,FreeMarker等
结果类型
比如我们逻辑视图名是 success,对应 success.jsp,那么我们是请求转发到该页面还是重定向呢。这就需要我们指定结果类型。struts2 提供了一系列的内置结果类型,在 struts-default.xml 中能看到。
<result../>属性
name:逻辑视图名称,应该与Action返回的字符串相同,如果不填写,默认为success
type:结果视图类型,不写的时候默认值为dispatcher(请求转发)
name是去哪里,type是怎么去。
struts 内建支持的常用结果类型
-chain:Action链式处理。当一个Action处理完成之后,系统并不想转发到视图资源,而是希望下一个Action进行处理,此时就需要这个类型。
-dispatcher:请求转发
-redirect:重定向
-redirectAction:重定向到其他Action
-stream:向浏览器返回一个InputStream的结果类型(一般用于文件下载)
Chain 例子
struts.xml文件配置
当发送请求demo1时,返回的结果转发到demo2的Action处理
<package name="demo" extends="struts-default">
<action name="demo1" class="com.cad.struts2.Hello" >
<result type="chain">demo2</result>
</action>
<action name="demo2" >
<result name="success" >/welcome.jsp</result>
<result name="error">/error.jsp</result>
</action>
</package>
不同包之间的请求转发
<package name="demo" extends="struts-default">
<action name="demo1" class="com.cad.struts2.Hello" >
<result type="chain">
//因为结果类型都有对应的实现类,我们到请求转发的实现类中发现,有actionName和namespace两个参数,并提供了get和set方法
//使用的是注入的思想,在请求转发之前,先调用setNamespace和setActionName赋值
<param name="actionName">demo2</param>
<param name="namespace">/user</param>
</result>
</action>
</package>
<package name="demo1" extends="struts-default" namespace="/user">
<action name="demo2" >
<result name="success" >/welcome.jsp</result>
<result name="error">/error.jsp</result>
</action>
</package>
重定向也是一样。
全局结果视图和局部结果视图
我们在包中定义了自己的结果类型,只有在自己的包或者子包中才能使用,在别的包中还是无法使用这个结果类型,为了所有的Action都能使用,我们需要将其变为全局。
例如:如果我们想调用其他包中的错误结果时,我们可以另外定义一个包, 来做为错误结果的处理包。
<package name="myPackage" extends="struts-default" >
<global-results>
<result name="success">/customer/success.jsp</result>
<result name="error">/customer/error.jsp</result>
</global-results>
</package>
然后后面要使用该返回结果的action,可以直接继承这个包,即可以使用相关的结果
<package name="p1" extends="myPackage" namespace="/ns1">
<action name="add" class="cn.ansel.domain.Customer" method="addCustomer"></action>
<action name="update" class="cn.ansel.domain.Customer" method="updateCustomer"></action>
</package>
在这里要注意的是,global-result只能出现在包里面!
Action 访问 Servlet API
第一种方式
Struts2提供了一个ServletActionContext对象可以访问ServletAPI。
例如
HttpServletRequest request=ServletActionContext.getRequest();
HttpServletResponse response=ServletActionContext.getResponse();
ServletContext context=ServletActionContext.getServletContext();
HttpSession session=request.getSession();
第二种方式,实现ServletContextAware,ServletRequestAware,ServletResponseAware三个接口
public class VcodeAction extends ActionSupport implements ServletContextAware,ServletRequestAware,ServletResponseAware {
//定义三个参数
private HttpServletRequest request;
private HttpServletResponse response;
private ServletContext context;
public String execute() throws Exception {
return null;
}
//实现接口中设置参数的方法
@Override
public void setServletResponse(HttpServletResponse response) {
this.response=response;
}
@Override
public void setServletRequest(HttpServletRequest request) {
this.request=request;
}
@Override
public void setServletContext(ServletContext context) {
this.context=context;
}
}
执行流程是什么,谁调用了set方法?
struts的内建拦截器有一个ServletConfig的拦截器。
它会先得到我们的动作类的引用,
然后通过instanceof方法判断我们动作类是否属于ServletContextAware,ServletRequestAware,ServletResponseAware类型
因为我们实现了这个接口,当然属于这个类型
然后获取request,response等
然后调用我们动作类实现的接口方法 setServletResponse,setServletRequest,setServletContext等为我们的request,response赋值。
分文件编写配置文件
struts2允许将一个配置文件分解成多个配置文件,从而进行模块化的设计,也提高了配置文件的可读性。
例如我们有一个商城系统,分为用户模块,订单模块等等很多模块
<struts>
<include file="struts-user.xml"/>
<include file="struts-order.xml"/>
.......
</struts>
PS:本文转载于 https://blog.csdn.net/c99463904/article/details/71075344