自己实现Struts2(三)实现ActionContext

上一章自己实现Struts2(二)加载配置文件我把加载配置文件的功能实现好了,现在要实现的是ActionContext类。先来简单介绍一下ActionContext类。

这是其他地方copy下来的,感觉介绍的很到位

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

说白了ActionContext就是一个数据中心,action想要的东西基本上都可以通过它拿到,像什么request、session还有ValueStack等等重要的东西。

#要做怎么样的ActionContext
我自己做的这个ActionContext可以获取下面这些对象

  • request
  • response
  • session
  • application
  • parameters : 存储请求参数
  • ValueStack : 值栈咯

当然了,像实现国际化的locale对象就没有了,没打算做那个功能,还有其它杂七杂八的也没有,就是用来获取上面6个对象,不过也够用了。

#实现ValueStack
要做ActionContext类,先把ValueStack类准备好,在Struts2中,ValueStack是一个接口,真正的实现是OgnlValueStack,不过我自己实现的话就直接把它作为类,而且用jdk提供的java.util.Stack实现,就不去弄什么root对象啦,我也做不出OGNL来。

ValueStack类,简单的很

package edu.jyu.stack;

import java.util.Stack;
/**
 * 值栈对象,将action压入栈
* @author Jason
 */
public class ValueStack {
	private Stack<Object> stack = new Stack<Object>();
	
	public void push(Object o){
		stack.push(o);
	}
	
	public Object pop(){
		return stack.pop();
	}
	
	public Object peek(){
		return stack.peek();
	}
	
}

#实现ActionContext

先把实现好的代码贴上来,然后再讲解

package edu.jyu.context;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import edu.jyu.stack.ValueStack;

/**
 * 数据中心
 * 
 * @author Jason
 */
public class ActionContext {

	public static final String REQUEST = "edu.jyu.request";
	public static final String RESPONSE = "edu.jyu.response";
	public static final String SESSION = "edu.jyu.session";
	public static final String APPLICATION = "edu.jyu.application";
	public static final String PARAMETERS = "edu.jyu.parameters";
	public static final String VALUESTACK = "edu.jyu.valuestack";

	private Map<String, Object> context;
	public static ThreadLocal<ActionContext> actionContext = new ThreadLocal<ActionContext>();

	public ActionContext(HttpServletRequest request, HttpServletResponse response, Object action) {
		context = new HashMap<String, Object>();
		// 准备域
		// request
		context.put(REQUEST, request);
		// response
		context.put(RESPONSE, response);
		// session
		context.put(SESSION, request.getSession());
		// application
		context.put(APPLICATION, request.getSession().getServletContext());
		// parameters
		context.put(PARAMETERS, request.getParameterMap());
		// valuestack
		ValueStack vs = new ValueStack();
		// 将action压入栈顶
		vs.push(action);
		// 将ValueStack放入request域中
		request.setAttribute(VALUESTACK, vs);
		// 将ValueStack放入context域中
		context.put(VALUESTACK, vs);
		// 为当前请求线程设置好ActionContext
		actionContext.set(this);
	}

	/**
	 * @return 当前线程对应的ActionContext对象
	 */
	public static ActionContext getContext() {
		return actionContext.get();
	}

	public HttpServletRequest getRequest() {
		return (HttpServletRequest) context.get(REQUEST);
	}

	public HttpServletResponse getResponse() {
		return (HttpServletResponse) context.get(RESPONSE);
	}

	public HttpSession getSession() {
		return (HttpSession) context.get(SESSION);
	}

	public ServletContext getApplication() {
		return (ServletContext) context.get(APPLICATION);
	}

	public Map<String, String[]> getParams() {
		return (Map<String, String[]>) context.get(PARAMETERS);
	}

	public ValueStack getValueStack() {
		return (ValueStack) context.get(VALUESTACK);
	}

}

一、常量值

大家应该注意到一开始我定义了很多常量值,像public static final String REQUEST = "edu.jyu.request";,这当然也是仿造Struts2中的ActionContext里面的,是为了在后面的Map中获取指定的对象。这也是一个良好的习惯,用常量值去代替字面量或者变量值作为key,不容易错而且方便。

二、核心——context

private Map<String, Object> context;:这个对象无疑就是ActionContext的核心成员了,我们要的对象存放在它里面,然后通过上面的常量值获取对应的对象。

三、保证线程安全——actionContext

public static ThreadLocal<ActionContext> actionContext = new ThreadLocal<ActionContext>();:这个actionContext是一个ThreadLocal对象,而且里面存放的值是ActionContext类型的,将每个请求的线程的ActionContext对象存放到这个actionContext的属性中,这样每个线程通过getContext()方法访问到的ActionContext对象都是自己的那份,从而保证了数据安全。

四、添加数据——构造方法

大家可以注意到除去getter方法,整个ActionContext类最多处理的是在构造方法中。我写的这个ActionContext类的构造方法跟Struts2里面的ActionContext类不同,Struts2里面的是这样的

public ActionContext(Map<String, Object> context) {
     this.context = context;
}

它里面的核心context是直接传进来的,而我是自己在构造方法中new出来的,只需要传进三个对象

  1. request
  2. response
  3. action

三个足以,session和parameters可以通过request获得,application可以通过session获得,ValueStack自己创建,全部数据都可以搞定了。

需要注意的几点:

  1. action要压入ValueStack中。
  2. ValueStack要放入request域中,在Struts2中是可以通过request域获取到ValueStack对象的。
  3. actionContext.set(this);即为当前请求线程设置好它的ActionContext对象,也可以说是将ActionContext对象绑定到当前线程上。

好了,ActionContext大功告成,项目已经上传到Github上
https://github.com/HuangFromJYU/JStruts2

如果大家有什么问题或者发现什么错误可以发邮件到jasonwong_hjj@qq.com,共同学习共同进步

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值