ActionContext

ActionContext是Action的上下文,Struts2自动在其中保存了一些在Action执行过程中所需的对象,比如session, parameters, locale等。Struts2会根据每个执行HTTP请求的线程来创建对应的ActionContext,即一个线程有一个唯一的ActionContext。因此,使用者可以使用静态方法ActionContext.getContext()来获取当前线程的ActionContext,也正是由于这个原因,使用者不用去操心让Action是线程安全的。

无论如何,ActionContext都是用来存放数据的。Struts2本身会在其中放入不少数据,而使用者也可以放入自己想要的数据。ActionContext本身的数据结构是映射结构,即一个Map,用key来映射value。所以使用者完全可以像使用Map一样来使用它,或者直接使用Action.getContextMap()方法来对Map进行操作。

Struts2本身在其中放入的数据有ActionInvocation、application(即ServletContext)、conversionErrors、Locale、action的name、request的参数、HTTP的Session以及值栈等。完整的列表请参考它的Javadoc(本文附录有对它包含内容的讨论)。

由于ActionContext的线程唯一和静态方法就能获得的特性,使得在非Action类中可以直接获得它,而不需要等待Action传入或注入。需要注意的是,它仅在由于request而创建的线程中有效(因为request时才创建对应的ActionContext),而在服务器启动的线程中(比如fliter的init方法)无效。由于在非Action类中访问其的方便性,ActionContext也可以用来在非Action类中向JSP传递数据(因为JSP也能很方便的访问它)。

ValueStack与ActionContext的联系和区别:

相同点:它们都是在一次HTTP请求的范围内使用的,即它们的生命周期都是一次请求。

不同点:值栈是栈的结构,ActionContext是映射(Map)的结构。

联系:ValueStack.getContext()方法得到的Map其实就是ActionContext的Map。查看Struts2的源代码可知(Struts2.3.1.2的org.apache.struts2.dispatcher.ng.PrepareOperations的第79行,createActionContext方法),在创建ActionContext时,就是把ValueStack.getContext()作为ActionContext的构造函数的参数。所以,ValueStack和ActionContext本质上可以互相获得。

注意:在一些文档中,会出现把对象存入“stack's context”的字样,其实就是把值存入了ActionContext。所以在阅读这些文档时,要看清楚,到底是放入了栈结构(即值栈),还是映射结构(值栈的context,即ActionContext)。

如何获得ActionContext:

在自定义的拦截器中:使用ActionInvocation.getInvocationContext()或者使用ActionContext.getContext()。

在Action类中:让拦截器注入或者使用ActionContext.getContext()。

在非Action类中:让Action类传递参数、使用注入机制注入或者使用ActionContext.getContext()。注意:只有运行在request线程中的代码才能调用ActionContext.getContext(),否则返回的是null。

在JSP中:一般不需要获得ActionContext本身。

如何向ActionContext中存入值:

在拦截器、Action类、非Action类等Java类中:使用ActionContext.put(Object key, Object value)方法。

在JSP中:标签默认将值存入ActionContext中(当然,标签还可以把值存到其他地方)。另外,许多标签都有var属性(以前用的是id属性,现在id属性已被弃用),这个属性能向ActionContext存入值,key为var属性的值,value为标签的value属性的值。(有些文档写的是向ValueStack的context存入值,其实是一样的)

如何从ActionContext中读取值:

在拦截器、Action类、非Action类等Java类中:使用ActionContext.get(Object key)方法。

在JSP中:使用#开头的Ognl表达式,比如会调用ActionContext.get("name")方法。注意:如果某标签的属性默认不作为Ognl表达式解析,则需要使用%{}把表达式括起来,于是就会出现类似“%{#name}的表达式”。(“#”的更多用途参见这里)

总之,在JSP中使用ActionContext一方面是由于它是映射结构,另一方面是能读取Action的一些配置。当你需要为许多Action提供通用的值的话,可以让每个Action都提供getXXX()方法,但更好的方法是在拦截器或JSP模板中把这些通用的值存放到ActionContext中(因为拦截器或JSP模板往往通用于多个Action)。

一些例子:

Java代码

// 本类将演示拦截器中对ActionContext的操作

publicclass MyInterceptor extends AbstractInterceptor {

public String intercept(ActionInvocation invocation) throws Exception {

// 获得ActionContext

ActionContext actionContext = invocation.getInvocationContext();

// 存入值

Person person = new Person();

actionContext.put("person", person);

// 获取值

Object value = actionContext.get("person");

// 获取HttpServletRequest

HttpServletRequest request = (HttpServletRequest) actionContext.get(StrutsStatics.HTTP_REQUEST);

// 获取request的Map,即HttpServletRequest.getAttribute(...)和HttpServletRequest.setAttribute(...)所操作的值

Map requestMap = (Map) actionContext.get("request");

// 其他代码

// ......

return invocation.invoke();

}

}

Java代码

// 本类将演示在Action中对ActionContext进行操作

publicclass MyAction extends ActionSupport {

@Override

public String execute() throws Exception {

// 获得值栈

ActionContext actionContext = ActionContext.getContext();

// 存入值

Person person = new Person();// 这是之前例子中定义的类

actionContext.put("person", person);

// 获取值

Object object = actionContext.get("person");

// 其他代码

// ......

return SUCCESS;

}

}

Html代码

JSP Page

3. HttpServletRequest类或request的Map

Struts2中提供了两种对request的操作:一种是Web服务器提供的HttpServletRequest类,这和传统Java Web项目中的操作request的方式相同;另一种是一个“request的Map”,即封装了HttpServletRequest的attributes的映射类,操作该Map相当于操作HttpServletRequest的attributes。之所以提供了Map的操作方式,一是方便操作,二是能方便使用Ognl在JSP标签中读取request。无论如何,这两个request是互通的。至于request的生命周期等概念,与其他的Java Web项目没有区别,本文不再详述。

使用HttpServletRequest类还是request的Map

虽然两者是互通的,但就读取request的attributes而言,使用request的Map要方便许多,并且不会暴露不必要的接口。当然,HttpServletRequest有一些request的Map没有的方法,使用这些方法时当然还是要用前者。

使用request的Map还是ActionContext:

两者都是Map,两者的生命周期都是一个请求。

传统的Java Web项目中,往往是通过request的attributes来向JSP传递值的:先在Servlet里setAttribute(),然后在JSP里getAttribute()。当然在Struts2的项目中,你仍然可以使用这个方法,然而抛弃了Struts2提供的传递功能是得不偿失的。虽然笔者没有找到官方文档说一定要用ActionContext替换request的Map,也没有发现程序中有能获得ActionContext却获得不了request的Map的地方,但在Struts2框架下,操作ActionContext要比操作request的Map更加方便。因此,笔者建议:尽量使用ActionContext而不是request的Map来传递值。

request的Map有时候会包含其他框架设置的值,比如Spring框架。获取这些值的时候就需要用request的Map了,因为ActionContext里没有。

通过ActionContext可以获得HttpServletRequest类:“HttpServletRequest request = (HttpServletRequest) actionContext.get(StrutsStatics.HTTP_REQUEST);”。

通过ActionContext也可以获得request的Map:“Map requestMap = (Map) actionContext.get("request");”。因此,在JSP标签中,使用表达式“#request”就可以获得request的Map的数据。

如何获得HttpServletRequest:

如果已经有ActionContext,则使用“actionContext.get(StrutsStatics.HTTP_REQUEST)”来获得HttpServletRequest。

在自定义的拦截器中,先获得ActionContext,再通过ActionContext来获得。

在Action中,先获得ActionContext,再通过ActionContext来获得。或者让Action实现ServletRequestAware接口,并使用ServletConfigInterceptor拦截器,这样这个拦截器就会注入HttpServletRequest。

在JSP中,一般不需要获得HttpServletRequest。

如何获得request的Map:

如果已经有ActionContext,则使用“actionContext.get("request")”来获得。

在自定义的拦截器中,先获得 ActionContext,再通过ActionContext来获得。

在Action中,先获得ActionContext,再通过ActionContext来获得。或者让Action实现RequestAware接口,并使用ServletConfigInterceptor拦截器,这样这个拦截器就会注入Map request。

在JSP中,用“#request”来获得request的Map,用“#request.key”或者“#request['key']”来读取Map中的值。

总之,request仍然符合Java Web网站的一般规律。不过笔者建议使用者应尽量避免用request传值。

一些例子:

Java代码

// 本类将演示拦截器中对HttpServletRequest和request的Map的操作

publicclass MyInterceptor extends AbstractInterceptor {

public String intercept(ActionInvocation invocation) throws Exception {

// 获得ActionContext

ActionContext actionContext = invocation.getInvocationContext();

// 获得HttpServletRequest

HttpServletRequest httpServletRequest=(HttpServletRequest)actionContext.get(StrutsStatics.HTTP_REQUEST);

// 获得request的Map

Map requestMap = (Map) actionContext.get("request");

// 创建一个类作为实例

Person person = new Person();

// 以下两行的语句作用相同

httpServletRequest.setAttribute("person", person);

requestMap.put("person", person);

// 其他代码

// ......

return invocation.invoke();

}

}

Java代码

// 本类将演示在Action中对HttpServletRequest和request的Map进行操作(静态方法获得ActionContext)

publicclass MyAction extends ActionSupport {

@Override

public String execute() throws Exception {

// 获得ActionContext

ActionContext actionContext = ActionContext.getContext();

// 获得HttpServletRequest

HttpServletRequest httpServletRequest=(HttpServletRequest)actionContext.get(StrutsStatics.HTTP_REQUEST);

// 获得request的Map

Map requestMap = (Map) actionContext.get("request");

// 创建一个类作为实例

Person person = new Person();

// 以下两行的语句作用相同

httpServletRequest.setAttribute("person", person);

requestMap.put("person", person);

// 其他代码

// ......

return SUCCESS;

}

}

Java代码

// 本类将演示在Action中使用ServletRequestAware获得HttpServletRequest(注意:要使用ServletConfigInterceptor拦截器)

publicclass MyAction extends ActionSupport implements ServletRequestAware {

private HttpServletRequest request;

//此方法是接口ServletRequestAware的方法

publicvoid setServletRequest(HttpServletRequest request) {

this.request = request;

}

@Override

public String execute() throws Exception {

// HttpServletRequest已在该类的字段中准备好,可直接使用

// ......

return SUCCESS;

}

}

Java代码

// 本类将演示在Action中使用ServletRequestAware获得request的Map(注意:要使用ServletConfigInterceptor拦截器)

publicclass MyAction extends ActionSupport implements RequestAware {

Map request;

// 该方法是接口RequestAware的方法

publicvoid setRequest(Map request) {

this.request = request;

}

@Override

public String execute() throws Exception {

// request的Map已在该类的字段中准备好,可直接使用

// ......

return SUCCESS;

}

}

Java代码

JSP Page

3. Parameters,即GET请求或POST请求的参数

Parameters为GET或POST等请求时浏览器向服务器传递而来的参数。在传统的Java Web项目中,使用HttpServletRequest.getParameter()等方法来获取参数,并且可以直接使用HttpServletRequest.getParameterMap()来获得一个封装了参数的Map。而在Struts2中,Struts2直接把上述Map存放到了ActionContext中,key为“parameters”。另外,ActionContext还直接提供了ActionContext.getParameters()方法来获得这个Map。因此,在Struts2的各个部件中操作parameters的方法和操作request的Map的方法十分相似,本段不再详述。

4. HttpServletSession类和session的Map

传统Java Web项目中的session是我们都熟悉的,我们用它来记录一个用户的会话状态。Struts2把HttpServletSession封装到了一个Map中,即“session的Map”,这类似对request的处理。然而为了节省系统资源,我们在不需要session的时候不会创建session。可能正是因为这个缘故,Struts2中没有把HttpServletSession放入ActionContext中,如果你的程序需要使用HttpServletSession,应该先获得HttpServletRequest,然后使用getSession()或getSession(boolean b)来获得它,同时决定是否需要创建session。对于session的Map,Struts2仍然把它放入了ActionContext中(key为"session"),但是不要担心,这个Map的机制使得只有put新值时才会创建session。总之,Struts2中对HttpServletSession的操作要先通过HttpServletRequest来获得它,而对session的Map的操作与对request的Map的操作如出一辙,本段不再详述。

5. ServletContext和application的Map

传统的Java Web项目中,ServletContext用来存放全局变量,每个Java虚拟机每个Web项目只有一个ServletContext。这个ServletContext是由Web服务器创建的,来保证它的唯一性。ServletContext有一些方法能操作它的attributes,这些操作方法和操作一个Map类似。于是,Struts2又来封装了:它把ServletContext的attributes封装到了一个Map中,即“application的Map”,并且也放入的ActionContext中(key为application),因此,对application的Map的操作就如果对request的Map操作,本段不再详述。

至于对ServletContext的操作,与HttpServletRequest的操作类似:Struts2将ServletContext放到了 ActionContext中,并且ServletConfigInterceptor提供了对ServletContext的注入接口ServletContextAware。因此,本段不再详述。

注意:在Ognl表达式中使用“#application”可以得到application的Map,而不是ServletContext。然而在JSP嵌入的Java代码中(比如“”),application为ServletContext,而不是Map。

java actioncontext_ActionContext详解相关推荐

  1. Apache Thrift - java开发详解

    2019独角兽企业重金招聘Python工程师标准>>> Apache Thrift - java开发详解 博客分类: java 架构 中间件 1.添加依赖 jar <depen ...

  2. Java泛型详解-史上讲解最详细的,没有之一

    目录 1. 概述 2. 一个栗子 3. 特性 4. 泛型的使用 4.1 泛型类 4.2 泛型接口 4.3 泛型通配符 4.4 泛型方法 4.4.1 泛型方法的基本用法 4.4.2 类中的泛型方法 4. ...

  3. Java虚拟机详解----JVM常见问题总结

    [正文] 声明:本文只是做一个总结,有关jvm的详细知识可以参考本人之前的系列文章,尤其是那篇:Java虚拟机详解04----GC算法和种类.那篇文章和本文是面试时的重点. 面试必问关键词:JVM垃圾 ...

  4. java 泛型详解、Java中的泛型方法、 java泛型详解

    本文参考java 泛型详解.Java中的泛型方法. java泛型详解 概述 泛型在java中有很重要的地位,在面向对象编程及各种设计模式中有非常广泛的应用. 什么是泛型?为什么要使用泛型? 泛型,即& ...

  5. 最详细的java泛型详解

    来源:最详细的java泛型详解 对java的泛型特性的了解仅限于表面的浅浅一层,直到在学习设计模式时发现有不了解的用法,才想起详细的记录一下. 本文参考java 泛型详解.Java中的泛型方法. ja ...

  6. Java异常详解及如何处理

    来源:Java异常详解及如何处理 简介 程序运行时,发生的不被期望的事件,它阻止了程序按照程序员的预期正常执行,这就是异常.异常发生时,是任程序自生自灭,立刻退出终止,还是输出错误给用户?或者用C语言 ...

  7. Java基础——Java NIO详解(一)

    一.基本概念 1.I/0简介 I/O即输入输出,是计算机与外界世界的一个借口.IO操作的实际主题是操作系统.在java编程中,一般使用流的方式来处理IO,所有的IO都被视作是单个字节的移动,通过str ...

  8. Java基础——Java NIO详解(二)

    一.简介 在我的上一篇文章Java NIO详解(一)中介绍了关于标准输入输出NIO相关知识, 本篇将重点介绍基于网络编程NIO(异步IO). 二.异步IO 异步 I/O 是一种没有阻塞地读写数据的方法 ...

  9. Java基础——Java IO详解

    一.概述 1.Java IO Java IO即Java 输入输出系统.不管我们编写何种应用,都难免和各种输入输出相关的媒介打交道,其实和媒介进行IO的过程是十分复杂的,这要考虑的因素特别多,比如我们要 ...

最新文章

  1. delphi self 的使用
  2. 【深度学习】Transformer长大了,它的兄弟姐妹们呢?(含Transformers超细节知识点)...
  3. OpenGL之利用矩阵的“平移”“旋转”“综合变换”等实现矩形的移动
  4. 利用Nmap对MS-SQLSERVER进行渗透
  5. UVa140 Bandwidth 【最优性剪枝】
  6. 资源向导之 quot;APUEquot;
  7. java后台与ISO端app对接
  8. yourphp添加KindEditor编辑器
  9. mac设置共享屏幕 苹果mac屏幕共享设置详细教程
  10. 第十四章 齐桓公广开门路招贤才 卫宁戚饭牛而歌得重用
  11. android老人字体变大,适合老年人用的安卓手机软件 一键让Android字体变大
  12. 算法面试必备-----数据分析常见面试题
  13. 洛谷P2738 [USACO4.1]篱笆回路Fence Loops(Floyed求最小环)
  14. Jsbeautifier JS代码美化库
  15. 软RAID 0的技术概要及实现 v0.1b
  16. 平衡二叉查找树的构建
  17. 计算机网络 -- RS232接口 ----OSI物理层协议----RS232接口
  18. 电脑屏幕显示字体边缘颗粒感严重
  19. 在对象内部尽量直接訪问实例变量 --Effictive Objective-C 抄书
  20. linux API大全

热门文章

  1. 汇编语言与接口技术(速通版)
  2. poll机制读取按键值
  3. Shell脚本之if语句
  4. C6000系列DSP优化总结
  5. scrapy mysql 多线程,爬虫进阶之Scrapy(三) 使用scrapy某新闻网并存到数据库
  6. Python例题(一) 输入一个正整数判断是不是素数
  7. 第三方分享工具bShare的技巧
  8. 简单易懂的单纯形法理解
  9. Android根文件系统认识
  10. 摩客怎么设置安卓的dp_Android屏幕适配——使用 dp 实现完美适配