我們知道,JSTL默認是從page,request,session,application這四個Scope逐次查找相應的EL表達式所對應 的對象的值。那麼如果要使用JSTL來讀取Action中的變量,就需要把Action中的變量,放到request域中才行。所以,早在 Webwork2.1.X的年代,我們會編寫一個攔截器來做這個事情的。大致的原理是:在Action執行完返回之前,依次讀取Action中的所有的變 量,並依次調用request.setAttribute()來進行設置。具體的整合方式,請參考以下這篇文檔:
不過隨着時代的發展,上面的這種方式,已經不再被推薦使用了。(雖然如此,我們依然可以學習它的一個解決問題的思路)目前來說,自從 Webwork2.2以後,包括Struts2,都使用另外一種整合方式:對HttpServletRequest進行裝飾。讓我們來看一下源碼:
public class StrutsRequestWrapper extends HttpServletRequestWrapper {
/**
* The constructor
* @param req The request
*/
public StrutsRequestWrapper(HttpServletRequest req) {
super(req);
}
/**
* Gets the object, looking in the value stack if not found
*
* @param s The attribute key
*/
public Object getAttribute(String s) {
if (s != null && s.startsWith("javax.servlet")) {
// don't bother with the standard javax.servlet attributes, we can short-circuit this
// see WW-953 and the forums post linked in that issue for more info
return super.getAttribute(s);
}
ActionContext ctx = ActionContext.getContext();
Object attribute = super.getAttribute(s);
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 && attribute == null && 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;
}
}
看到了嘛?這個類會在Struts2初始化的時候,替換HttpServletRequest,運行於整個Struts2的運行過程中,當我們試 圖調用request.getAttribute()的時候,就會執行上面的這個方法。(這是一個典型的裝飾器模式)在執行上面的方法時,會首先調用 HttpServletRequest中原本的request.getAttribute(),如果沒有找到,它會繼續到ValueStack中去查找, 而action在ValueStack中,所以action中的變量通過OGNL表達式,就能找到對應的值了。