关于struts2中ActionContext的实现原理

2023-12-20 03:58

本文主要是介绍关于struts2中ActionContext的实现原理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转载地址:http://blog.51cto.com/yangfei520/1565698

转载地址:https://blog.csdn.net/smcfy/article/details/5693481

转载地址:https://blog.csdn.net/smcfy/article/details/5693481

ActionContext与ServletActionContext的区别及获取request、session等对象

转载  2014年08月22日 13:42:45
  • 12641

我们知道struts2接受客户端请求,在Action中进行处理后,将视图结果返回。struts2容器自身不依赖于web容器,不用和servlet对象中的请求(request)、响应(response)进行关联,对于请求的参数,通过paramerInterceptor将参数封装在Action中,然后通过调用get、set方法将参数值设置进Action之中。如果仅仅获取参数,可能有时候满足不了开发的需求,有时我们要获取request或者response中的信息,要对其进行设置、处理。

 

一、ActionContext

    是Action执行的上下文,Action的上下文可以看作是一个容器,里面封装了请求(Request)、会话(Session)、Application等,这里面的Request、Session、Application是Map类型的,往里面封装的是键值对,所以这就体现了struts2不与底层servlet Api打交道,那么对很多web的相关对象进行封装,这样可以达到Action与web层解耦。

用ActionContext得到Map类型的Request、Session、Application。

例子:

    获取request:

     Map request = ActionContext.getContext().get("request");

    往request里封装数据

    request.put("name", value);

    在前台就可以用request.getAttribute("name");

   

    获取session

    Map session = ActionContext.getContext().getSession();

    将数据封装到session中

    session.put("name", value);

    在前台页面上用sessionScope.getAttribute("name");得到session里面封装的值。

得到session、request有点区别,得到request用的是get("reqeust"),得到session用的是getSession()

 

也可以直接对Java Servlet Http的请求(HttpServletRequest)、响应(HttpServletResponse)操作,和上面的例子有点区别,注意区别

ActionContext ctx = ActionContext.getContext();       
      
  HttpServletRequest request = (HttpServletRequest)ctx.get(ServletActionContext.HTTP_REQUEST);
  HttpServletResponse response = (HttpServletResponse)ctx.get(ServletActionContext.HTTP_RESPONSE);

用法就和Servlet中的request、response用法一样

 

二、ServletActionContext

它继承ActionContext,所以ServletActionContext也可以得到HttpServetRequest、HttpServletResponse,,它也提供了直接与Servlet相关对象访问的功能,它可以取得的对象有:

(1)javax.servlet.http.HttpServletRequest : HTTPservlet请求对象

(2)javax.servlet.http.HttpServletResponse : HTTPservlet相应对象

(3)javax.servlet.ServletContext : Servlet上下文信息

(4)javax.servlet.ServletConfig : Servlet配置对象

(5)javax.servlet.jsp.PageContext : Http页面上下文

 

如何获取HttpRequest、HttpResponse

例子

  HttpServletRequest request = ServletActionContext.getRequest();

  HttpServletResponse response = ServletActionContext.getResponse();

然后就可以用request.setAttribute("name", value)方法了。

 

总结:不难看出,两者之间还是存在很多共同功能,那么我们还是根据自己的需求进行选择,能用ActionContext对象满足就尽量使用ActionContext,避免让我们直接去访问Servlet对象。另外,不要在Action还没实例化的时候去通过ActionContext调用方法,因为Action实例在ActionContext实例之前创建,ActionContext中一些值还没有设置,会返回null。


 为了避免与Servlet API耦合在一起,方便Action类做单元测试,Struts 2对HttpServletRequest、HttpSession和ServletContext进行了封装,构造了三个Map对象来替代这三种对象,在Action中,直接使用HttpServletRequest、HttpSession和ServletContext对应的Map对象来保存和读取数据。

(一)通过ActionContext来获取request、session和application对象的LoginAction1

[java]  view plain  copy
  1. ActionContext context = ActionContext.getContext();   
  2. Map request = (Map)context.get("request");  
  3. Map session = context.getSession();  
  4. Map application = context.getApplication();  
  5. request.put("greeting""欢迎您来到程序员之家");//在请求中放置欢迎信息。  
  6. session.put("user", user);//在session中保存user对象  
  7. application.put("counter", count);  
  

在JSP中读取

[xhtml]  view plain  copy
  1. <body><h3>${sessionScope.user.username},${requestScope.greeting}。<br>本站的访问量是:${applicationScope.counter}</h3>  
  2. </body>  

(二)直接使用ActionContex类的put()方法

ActionContext.getContext().put("greeting", "欢迎您来到http://www. sunxin.org");

然后在结果页面中,从请求对象中取出greeting属性,如下:

${requestScope.greeting} 或者 <%=request.getAttribute("greeting")%>

 

以下是原博客的地址,以备查阅http://apps.hi.baidu.com/share/detail/9065250



为一个问题“struts2如何保证ActionContext每次取的都是本次请求所对应的实例?”,给一个网友解释了半天。

   首先,我们知道,struts2struts1的一个重要区别就是它进行了Action类和Servlet的解耦。而又提供了获取Servlet API的其它通道,就是ActionContext(别跟我说还有个ServletActionContext,其实ServletActionContext只是ActionContext的一个子类而已)。源码为证:

1
public  class  ServletActionContext  extends  ActionContext  implements  StrutsStatics

   其次,他也知道,ActionContextAction执行时的上下文,可以看作是一个容器,并且这个容器只是一个Map而已,在容器中存放的是Action在执行时需要用到的VALUE_STACKACTION_NAMESESSIONAPPLICATIONACTION_INVOCATION等等对象,还可以存放自定义的一些对象。我想用过struts2的朋友们,大多也都知道这些吧。

   第三,他奇怪的是,在一个请求的处理过程拦截器、action类和result中任何时候获取的ActionContext都是跟当前请求绑定那一个。为什么!?

 

我给他的建议是,带着问题读源码,呵呵。那我们一起来看看吧:

首先ActionContext类的源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
public  class  ActionContext  implements  Serializable{
   static  ThreadLocal actionContext =  new  ThreadLocal();
   public  static  final  String ACTION_NAME =  "com.opensymphony.xwork2.ActionContext.name" ;
   public  static  final  String VALUE_STACK =  "com.opensymphony.xwork2.util.ValueStack.ValueStack" ;
   public  static  final  String SESSION =  "com.opensymphony.xwork2.ActionContext.session" ;
   public  static  final  String APPLICATION =  "com.opensymphony.xwork2.ActionContext.application" ;
   public  static  final  String PARAMETERS =  "com.opensymphony.xwork2.ActionContext.parameters" ;
   public  static  final  String LOCALE =  "com.opensymphony.xwork2.ActionContext.locale" ;
   public  static  final  String TYPE_CONVERTER =  "com.opensymphony.xwork2.ActionContext.typeConverter" ;
   public  static  final  String ACTION_INVOCATION =  "com.opensymphony.xwork2.ActionContext.actionInvocation" ;
   public  static  final  String CONVERSION_ERRORS =  "com.opensymphony.xwork2.ActionContext.conversionErrors" ;
   public  static  final  String CONTAINER =  "com.opensymphony.xwork2.ActionContext.container" ;
   Map<String, Object> context;
   public  ActionContext(Map<String, Object> context)
   {
     this .context = context;
   }
   //... ...
   public  static  void  setContext(ActionContext context)
   {
     actionContext.set(context);
   }
   public  static  ActionContext getContext()
   {
     return  (ActionContext)actionContext.get();
   }
   public  void  setContextMap(Map<String, Object> contextMap)
   {
     getContext().context = contextMap;
   }
   public  Map<String, Object> getContextMap()
   {
     return  this .context;
   }
   //... ...
   public  void  setSession(Map<String, Object> session)
   {
     put( "com.opensymphony.xwork2.ActionContext.session" , session);
   }
   public  Map<String, Object> getSession()
   {
     return  (Map)get( "com.opensymphony.xwork2.ActionContext.session" );
   }
   //... ...
   public  Object get(String key)
   {
     return  this .context.get(key);
   }
   public  void  put(String key, Object value)
   {
     this .context.put(key, value);
   }
}

源码清晰的说明了我们编程中再熟悉不过的一行代码:ActionContext ctx = ActionContext.getContext();,原来我们所取得的ctx来自于ThreadLocal啊!熟悉ThreadLocal的朋友都知道它是与当前线程绑定的,而且是我们Java中处理多线程问题的一种重要方式。我们再看,类中有个Map类型的变量context,其实,它才是前面我们提到的真正意义上的“容器”,用来存放Action在执行时所需要的那些数据。

    到这里,他最初的那个问题已经很了然了。但是,他紧接着又一个疑惑提出来了:“那既然每个请求处理线程都有自己的ActionContext,那里面的那些数据是什么时候放进去的呢”?

   这次我给他的建议是,动脑筋,用源码验证。既然ActionContext存放有HttpServletRequest及其中的参数,既然ActionContext贯穿于整个请求处理过程,那就从struts2请求处理的入口(过滤器StrutsPrepareAndExecuteFilter)找,源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public  class  StrutsPrepareAndExecuteFilter  implements  StrutsStatics, Filter
{
   // ... ...
   public  void  doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
     throws  IOException, ServletException
   {
     HttpServletRequest request = (HttpServletRequest)req;
     HttpServletResponse response = (HttpServletResponse)res;
     try
     {
       this .prepare.setEncodingAndLocale(request, response);
       this .prepare.createActionContext(request, response); //就是在这里进行创建并初始化ActionContext实例
       this .prepare.assignDispatcherToThread();
       if  (( this .excludedPatterns !=  null ) && ( this .prepare.isUrlExcluded(request,  this .excludedPatterns))) {
         chain.doFilter(request, response);
       else  {
         request =  this .prepare.wrapRequest(request);
         ActionMapping mapping =  this .prepare.findActionMapping(request, response,  true );
         if  (mapping ==  null ) {
           boolean  handled =  this .execute.executeStaticResourceRequest(request, response);
           if  (!handled)
             chain.doFilter(request, response);
         }
         else  {
           this .execute.executeAction(request, response, mapping);
         }
       }
     finally  {
       this .prepare.cleanupRequest(request);
     }
   }
    //... ...
}

再找到prepare对应的类PrepareOperations,查看方法createActionContext(),就一目了然了。

   对于ServletActionContext作为ActionContext一个直接子类,原理也是类似的,感兴趣的朋友可以看一下。


这篇关于关于struts2中ActionContext的实现原理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/514683

相关文章

Python中pywin32 常用窗口操作的实现

《Python中pywin32常用窗口操作的实现》本文主要介绍了Python中pywin32常用窗口操作的实现,pywin32主要的作用是供Python开发者快速调用WindowsAPI的一个... 目录获取窗口句柄获取最前端窗口句柄获取指定坐标处的窗口根据窗口的完整标题匹配获取句柄根据窗口的类别匹配获取句

在 Spring Boot 中实现异常处理最佳实践

《在SpringBoot中实现异常处理最佳实践》本文介绍如何在SpringBoot中实现异常处理,涵盖核心概念、实现方法、与先前查询的集成、性能分析、常见问题和最佳实践,感兴趣的朋友一起看看吧... 目录一、Spring Boot 异常处理的背景与核心概念1.1 为什么需要异常处理?1.2 Spring B

Python位移操作和位运算的实现示例

《Python位移操作和位运算的实现示例》本文主要介绍了Python位移操作和位运算的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1. 位移操作1.1 左移操作 (<<)1.2 右移操作 (>>)注意事项:2. 位运算2.1

如何在 Spring Boot 中实现 FreeMarker 模板

《如何在SpringBoot中实现FreeMarker模板》FreeMarker是一种功能强大、轻量级的模板引擎,用于在Java应用中生成动态文本输出(如HTML、XML、邮件内容等),本文... 目录什么是 FreeMarker 模板?在 Spring Boot 中实现 FreeMarker 模板1. 环

Qt实现网络数据解析的方法总结

《Qt实现网络数据解析的方法总结》在Qt中解析网络数据通常涉及接收原始字节流,并将其转换为有意义的应用层数据,这篇文章为大家介绍了详细步骤和示例,感兴趣的小伙伴可以了解下... 目录1. 网络数据接收2. 缓冲区管理(处理粘包/拆包)3. 常见数据格式解析3.1 jsON解析3.2 XML解析3.3 自定义

SpringMVC 通过ajax 前后端数据交互的实现方法

《SpringMVC通过ajax前后端数据交互的实现方法》:本文主要介绍SpringMVC通过ajax前后端数据交互的实现方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价... 在前端的开发过程中,经常在html页面通过AJAX进行前后端数据的交互,SpringMVC的controll

Spring Security自定义身份认证的实现方法

《SpringSecurity自定义身份认证的实现方法》:本文主要介绍SpringSecurity自定义身份认证的实现方法,下面对SpringSecurity的这三种自定义身份认证进行详细讲解,... 目录1.内存身份认证(1)创建配置类(2)验证内存身份认证2.JDBC身份认证(1)数据准备 (2)配置依

利用python实现对excel文件进行加密

《利用python实现对excel文件进行加密》由于文件内容的私密性,需要对Excel文件进行加密,保护文件以免给第三方看到,本文将以Python语言为例,和大家讲讲如何对Excel文件进行加密,感兴... 目录前言方法一:使用pywin32库(仅限Windows)方法二:使用msoffcrypto-too

Java Spring 中 @PostConstruct 注解使用原理及常见场景

《JavaSpring中@PostConstruct注解使用原理及常见场景》在JavaSpring中,@PostConstruct注解是一个非常实用的功能,它允许开发者在Spring容器完全初... 目录一、@PostConstruct 注解概述二、@PostConstruct 注解的基本使用2.1 基本代

C#使用StackExchange.Redis实现分布式锁的两种方式介绍

《C#使用StackExchange.Redis实现分布式锁的两种方式介绍》分布式锁在集群的架构中发挥着重要的作用,:本文主要介绍C#使用StackExchange.Redis实现分布式锁的... 目录自定义分布式锁获取锁释放锁自动续期StackExchange.Redis分布式锁获取锁释放锁自动续期分布式