Struts2


1. JavaEE软件三层结构和MVC的区别?

JavaEE软件三层机构是由 sun 公司提供 JavaEE 开发规范的: Web( 表现层 ) 、业务逻辑层、数据持久层。【其中 WEB 层会使用前端控制器模式】
MVC是一种思想,是一种模式,将软件分为  Model 模型、 View 视图、 Controller 控制器。【 JavaEE 开发更强调三层结构, web 层开发更注重 MVC
Struts2 就是web层开发框架 ,符合 MVC 模式; struts1 webwork jsf SpringMVC  都是 MVC 

2. Struts和struts2的区别有哪些?

Action类 
Struts 1要求Action类要扩展自一个抽象基类。Struts 1的一个共有的问题是面向抽象类编程而不是面向接口编程。 
Struts 2的Action类实现了一个Action接口,连同其他接口一起实现可选择和自定义的服务。Struts 2提供一个名叫ActionSupport的基类实现一般使用的接口。虽然,Action接口不是必须的。任何使用execute方法的POJO对象可以 被当作Struts 2Action对象使用。 
程模型 
Struts 1 Action类是单例类,因只有一个示例控制所有的请求。单例类策略造成了一定的限制且给开发带来了额外的烦恼。Action资源必须是程安全或者同步 的。 
Struts 2 Action对象每一个请求都实例化对象,所以没有程安全的问题。(实践中,servlet容器生许多丢的对象对于每一个请求,多于一个的对象并不影响垃 圾收集) 
Servlet 依赖 
Struts 1的Action类依赖于servlet APIHttpServletRequestHttpServletResponse作参数传给execute方法当Action被调用时。 
Struts 2的Action不和容器有关。Servlet上下文被表现简单的Maps,允许Action被独立的测试。Struts 2Action可以访问最初的请求和相应,如果需要的话。然而,其他的架构元素少或者排除直接访问HttpServletRequest或者 HttpServletResponse的需要。 
易测性 
测试Struts 1的主要障碍是execute方法暴露了Servlet API。第三方的扩展,Struts测试用例,提供Struts 1的集合对象。 
Struts 2的Action可以通过实例化Action测试,设置属性,然后调用方法。依赖注入的支持也是测试变得更简单。 
接受输入 
Struts 1使用ActionForm对象捕获输入。象Action一样,所有的ActionForm必须扩展基类。因其他的JavaBean不能作 ActionForm使用,开发者经常创建多余的类捕获输入。DynaBeans可以被用来作替代ActionForm的类创建。但是开发者可以重新描述 已经存在的JavaBean。 
Struts 2 Action属性作输入属性,排除第二个输入对象的需要。输入属性可能有丰富的对象类型这些类型有他们自己的属性。Action的属性可以通过标签库访 问。Struts 2也支持ActionForm形式。丰富的对象类型,包含业务或者域对象,可以被当作输入或者输出对象使用。馍型驱动特性简化标签对POJO输入对象的引 用。 
表达式语言 
Struts 1整和JSTL,所以它使用JSTL的表达式语言。表达式语言有基本的图形对象移动,但是相对很弱的集合和被索引的属性支持。 
Struts 2使用JSTL,但是框架也支持更大和更灵活的表达式,叫做对象图形符号语言OGNL)。 
将值绑定要视图上 
Struts 1使用标准JSP机制来绑定对象到页面上下文。 
Struts 2使用“ValueStack”技术了标签库可以不用链接你的视图到对象的表现类型访问值。ValueStack策略允许重用视图。 
类型转换 
Struts 1的ActionForm属性经常都是String的。Struts 1使用Commons-Beanutils类型转换。转换每一个类,不是每一个实例配置。 
Struts 2使用OGNL类型转换。框架包含转换器基本的和共同的对象类型和原始类型。 
验证 
Struts 1支持手动验证凭借ActionFormvalidate方法,或者通过扩展的公用验证器。类可以有不同的验证上下文未相同的类,但是不能不能包括验证 子对象。 
Struts 2支持手动验证凭借validate方法和XWork验证框架。Xwork验证框架支持一连串的验证子属性使用的验证了属性类的类型和严正上下文而定义。 
Action执行的控制 
Struts 1支持独立的请求处理器对于每一个模型,但是所有在模型中的Action必须共享同一个生命周期。 
Struts 2支持在每一个Action基础上凭借拦截栈创建不同的生命周期。自定义栈可以被创建且使用不同的所需 的Action

3. 简要说说Struts2的处理流程

Struts2 框架的大致处理流程如下:
1 、加载类( FilterDispatcher
2 、读取配置( struts 配置文件中的 Action
3 、派发请求(客户端发送请求)
4 、调用 Action FilterDispatcher struts 配置文件中读取与之相对应的 Action 
5 、启用拦截器( WebWork 拦截器链自动对请求应用通用功能,如验证)
6 、处理业务(回调 Action execute() 方法)
7 、返回响应(通过 execute 方法将信息返回到 FilterDispatcher
8 、查找响应( FilterDispatcher 根据配置查找响应的是什么信息如: SUCCESS ERROER ,将跳转到哪个 jsp 页面)
9 、响应用户( jsp---> 客户浏览器端显示)
10 struts2 标签库(相比 struts1 的标签库, struts2 是大大加强了,对数据的操作功能很强大)

 

请求(.action)---->经过StrutsPrepareAndExecuteFilter 核心控制器---->进入到Struts2的拦截器Interceptor(实现代码功能)----->通过action的名称找对应的Action----->执行Action类的execute方法----->通过execute方法中返回的字符串,在Struts.xml中找对应的结果页面(result)【在action执行之前,执行了defaultStack拦截器栈

拦截器 在 struts-default.xml定义 【它位于sruts2-core-xxx.jar目录下

执行拦截器 是 defaultStack 中引用拦截器

4、Struts2配置文件加载顺序

    通过查看StrutsPrepareAndExecuteFilter源码可以得到答案!
            
    此处,我们以及清晰了看到了该类加载配置文件的顺序,我们依次围绕标号查看对应方法产生的文件即可。

    
    对应产生文件依次如下:
 
   
    init_DefaultProperties(); // [1]----  org/apache/struts2/default.properties
 
    init_TraditionalXmlConfigurations(); // [2] --- struts-default.xml,struts-plugin.xml,struts.xml
 
    init_LegacyStrutsProperties(); // [3] --- 自定义struts.properties
 
    init_CustomConfigurationProviders(); // [5]  ----- 自定义配置提供
 
    init_FilterInitParameters() ; // [6] ----- web.xml
 
    init_AliasStandardObjects() ; // [7] ---- Bean加载
结论  :【前三个是默认的,不用关注,后面三个需要注意】
     ①  default.properties  该文件保存在  struts2-core-2.3.7.jar  中  org.apache.struts2 包里面    (常量的默认值)
     ②  struts-default.xml  该文件保存在  struts2-core-2.3.7.jar   ( Bean 、拦截器、结果类型  )
     ③  struts-plugin.xml  该文件保存在 struts-Xxx-2.3.7.jar   (在插件包中存在  ,配置插件信息  ) struts-config-browser-plugin-2.3.7.jar 里面有
     ④  struts.xml  该文件是 web 应用默认的 struts 配置文件  (实际开发中,通常写 struts.xml  )
     ⑤  struts.properties  该文件是 Struts 的默认配置文件   ( 配置常量  )
     ⑥  web.xml  该文件是 Web 应用的配置文件  ( 配置常量  )

后加载配置文件中修改的常量的值会覆盖前面配置文件修改的常量的值!

5、我们在书写Action的时候有哪几种方式?他们有什么区别?

有三种方式:
     普通POJO(简单Java对象), 这种方式我们不需要继承任何父类,实现任何接口。Struts2框架读取struts.xml文件,获得完整的action类名。
 
     
  1. obj =Class.forName("完整类名").newInstance();
  2. Method m =Class.forName("完整类名").getMethod("execute");
  3. m.invoke(obj);//通过反射 执行execute()方法
     编写Action实现Action接口
 
     
  1. Action接口中,定义默认五种逻辑视图名称
  2. // 数据处理成功 (成功页面)
  3. publicstatic final String SUCCESS ="success";
  4. // 页面不跳转 return null; 效果一样
  5. publicstatic final String NONE ="none";
  6. // 数据处理发送错误 (错误页面)
  7. publicstatic final String ERROR ="error";
  8. // 用户输入数据有误,通常用于表单数据校验 (输入页面)
  9. publicstatic final String INPUT ="input";
  10. // 主要权限认证 (登陆页面)
  11. publicstatic final String LOGIN ="login";
     编写Action继承ActionSupport(推荐)
在Action中使用 表单校验、错误信息设置、读取国际化信息三个功能 
 
     
  1. 代理模式,控制目标对象访问
  2. /hello.action 请求时StrutsPrepareAndExecuteFilter doFilter一定执行
  3. //判断配置文件中有没有对应Action
  4. ActionMapping mapping = prepare.findActionMapping(request, response,true);
  5. //根据配置创建代理对象
  6. ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(namespace, name, method, extraContext,true,false);
  7. 执行时:先执行interceptorintercept拦截方法,最后指向actionexecute

6、Action是如何接受请求参数的?

属性驱动和模型驱动   
 Struts2内部提供了参数封装功能,不需要使用BeanUtils进行封装。Struts2大部分内置功能都是拦截器实现的。
    
    当点击登录提交表单时,就会被下面的拦截器进行封装,进行set注入值,实现参数封装。
 
     
<interceptor name="params"class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>

第一种 :Action 本身作为model对象,通过成员setter封装 (属性驱动 )
    主要用于参数较少的封装,如果分层,不利于将数据传递到业务层。
    页面:        
 
    
用户名:<inputtype="text"name="username"/><br/>
    Action: 
 
    
publicclassRegistAction1extendsActionSupport{
privateString username;
publicvoid setUsername(String username){
this.username = username;
}
}
    Struts2 action是多实例,不会有线程安全问题,使用这种数据封装方式,数据封装到action属性中,不能将action对象传递给业务层,我们需要再单独定义javabean,将action属性封装到javabean。

第二种 :创建独立model对象,页面通过ognl表达式封装 (属性驱动)
     具体封装流程如下:传递 username ,调用 setUsername ,把 username 注入 User 中,将会新建一个 User 对象,当第二个参数 password 传递过来时, struts 框架将首先调用 getUser 方法询问 User 是否为空,如果为空,将会新建一个 User ,否则不会新建,直接注入值。如果只有一个 Set 方法,那么每 set 一次数据,就会新建一个 User 对象,那么就是把 username password 封装在两个不同的 User 对象中了。这样封装失败。
    页面: 
 
     
<!--基于OGNL表达式的写法-->
用户名:<inputtype="text"name="user.username"/><br/>
密 码: <input type = "password" name = "user.password" /> <br/>
    model(User):
 
      
publicclassUser{
privateString username;
privateString password;
publicString getUsername(){
return username;
}
publicvoid setUsername(String username){
this.username = username;
}
publicString getPassword(){
return password;
}
publicvoid setPassword(String password){
this.password = password;
}
}
    Action:
 
    
publicclassRegistAction2extendsActionSupport{
    privateUser user;
publicvoid setUser(User user){
    this.user = user;
}
//必须提供get方法(封装第一个参数时,创建新的User对象, 封装第二个参数需要使用第一个创建user对象)
publicUser getUser(){
    return user;
    }
}
    由params的拦截器完成参数的封装
 
    
<interceptorname="params"class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>

第三种 :使用ModelDriven接口,对请求数据进行封装 (模型驱动 ) ----- 企业开发的主流(模型驱动有很多特性)
 
     
<interceptorname="modelDriven"class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/> 为模型驱动提供了更多特性
    页面:
 
     
用户名:<inputtype="text"name="username"/><br/>  
    model(User):
    
    Action :
 
    
publicclassRegistAction3extendsActionSupportimplementsModelDriven<User>{
// 模型对象必须手动实例化
    privateUser user =newUser();
publicUser getModel(){
    return user;
}
}
    对比第二种、第三种 : 第三种只能在Action中指定一个model对象(返回一个model对象),第二种可以在Action中定义多个model对象 
 
    
<inputtype="text"name="user.username"/> 
<inputtype="text"name="product.info"/>

7、Action的相关配置?

   1 ) 必须要为 <action>元素 配置<package>元素  (struts2 围绕package进行Action的相关配置 )

    配置package 三个常用属性

 
   
<packagename="default"namespace="/"extends="struts-default">
     ① name 包名称,在 struts2 的配置文件中,包名不能重复, name 并不是真正包名,只是为了管理 Action

    ②namespace和 <action>的name属性,决定 Action的访问路径  (以/开始 )

          namespace=""          :默认的名称空间
         namespace="/"         :根名称空间
         namespace="/aa/"     :带有名称空间的路径

    ③extends继承哪个包,通常开发中继承struts-default包  (struts-default包在 struts-default.xml中定义 )【可以使用包中默认的拦截器和结果集】

    2)Action是通过<action>元素配置

 
   
<action name="hello"class="cn.itcast.struts2.demo1.HelloAction" method="execute">
     <action> 的 name 和  <package> 的 namespace 属性共同决定  Action 的访问路径
     class :类全路径
     method :执行的方法,默认为execute()方法

例如:

 
   
<package name="default"namespace="/user" extends="struts-default">
    <action name="hello"class="cn.itcast.struts2.demo1.HelloAction">
        <result name="success">/demo1/success.jsp</result>
    </action>
</package>
此时的访问路径  http://localhost:8080/Struts2/demo1 /user/hello.action
     result中的 name :结果页面逻辑视图名称,默认为success
     type:结果类型(后面会做详细介绍,默认为转发)

 3) <action> 元素配置默认值

    <package>  的 namespace  默认值  /
    <action>  的 class  默认值  ActionSupport  类        <default-class-ref class="com.opensymphony.xwork2.ActionSupport" />     
    <result>  的  name  默认值  success

8、Action访问Servlet API有哪几种方式,简单的介绍一下

①.方式一:使用 ActionContext对象(在Action中解耦合方式间接访问Servlet API)
    在struts2中Action API已经与Servlet API 解耦合(没有依赖关系),开发简单,便于测试。
    Servlet API 常见操作 :  表单提交请求参数获取,向request、session、application三个范围存取数据  
.方式二:使用接口注入的方式操作Servlet API(藕合)
    通过 Aware接口,在构造Action时,自动注入需要操作Servlet对象(需要哪个对象就实现哪个Aware接口)
③.方式三:在Action中直接通过  ServletActionContext 获得Servlet API
    静态方法返回request,不会有线程问题(使用了ThreadLocal来实现的)
总结:理论来说,第一种方式最好,实现了解耦和,但是第三种我们使用最为简单,企业中没有很大的限制,自己熟悉哪种就使用哪种。

9. 说说Struts2的输入校验流程

Struts2校验框架进行校验时,将执行以下流程:
A:类型转换器负责对字符串的请求参数执行类型转换,并将这些值设置成 Action 的属性值
B:在执行类型转换过程中可能出现异常,如果出现异常,将异常信息保存到 ActionContext 中, convertionError 拦截器将负责将其封装到 fieldError 里,如果没有异常,直接进入第 3
C:调用 Struts2 的内置校验规则进行输入校验
D:通过反射调用 validateXXX() 方法
E:调用 Action 类中的 validate() 方法
F:如果上面的几步中没有出 FiledError ,就调用 Acton 中的逻辑处理方法,如果有,则进入 input 视图
所以,在进行校验时,别忘记在 Action 中的配置名为 input 的结果如: <result name= “ input>validate.jsp</result>

10. Struts2 form标签数据为什么可以回显?


11. 什么是值栈?值栈的内部结构?

    ValueStack 是 struts2 提供一个接口,实现类 OgnlValueStack ---- 值栈对象 (OGNL是从值栈中获取数据的 )每个Action实例都有一个ValueStack对象 (一个请求对应 一个ValueStack对象 )在其中保存当前Action 对象和其他相关对象 (值栈中是有Action引用的 )Struts 框架把 ValueStack 对象保存在名为“struts.valueStack” 的请求属性中,request中(值栈对象是request一个属性)


    值栈由两部分组成,ObjectStack和ContextMap
ObjectStack: Struts  把动作和相关对象压入  ObjectStack --List
ContextMap: Struts 把各种各样的映射关系 ( 一些  Map  类型的对象 压入 ContextMap Struts 会把下面这些映射压入  ContextMap 
parameters: 该  Map  中包含当前请求的请求参数
request: 该  Map  中包含当前  request  对象中的所有属性
session: 该  Map  中包含当前  session  对象中的所有属性
application:该  Map  中包含当前  application   对象中的所有属性
attr:  该  Map  按如下顺序来检索某个属性 : request, session, application

VaValueStack中 存在root属性 (CompoundRoot) 、 context 属性 (OgnlContext )
    * CompoundRoot 就是ArrayList
    * OgnlContext 就是 Map
cncontext 对应Map 引入 root对象 
    * context中还存在 request、 session、application、 attr、 parameters 对象引用 
    * OGNL表达式,访问root中数据时 不需要 #, 访问 request、 session、application、 attr、 parameters 对象数据 必须写 # 
    * 操作值栈 默认指 操作 root 元素

12. 值栈对象的创建 ,ValueStack 和 ActionContext 是什么关系 ?

值栈对象是请求时创建的 
doFilter中 prepare.createActionContext(request, response); 
    * 创建ActionContext对象过程中,创建值栈对象ValueStack 
    * ActionContext对象对ValueStack对象有引用的(在程序中通过 ActionContext 获得值栈对象 ) 
Dispatcher类 serviceAction 方法中将值栈对象保存到request范围
    request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());

13.如何获得值栈对象?

获得值栈对象 有两种方法
    ValueStack valueStack = (ValueStack) ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
    ValueStack valueStack2 = ActionContext.getContext().getValueStack();

14.如何向值栈中保存数据?如何在jsp页面中获取值栈的数据?

两种方式 
    // 将数据保存root的索引0位置,放置到第一个元素 ArrayList add(0,element);
    valueStack.push("itcast");
    // 在值栈创建参数map, 将数据保存到map中
    valueStack.set("company", "传智播客");
在jsp中 通过 <s:debug /> 查看值栈的内容 

 



获取值栈数据时,如果访问root中数据不需要# ,访问其它对象数据加 #
通过下标获取root中对象
<s:property value="[0].top"/> //取值栈顶对象
直接在root中查找对象属性 (自上而下自动查找)
valueStack:<s:property value="username"/>

在OgnlContext中获取数据
request:<s:property value="#request.username"/>
session:<s:property value="#session.username"/>
application:<s:property value="#application.username"/>
attr:<s:property value="#attr.username"/>
parameters:<s:property value="#parameters.cid[0]"/>

15.为什么EL也能访问值栈中的数据?

StrutsPreparedAndExecuteFilter的doFilter代码中 request = prepare.wrapRequest(request); 
* 对Request对象进行了包装 ,StrutsRequestWrapper 
* 重写request的 getAttribute 
Object attribute = super.getAttribute(s);
if (attribute == null) {
    attribute = stack.findValue(s);
}
访问request范围的数据时,如果数据找不到,去值栈中找 

16.你在开发中,值栈主要有哪些应用?

值栈主要解决Action向JSP传递数据问题
Action 向JSP 传递数据处理结果 ,结果数据有两种形式 
1)消息 String类型数据
this.addFieldError("msg", "字段错误信息");
this.addActionError("Action全局错误信息");
this.addActionMessage("Action的消息信息");
* fieldError 针对某一个字段错误信息 (常用于表单校验)、actionError (普通错误信息,不针对某一个字段 登陆失败)、 actionMessage 通用消息 

在jsp中使用 struts2提供标签 显示消息信息
<s:fielderror fieldName="msg"/>
<s:actionerror/>
<s:actionmessage/>
2)数据 (复杂类型数据)
使用值栈  valueStack.push(products);
哪些数据默认会放入到值栈 ??? 
1)每次请求,访问Action对象 会被压入值栈 ------- DefaultActionInvocation 的 init方法 stack.push(action);
    * Action如果想传递数据给 JSP,只有将数据保存到成员变量,并且提供get方法就可以了 
2)ModelDriven 接口有一个单独拦截器
<interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>
在拦截器中,将model对象压入了值栈 stack.push(model);
    * 如果Action 实现ModelDriven接口,值栈默认栈顶对象就是model对象 

17.如何防止表单重复提交?

哪些情况会导致重复提交?
    服务器处理服务后,转发页面,客户端点击刷新(重定向)
    客户端网络过慢,按钮连续点击(按钮点击一次后,禁用按钮)
使用令牌机制

18.简单的说一下ActionProxy的运行原理?

Struts2的拦截器的本质就是AOP思想,而AOP就是基于代理模式。

19.Struts2详细运行流程


    请求首先通过Filter chain,Filter主要包括ActionContextCleanUp,它主要清理当前线程的ActionContext和Dispatcher;FilterDispatcher主要通过AcionMapper来决定需要调用哪个Action。
    ActionMapper取得了ActionMapping后,在Dispatcher的serviceAction方法里创建ActionProxy,ActionProxy创建ActionInvocation,然后ActionInvocation调用Interceptors,执行Action本身,创建Result并返回,当然,如果要在返回之前做些什么,可以实现PreResultListener。 

部分类介绍
    ActionMapper 
    ActionMapper其实是HttpServletRequest和Action调用请求的一个映射,它屏蔽了Action对于Request等java Servlet类的依赖。Struts2中它的默认实现类是DefaultActionMapper,ActionMapper很大的用处可以根据自己的需要来设计url格式,它自己也有Restful的实现,具体可以参考文档的docs\actionmapper.html。
     ActionProxy&ActionInvocation 
    Action的一个代理,由ActionProxyFactory创建,它本身不包括Action实例,默认实现DefaultActionProxy是由ActionInvocation持有Action实例。ActionProxy作用是如何取得Action,无论是本地还是远程。而ActionInvocation的作用是如何执行Action,拦截器的功能就是在ActionInvocation中实现的。
     ConfigurationProvider&Configuration 
    ConfigurationProvider就是Struts2中配置文件的解析器,Struts2中的配置文件主要是尤其实现类XmlConfigurationProvider及其子类StrutsXmlConfigurationProvider来解析。

Struts2请求流程
    1、客户端发送请求 
    2、请求先通过ActionContextCleanUp-->FilterDispatcher 
    3、FilterDispatcher通过ActionMapper来决定这个Request需要调用哪个Action 
    4、如果ActionMapper决定调用某个Action,FilterDispatcher把请求的处理交给ActionProxy,这儿已经转到它的Delegate--Dispatcher来执行
    5、ActionProxy根据ActionMapping和ConfigurationManager找到需要调用的Action类 
    6、ActionProxy创建一个ActionInvocation的实例 
    7、ActionInvocation调用真正的Action,当然这涉及到相关拦截器的调用 
    8、Action执行完毕,ActionInvocation创建Result并返回,当然,如果要在返回之前做些什么,可以实现PreResultListener。添加PreResultListener可以在Interceptor中实现。

源代码分析
      启动服务器(tomcat)将会自动加载配置文件,加载过程如下:
        服务器启动,init()方法被执行
    
    客户端初始化一个指向Servlet容器(WEB容器)的请求;

    这个请求经过一系列的过滤器(Filter)(这些过滤器中有一个叫做ActionContextCleanUp的可选过滤器,这个过滤器对于Struts2和其他框架的集成很有帮助,例如:(SiteMesh Plugin)。

     接着StrutsPrepareAndExecuteFilter被调用,StrutsPrepareAndExecuteFilter询问ActionMapper来决定这个请求是否需要调用某个Action。
    

     如果ActionMapper决定需要调用某个Action,FilterDispatcher把请求的处理交给ActionProxy。ActionProxy通过Configuration Manager询问框架的配置文件,找到需要调用的Action类
    
    
     ActionProxy创建一个ActionInvocation的实例。ActionInvocation实例使用命名模式来调用,在调用Action的过程前后,涉及到相关拦截器(Intercepter)的调用。拦截器默认执行<default-interceptor-ref name="defaultStack"/>defaultStack里面有一系列的interceptor。

     一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。返回结果通常是(但不总是,也可能是另外的一个Action链)一个需要被表示的JSP或者FreeMarker的模版。在表示的过程中可以使用Struts2框架中继承的标签。在这个过程中需要涉及到ActionMapper,响应的返回是通过我们在web.xml中配置的过滤器  

     如果ActionContextCleanUp是当前使用的,则FilterDispatecher将不会清理threadlocal ActionContext;如果ActionContextCleanUp不使用,则将会去清理threadlocals。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值