通过不少年发展,Struts1已经成为了高度成熟的框架,但随着时间的发展,Struts1的局限性和缺点不断的暴露出来。
如今Struts已经分化成了两个框架
-第一个是在Struts1的基础上,融合了另外一个web框架Webwork的Struts2.Struts2实质上是以Webwork为核心的,和Struts1有很大区别。
-第二个是Shale,与原有Struts1关联不多,使用了全新的设计思想。java
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
持久层:daoweb
(1)下载Struts2spring
目录结构 apps:该文件夹下包含了基于Struts2的示例应用 docs:包含了Struts2的相关文档 lib:包含了Struts2的核心类库,以及Struts2的第三方类库 src:包含了Struts框架的全部源代码
(2)建立web项目,导入struts2所需jar包,lib中有struts2的全部jar包,可是咱们不须要那么多。数据库
咱们只把必需的添加到项目便可。将apps目录下struts2-blank.war压缩包中的lib目录下的jar包添加到咱们项目中便可。这是struts2必需的jar包。
apache
struts使用拦截器做为加强处理,以用户的逻辑控制器为目标,建立一个控制器代理,控制器代理回调业务控制器的execute方法处理用户请求,该方法的返回值决定struts2将怎样的视图资源呈现给用户编程
struts2大体处理流程:后端
(1)浏览器发送请求
(2)核心控制器根据请求决定是否调用相应的Action
(3)struts2内置的拦截器链会自动对请求进行一些操做
(4)回调Action的execute方法,执行操做。
(5)Action会将处理结果存入stack Context中,并返回字符串,核心控制器根据字符串跳转到指定的视图资源。
(6)视图资源会读取Stack Context中的信息,向浏览器生成响应数据。浏览器
只需跟着作便可,先没必要了解为什么这样作。缓存
(1)编辑web应用的web.xml配置文件,配置struts2的核心拦截器。tomcat
<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核心就是核心控制器和业务控制器。
核心控制器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相对应,跳转到不一样页面。
(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核心配置文件是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结尾的请求成功。这也验证了咱们说的配置文件的加载顺序。
Bean配置
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)没匹配到任何命名空间直接报错。
开发者须要提供大量的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> 重定向也是同样。
自定义结果类型
须要实现一个结果类型类,继承StrutsResultSupport类 咱们这里面使用咱们的验证码小工具,输出一个验证码 至于这个验证码小工具,之前的文章中有详细的说明。 public class VcodeResult extends StrutsResultSupport { @Override protected void doExecute(String arg0, ActionInvocation arg1) throws Exception { VerifiCode v=new VerifiCode(); HttpServletResponse response=ServletActionContext.getResponse(); BufferedImage b=v.getImage(); v.output(b, response.getOutputStream()); } }
而后再建立一个Action类 ,什么都不用写 public class VcodeAction extends ActionSupport { }
在struts.xml中进行配置 <package name="vcode" extends="struts-default" > //配置咱们自定义的结果类型 <result-types> <result-type name="vcode" class="com.cad.struts2.VcodeResult"></result-type> </result-types> //咱们仍是在咱们的原页面,因此不须要指定其余页面,type即为咱们的自定义结果类型 <action name="vcode" class="com.cad.struts2.VcodeAction"> <result name="success" type="vcode"></result> </action> </package>
咱们能够在自定义的结果类型类中添加get和set方法,来方便咱们的一些参数自定义。 例如咱们添加了weight,height的get和set方法。 <action name="vcode" class="com.cad.struts2.VcodeAction"> <result name="success" type="vcode"> <param name="weight">100</param> <param name="height">100</param> </result> </action> 咱们就能够自定义验证码的长宽等。这也又体现了咱们的注入思想。 咱们前面请求转发前设置nameSpace和actionName和咱们作的实际上是相同的操做。
全局结果视图和局部结果视图
咱们在包中定义了本身的结果类型,只有在本身的包或者子包中才能使用,在别的包中仍是没法使用这个结果类型,为了全部的Action都能使用,咱们须要将其变为全局。 咱们只须要定义一个包,继承struts2的默认配置文件 <package name="myresult" extends="struts-default"> <result-types> <result-type name="vcode" class="com.cad.struts2.VcodeResult"></result-type> </result-types> <global-results> <result> <param name="weight">500</param> <param name="height">1000</param> </result> </global-results> </package> 而后若是咱们须要这个结果类型,只须要咱们的包继承这个包便可。 在<global-results>中配置全局参数,全部的action使用这个类型生成的验证码尺寸都同样。
第一种方式 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>