在编写SSH的项目中通常会获取request,response,sessinon对象或者需要需要从表单中获取参数值,如果项目中
包含上百个Action或者更多,那么我们就会编写许多类似的代码,可以通过编写一个通用的基类从而减少了重复的代码,提
高了编码的效率。
package com.wuhen.struts2.hello;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.interceptor.ServletResponseAware;
import org.apache.struts2.interceptor.SessionAware;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.Preparable;
public class BaseAction extends ActionSupport implements ServletRequestAware,
ServletResponseAware, Preparable, SessionAware {
private static final long serialVersionUID = -4871815191368438694L;
protected HttpServletRequest request;
protected HttpServletResponse response;
protected PrintWriter printWriter;
protected ActionContext actionContext;
protected Map<String, Object> session;
@Override
public void prepare() throws Exception {
}
@Override
public void setServletResponse(HttpServletResponse response) {
this.response = response;
}
@Override
public void setServletRequest(HttpServletRequest request) {
this.request = request;
}
public PrintWriter getPrintWriter() throws IOException {
return response.getWriter();
}
protected void initUTF8() {
response.setContentType("text/html");
response.setCharacterEncoding("UTF-8");
}
@Override
public void setSession(Map<String, Object> session) {
this.session = session;
}
public Object getSession(String key) {
return session.get(key);
}
public void setSession(String name, Object value) {
session.put(name, value);
}
protected ActionContext getActionContext() {
return ActionContext.getContext();
}
protected Object getAttribute(String name) {
return request.getAttribute(name);
}
public void setAttribute(String name, Object value) {
request.setAttribute(name, value);
}
public String getParameter(String name) {
return request.getParameter(name);
}
public String[] getParameterValues(String name) {
return request.getParameterValues(name);
}
public String ajax(String content, String type) throws IOException {
if (StringUtils.isEmpty(type)) {
initUTF8();
} else {
response.setContentType(type + ";charset=UTF-8");
}
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
getPrintWriter().write(content);
getPrintWriter().flush();
return null;
}
}
获取request,response,session都是通过实现对应的接口,在struts2中的ServletConfigInterceptor中拦截器中
进行了相关代码的封装。其部分源码如下:
/**
* Sets action properties based on the interfaces an action implements. Things like application properties,
* parameters, session attributes, etc are set based on the implementing interface.
*
* @param invocation an encapsulation of the action execution state.
* @throws Exception if an error occurs when setting action properties.
*/
public String intercept(ActionInvocation invocation) throws Exception {
final Object action = invocation.getAction();
final ActionContext context = invocation.getInvocationContext();
if (action instanceof ServletRequestAware) {
//从contex对象中获取com.opensymphony.xwork2.dispatcher.HttpServletRequest对象
HttpServletRequest request = (HttpServletRequest) context.get(HTTP_REQUEST);
//进行对象设置
((ServletRequestAware) action).setServletRequest(request);
}
if (action instanceof ServletResponseAware) {
HttpServletResponse response = (HttpServletResponse) context.get(HTTP_RESPONSE);
((ServletResponseAware) action).setServletResponse(response);
}
if (action instanceof ParameterAware) {
((ParameterAware) action).setParameters((Map)context.getParameters());
}
if (action instanceof ApplicationAware) {
((ApplicationAware) action).setApplication(context.getApplication());
}
if (action instanceof SessionAware) {
((SessionAware) action).setSession(context.getSession());
}
if (action instanceof RequestAware) {
((RequestAware) action).setRequest((Map) context.get("request"));
}
if (action instanceof PrincipalAware) {
HttpServletRequest request = (HttpServletRequest) context.get(HTTP_REQUEST);
if(request != null) {
// We are in servtlet environment, so principal information resides in HttpServletRequest
((PrincipalAware) action).setPrincipalProxy(new ServletPrincipalProxy(request));
}
}
if (action instanceof ServletContextAware) {
ServletContext servletContext = (ServletContext) context.get(SERVLET_CONTEXT);
((ServletContextAware) action).setServletContext(servletContext);
}
return invocation.invoke();
}
对于这段代码是从context对象中获取的
(HttpServletRequest) context.get(HTTP_REQUEST);
那么struts2是从何时将这些对象设置到context对象中的呢?
我们可以从struts2中的StrutsPrepareAndExecuteFilter中的接口入口进行分析
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
try {
prepare.setEncodingAndLocale(request, response);
//设置相关的request和respon对象
prepare.createActionContext(request, response);
prepare.assignDispatcherToThread();
if ( excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {
chain.doFilter(request, response);
} else {
request = prepare.wrapRequest(request);
ActionMapping mapping = prepare.findActionMapping(request, response, true);
if (mapping == null) {
boolean handled = execute.executeStaticResourceRequest(request, response);
if (!handled) {
chain.doFilter(request, response);
}
} else {
execute.executeAction(request, response, mapping);
}
}
} finally {
prepare.cleanupRequest(request);
}
}
从上述的代码可知,在 prepare.createActionContext(request, response);对request,response对象进行了设置
该方法的源码如下:
public ActionContext createActionContext(HttpServletRequest request, HttpServletResponse response) {
ActionContext ctx;
Integer counter = 1;
Integer oldCounter = (Integer) request.getAttribute(CLEANUP_RECURSION_COUNTER);
if (oldCounter != null) {
counter = oldCounter + 1;
}
ActionContext oldContext = ActionContext.getContext();
if (oldContext != null) {
// detected existing context, so we are probably in a forward
ctx = new ActionContext(new HashMap<String, Object>(oldContext.getContextMap()));
} else {
ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();
stack.getContext().putAll(dispatcher.createContextMap(request, response, null, servletContext));
ctx = new ActionContext(stack.getContext());
}
request.setAttribute(CLEANUP_RECURSION_COUNTER, counter);
ActionContext.setContext(ctx);
return ctx;
}
//如果旧ActionContext 对象不为空,就oldContext.getContextMap()直接获取,否则获取ValueStack对象,将其
相关对象信息putAll(),该方法源码如下:
public Map<String,Object> createContextMap(HttpServletRequest request, HttpServletResponse response,
ActionMapping mapping, ServletContext context) {
// request map wrapping the http request objects
Map requestMap = new RequestMap(request);
// parameters map wrapping the http parameters. ActionMapping parameters are now handled and applied separately
Map params = new HashMap(request.getParameterMap());
// session map wrapping the http session
Map session = new SessionMap(request);
// application map wrapping the ServletContext
Map application = new ApplicationMap(context);
Map<String,Object> extraContext = createContextMap(requestMap, params, session, application, request, response, context);
if (mapping != null) {
extraContext.put(ServletActionContext.ACTION_MAPPING, mapping);
}
return extraContext;
}
其中createContextMap方法是将request和response对象放入到map中。
public HashMap<String,Object> createContextMap(Map requestMap,
Map parameterMap,
Map sessionMap,
Map applicationMap,
HttpServletRequest request,
HttpServletResponse response,
ServletContext servletContext) {
HashMap<String,Object> extraContext = new HashMap<String,Object>();
extraContext.put(ActionContext.PARAMETERS, new HashMap(parameterMap));
extraContext.put(ActionContext.SESSION, sessionMap);
extraContext.put(ActionContext.APPLICATION, applicationMap);
Locale locale;
if (defaultLocale != null) {
locale = LocalizedTextUtil.localeFromString(defaultLocale, request.getLocale());
} else {
locale = request.getLocale();
}
extraContext.put(ActionContext.LOCALE, locale);
//extraContext.put(ActionContext.DEV_MODE, Boolean.valueOf(devMode));
extraContext.put(StrutsStatics.HTTP_REQUEST, request);
extraContext.put(StrutsStatics.HTTP_RESPONSE, response);
extraContext.put(StrutsStatics.SERVLET_CONTEXT, servletContext);
// helpers to get access to request/session/application scope
extraContext.put("request", requestMap);
extraContext.put("session", sessionMap);
extraContext.put("application", applicationMap);
extraContext.put("parameters", parameterMap);
AttributeMap attrMap = new AttributeMap(extraContext);
extraContext.put("attr", attrMap);
return extraContext;
}
通过对源码简单的分析,相信大家应该有所了解,如果需要深入的了解可以查看struts2相关的文档和源码。