上一章自己实现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出来的,只需要传进三个对象
- request
- response
- action
三个足以,session和parameters可以通过request获得,application可以通过session获得,ValueStack自己创建,全部数据都可以搞定了。
需要注意的几点:
- action要压入ValueStack中。
- ValueStack要放入request域中,在Struts2中是可以通过request域获取到ValueStack对象的。
actionContext.set(this);
即为当前请求线程设置好它的ActionContext对象,也可以说是将ActionContext对象绑定到当前线程上。
好了,ActionContext大功告成,项目已经上传到Github上
https://github.com/HuangFromJYU/JStruts2
如果大家有什么问题或者发现什么错误可以发邮件到jasonwong_hjj@qq.com,共同学习共同进步