ActionContext对象的使用

Struts1的Action必须依赖于web容器,他的extecute方法会自动获得HttpServletRequest、HttpServletResponse对象,从而可以跟web容器进行交互。

Struts2的Action不用依赖于web容器,本身只是一个普通的java类而已。但是,在web开发中我们往往需要获得request、session、application等对象。这时候,可以通过ActionContext来处理。

ActionContext正如其名,是Action执行的上下文。他内部有个map属性,它存放了Action执行时需要用到的对象。

在每次执行Action之前都会创建新的ActionContext对象,所以Actioncontext是线程安全的。新new的ActionContext是保存在一个Threadlocal变量中,即采用Threadlocal模式。Threadlocal变量为每个线程提供独立的变量值的副本,使每个线程都可以独立的使用自己的副本,而不会和其他线程发生冲突。

通过ActionContext获取的session、request、application并不是真正的HttpServletRequest、HttpServletResponse、ServletContext对象,而是将这三个对象里面的值重新包装成了map对象。这样的封装,我们及获取了我们需要的值,同时避免了跟Web容器直接打交道,实现了完全的解耦。

测试代码:

public class TestActionContextAction extends ActionSupport{
    private String uname;
    public String execute() throws Exception {
        ActionContext ac = ActionContext.getContext();
        System.out.println(ac);    //在此处定义断点
        return this.SUCCESS;
    }
    //get和set方法省略!
}

我们定义断点,debug进去,跟踪ac对象的值。发现他有个table属性,该属性内部包含一个map属性,该map中又有多个map属性,他们分别是:
request、session、application、action、attr、parameters等。

同时,我们跟踪request进去,发现属性attribute又是一个table,再进去发现一个名字叫做”struts.valueStack”属性。内容如下:
这里写图片描述
这里写图片描述
OgnlValueStack可以简单看做List,里面还放了Action对象的引用,通过它可以得到该Action对象的引用。

下图说明了几个对象的关系:
这里写图片描述

虽然我们已经从debug中得到上图的关系。为了验证我们的想法,我们写个代码进行测试:

    private String uname;

    public String execute() throws Exception {
        ActionContext ac = ActionContext.getContext();
            ac.put("uu", "uuu");
        ac.getSession().put("s", "ss");   //直接使用:${sessionScope.s}即可获取
        ((Map)ac.get("request")).put("r", "request作用域中的r参数");
        System.out.println(ac);     
return this.SUCCESS;
    }
    request:${requestScope.s} <br/>
    session:${sessionScope.s}  <br/>
    actioncontext中的属性,会被拦截器处理成request对象的属性,便于引用:${requestScope.uu}<br/>
    action中的属性也会拦截器被处理成request对象的属性,便于引用:${requestScope.uname }<br/>

结果如下:
这里写图片描述

总结:
ActionContext、Action本身和HttpServletRequest对象没有关系。但是为了能够使用EL表达式、JSTL直接操作他们的属性。会有一个拦截器将ActionContext、Action中的属性通过类似request.setAttribute()方法置入request中(webwork2.1之前的做法)。这样,我们也可以通过:${requestScope.uname}即可访问到ActionContext和Action中的属性。
注:struts2后,使用装饰器模式来实现上述功能。
Action的实例,总是放到value stack中。因为Action放在stack中,而stack是root(根对象),所以对Action中的属性的访问就可以省略#标记。



用ActionContext获取Web容器信息
上面我们已经测试过,通过ActionContext可以获得session、request、application,但他们并不是真正的HttpServletRequest、HttpServletResponse、ServletContext对象,而是将这三个对象里面的值重新包装成了map对象。 Struts框架通过他们来和真正的web容器对象交互。

Action对象需要继承ActionSupport对象

第一种方法:

//通过ActionContext对象
ActionContext ac = ActionContext.getContext();
//获取request作用域对象
Map<String, Object> requestMap = (Map<String, Object>) ac.get("request");
//对request作用域存放信息
requestMap.put("requestval", "ActionContext.request");
//同样session和application作用域操作一样
Map<String, Object> sessionMap = (Map<String, Object>) ac.get("session");
sessionMap.put("sessionval", "ActionContext.session");
Map<String, Object> applicationMap = (Map<String, Object>) ac.get("application");
applicationMap.put("applicationval", "ActionContext.application");

对应的jsp页面获取数据:

第一种方式获取request:${requestval }<hr>
使用ognl表达式获取:<s:property value="#request['requestval']"/><hr>

第二种方法:

//通过ActionContext对象获取对象
ActionContext ac = ActionContext.getContext();
//给request作用域存放信息
ac.put("requestval", "ActionContext.request");
//通过ActionContext对象的get方法给session和application作用域存放信息
Map<String, Object> sessionMap = ac.getSession();
sessionMap.put("sessionval", "ActionContext.session");
Map<String, Object> applicationMap = ac.getApplication();
applicationMap.put("applicationval", "ActionContext.application");

第三种方法:
直接获取真正的request、session、application对象获得Servlet API(非耦合):通过ServletActionContext获得真正的Servlet API

HttpServletRequest request = ServletActionContext.getRequest();
request.setAttribute("servletrequestval", "request");
//获取到的作用域对象,用法和servlet中使用的一致
HttpSession session = request.getSession();
session.setAttribute("serveltsessionval", "session");

ServletContext application = request.getServletContext();
application.setAttribute("serveltapplicationval", "application");

第四种方法:(一般不使用)
实现RequestAware,SessionAware,ApplicationAware接口,重写接口内定义的方法

//定义一个变量来接收信息。
public class TestActionContextAction extends ActionSupport implements RequestAware,SessionAware,ApplicationAware{

Map<String, Object> map;
@Override
public void setRequest(Map<String, Object> map) {
    // TODO Auto-generated method stub
    this.map = map;
}

在jsp页面中可以通过el表达式获取数值:

request:${requestval }<br>
    session:${sessionval }<br>
    application:${applicationval }<br>

或者

request:${requestScope.requestval }<br>
session:${sessionScope.sessionval }<br>
application:${applicationScope.applicationval }

猜你喜欢

转载自blog.csdn.net/zhangfengbx/article/details/78204579