ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

ActionContext和ServletActionContext解析

2021-06-09 13:02:25  阅读:169  来源: 互联网

标签:Map ServletActionContext request session Action ActionContext 解析


1.ActionContext
xwork框架的ActionContext是Action执行时的上下文,存放Action执行时需要用到的对象。在使用webwork时,其中放有Parameter、Session、ServletContext、Locale等信息。这样,webwork负责将Servlet相关数据转换为与ServletAPI无关的Map对象(即ActionContext),使得xwork的Action实现与web层、逻辑层与表现层的解耦。

2.ServletActionContext
提供直接与Servlet容器交互的途径。通过它,可以取得HttpServletRequest、HttpServletResponse 、ServletConfig、ServletContext、PageContext 对象。但是,使用ServletActionContext意味着Action与ServletAPI的紧密耦合。

3.由于WebWork对request,parameter,Session和Application都进行了封装,将这些隐含的对象封装成了相应的Map,如RequestMap,ParameterMap,SessionMap和ApplicationMap,而这些Map就组成

了ActionContext,因此我们通常都不再需要与request,session这些底层的对象打交道了,这也是我一开始觉得迷惑的地方,因为我找不到Session了。事实上,对于SessionMap的处理即是对Session的

处理了。我们可以通过ActionContext的静态方法getContext返回一个ActionContext的实例,然后再调用其getSession方法获得SessionMap,接着就可以利用put和get方法对session进行读写的操作了。

Map params = new HashMap();;   
params.put(String, String);;   
......   
Map extraContext = new HashMap();;   
extraContext.put(ActionContext.PARAMETERS,params); 

Map session = new HashMap();;   
session.put("foo", "bar");;   
extraContext.put(ActionContext.SESSION, session); 

ActionContext ctx = ActionContext.getContext(); 
Map session = ctx.getSession(); 
session.put("username",loginInfo.getUsername()); 

ActionContext ctx = ActionContext.getContext(); 
Map params = ctx.getParameters(); 
String username = ctx.getParameters("username"); 

OgnlValueStack stack = new OgnlValueStack(); 
stack.push(new User());//首先将欲赋值对象压入栈中 
stack.setValue("name","erica");//为栈顶对象的指定属性名赋值 

再探ActionContext
前面已经了解到ActionContext是Action执行时的上下文,里面存放着Action在执行时需要用到的对象,我们也称之为广义值栈。

Struts2在每次执行Action之前都会创建新的ActionContext,在同一个线程里ActionContext里面的属性是唯一的,这样Action就可以在多线程中使用。

1:ActionContext的线程安全性

那么Struts2是如何保证ActionContext的线程安全性呢?

看看ActionContext对象的代码,示例如下:

java代码:

public class ActionContext implements Serializable {
static ThreadLocal actionContext = new ThreadLocal();
……
}

public class ActionContext implements Serializable {static ThreadLocal actionContext = new ThreadLocal();……}
ThreadLocal又称为“线程局部变量”,它为每一个使用该变量的线程都提供一个变量值的副本,使每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。

存放在ActionContext里的数据都存放在这个ThreadLocal的属性中,而这个属性只会在对应的当前请求线程中可见,从而保证数据是线程安全的。

2:访问的是Map

回顾前面在使用ActionContext来访问Session中数据的程序,你会发现,其实在程序里面访问的是一个Map,而非HttpSession对象,这是为什么呢?

原来,Struts2框架将与Web相关的很多对象重新进行了包装,比如将HttpSession对象重新包装成了一个Map对象,里面存放着Session中的数据,提供这个Map给Action使用,而不用Action直接和底层的HttpSession打交道。也正是因为框架的包装,让Action可以完全的和Web层解耦。

但是要注意一点,ActionContext不能在普通的Java应用程序中使用。

在以前的学习中,介绍了Action和Servlet API是解耦的,因此可以在Java应用程序中调用Action的execute方法来进行测试。但是如果使用了ActionContext来获取session数据,那么就不能这样运行了。因为ActionContext包装的都是Web的数据,在Java应用程序中运行的时候,没有Web的环境和响应的数据,因而会抛出空指针的异常。

访问其它的Web对象的值也是与此类似的,你通过ActionContext去访问的都是包装后的Map。

3:使用SessionAware接口

Struts2还提供另外一种简单的方式,使用SessionAware接口来访问存储于ActionContext中的数据,该接口通过使用IoC/DI来为Action注入Session Map,就可以在程序里面直接使用这个Map来操作数据了。

(1)在Action中不再需要访问ActionContext了,取而代之,Action实现SessionAware接口,该接口告知Struts2在Action执行之前要设置Session Map,是通过servletConfig 拦截器来实现的,这个拦截器在defaultStack里面就有。示例代码如下:

java代码:

public class OgnlAction extends ActionSupportimplements SessionAware{
private Map<String, Object> session;
public void setSession(Map<String, Object> session) 
	{
		this.session = session;
	}
	public String execute(){
	session.put("sessionTestKey", "测试SessionAware");
	return this.SUCCESS;
	}
}
public class OgnlAction extends ActionSupport implements SessionAware{ private Map<String, Object> session; public void setSession(Map<String, Object> session) { this.session = session; } public String execute(){ session.put("sessionTestKey", "测试SessionAware"); return this.SUCCESS; }}

在上面的代码中:

Action类实现SessionAware接口
这个接口要求Action类实现一个方法setSession(Map<String, Object> session),通过这个方法注入Session的数据
在execute方法中,通过这个私有属性就可以操作会话中的数据,注意一点,这个Map中的值也是与HttpSession联动的。
(2)结果界面也稍作修改,好来看出Action操作session后的效果,示例如下:

java代码:

<%@ taglib prefix="s" uri="/struts-tags"%>
会话中的值:<s:property value="#session['sessionTestKey']"/>
<br>
通过Servlet的Api获取会话中的值:<%=session.getAttribute("sessionTestKey") %>
<%@ taglib prefix="s" uri="/struts-tags"%>会话中的值:<s:property value="#session['sessionTestKey']"/><br>通过Servlet的Api获取会话中的值:<%=session.getAttribute("sessionTestKey") %>

通过两种方式来查看会话中的值。

去运行测试一下,结果页面示例如下:
在这里插入图片描述

为了能够在普通的Java应用中运行并测试Action,推荐大家使用SessionAware的方式来访问HttpSession。因为这样一来,在通过main方法运行或测试的时候,可以直接调用setSession方法,传入模拟的会话数据,就不会出现execute方法中抛出空指针的异常了。

因此,推荐大家使用SessionAware的方式来访问HttpSession。

4:使用其它包装接口

跟SessionAware类似,你可以使用RequestAware来获取包装请求对象的attribute中的值的Map;使用ApplicationAware来获取包装ServletContext对象的attribute中的值的Map;使用ParameterAware来获取包装请求对象的参数中的值的Map,等等,这里只罗列这几个常见和常用的,还有更多的请参见Struts2的API文档。

7.4.2 ServletActionContext
在实际应用开发中,光是获取数据就够了吗?答案显然是否定的,有些时候,根据功能需要,在Action中必须要能获取到Servlet相关的API,比如要操作Cookie。这个时候,就需要用ServletActionContext了。

1:ServletActionContext概述

这个类直接继承了ActionContext,当然也继承了它父类的很多功能,比如:对OgnlValueStack、Action名字等的访问。更重要的是,它还提供了直接访问Servlet的相关对象的功能,它可以取得的对象有:

HttpServletRequest:请求对象
HttpServletResponse:响应对象
ServletContext:Servlet上下文信息
PageContext:Http页面上下文

2:基本使用

直接使用ServletActionContext的静态方法就可以获取到相应的对象。示例如下:

java代码:

HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
ServletContext servletContext = ServletActionContext.getServletContext();
PageContext pageContext = ServletActionContext.getPageContext();
HttpSession session = ServletActionContext.getRequest().getSession();
HttpServletRequest request = ServletActionContext.getRequest();HttpServletResponse response = ServletActionContext.getResponse();ServletContext servletContext = ServletActionContext.getServletContext();PageContext pageContext = ServletActionContext.getPageContext();HttpSession session = ServletActionContext.getRequest().getSession();

这里要注意的是HttpSession对象的获取,是在取得HttpRequest对象过后,通过HttpRequest对象来获取会话对象。当然,取得相应的对象后,就直接使用这些对象的方法来进行开发,这里就不去赘述了。

3:通过IoC/DI的方式来获取相应的Servlet对象

还可以通过IoC/DI的方式来获取相应的Servlet对象,对应关系是:

ServletRequestAware:通过这个接口来获取HttpServletRequest对象
ServletResponseAware:通过这个接口来获取HttpServletResponse对象
用ServletRequestAware来示例一下。

(1)修改Action,让其实现ServletRequestAware接口,示例代码如下:

java代码:

public class OgnlAction extends ActionSupportimplements ServletRequestAware{
	private HttpServletRequest request = null;
	public void setServletRequest(HttpServletRequest request) {
	this.request = request;
}
public String execute()
{
	request.setAttribute("request", "Request的属性值");
	request.getSession().setAttribute("sessionTestKey", "测试SessionAware");
	return this.SUCCESS;
}
	


public class OgnlAction extends ActionSupport implements ServletRequestAware{ private HttpServletRequest request = null; public void setServletRequest(HttpServletRequest request) { this.request = request; } public String execute(){ request.setAttribute("request", "Request的属性值"); request.getSession().setAttribute("sessionTestKey", "测试SessionAware"); return this.SUCCESS; } }

(2)对应的结果页面也需要稍作修改,要把Action中设置的值显示出来,示例如下:

java代码:

<%@ taglib prefix="s" uri="/struts-tags"%>
Request的属性值:<s:property value="#request['request']"/>
<br>
会话的属性值:<s:property value="#session['sessionTestKey']"/>
<%@ taglib prefix="s" uri="/struts-tags"%>Request的属性值:<s:property value="#request['request']"/><br>会话的属性值:<s:property value="#session['sessionTestKey']"/>

(3)运行测试一下,结果页面应该如下:
在这里插入图片描述

图7.7 使用ServletRequestAware的结果页面

当然,你也可以以同样的方式去使用ServletResponseAware,这里就不去赘述了。

7.4.3 ActionContext和ServletActionContext
根据前面的讲述,你会发现,ActionContext和ServletActionContext有着一些重复的功能,都能够获取到Web对象的数据,但是又有些不同。

通常情况下,可以这么认为:ActionContext主要负责值的操作;ServletActionContext主要负责获取Servlet对象。

那么在Action中,该如何去抉择呢?建议的原则是:

优先使用ActionContext
只有ActionContext不能满足功能要求的时候,才使用ServletActionContext
总之,要尽量让Action与Web无关,这对于Action的测试和复用都是极其有好处的。

另外还有一点需要注意:在使用ActionContext时,不要在Action的构造函数里使用ActionContext.getContext(),因为这个时候ActionContext里的一些值也许还没有设置,这时通过ActionContext取得的值也许是null。

标签:Map,ServletActionContext,request,session,Action,ActionContext,解析
来源: https://blog.csdn.net/Captain_Aaron/article/details/117738379

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有