简单地说,struts2对默认的request进行了包装,默认会先从原request里面找,如果找不到,会从值栈里面找;
实现细节如下:
StrutsPrepareAndExecuteFilter在doFilter()时候,调用PrepareOperations的wrapRequest()方法;最终调用了Dispatcher的wrapRequest()方法;
// Dispatcher的wrapRequest()方法
public HttpServletRequest———— wrapRequest(HttpServletRequestrequest, ServletContext servletContext) throws IOException {
// don't wrap more than once
if (request instanceof StrutsRequestWrapper) {
return request;
}
String content_type = request.getContentType();
if (content_type != null &&content_type.indexOf("multipart/form-data") != -1) {
MultiPartRequest mpr = null;
//check for alternate implementations of MultiPartRequest
Set<String> multiNames =getContainer().getInstanceNames(MultiPartRequest.class);
if (multiNames != null) {
for (String multiName : multiNames) {
if (multiName.equals(multipartHandlerName)) {
mpr = getContainer().getInstance(MultiPartRequest.class,multiName);
}
}
}
if (mpr == null ) {
mpr = getContainer().getInstance(MultiPartRequest.class);
}
request = new MultiPartRequestWrapper(mpr, request,getSaveDir(servletContext));
} else {
request = new StrutsRequestWrapper(request);
}
return request;
}
StrutsRequestWrapper构造器会修改父类HttpServletRequestWrapper的父类ServletRequestWrapper的指针,视其指向StrutsRequestWrapper这个实例;
// 源码如下:
public class StrutsRequestWrapper extendsHttpServletRequestWrapper {
publicStrutsRequestWrapper(HttpServletRequest req) {
super(req);
}
publicObject getAttribute(String s) {
if (s != null &&s.startsWith("javax.servlet")) {
// don't bother with the standard javax.servlet attributes, we canshort-circuit this
// see WW-953 and the forums post linked in that issue for moreinfo
return super.getAttribute(s);
}
ActionContext ctx = ActionContext.getContext();
Object attribute = super.getAttribute(s); // 先从原request中取
if (ctx != null) { // 上下文不为空
if (attribute == null) { // 没取到值
boolean alreadyIn = false;
Boolean b = (Boolean)ctx.get("__requestWrapper.getAttribute");
if (b != null) {
alreadyIn = b.booleanValue();
}
// note: we don't let # come through or else a request for
// #attr.foo or #request.foo could cause an endless loop
if (!alreadyIn && s.indexOf("#") ==-1) {
try {
// If not found, then try the ValueStack
ctx.put("__requestWrapper.getAttribute", Boolean.TRUE);
ValueStack stack = ctx.getValueStack();
if (stack != null) {
attribute = stack.findValue(s); // 从值栈取
}
} finally {
ctx.put("__requestWrapper.getAttribute", Boolean.FALSE);
}
}
}
}
return attribute;
}
}
这样在页面上使用<%=request.getAttribute("xxx")%>可以访问到值栈的数据,el表达式可以访问到page、request、session、application范围的数据,所以可以访问到struts2的值栈;