https://cloud.tencent.com/developer/article/1391154 这是我的有关 struts2 的第一篇文章,对于里面我们说到的一个 struts2 HelloWorld 小练习,即在输入框输入信息提交后在另外一个页面显示输入的信息,显示页面的代码如下:
UserName: ${userName}<br>
Email: ${email}<br>
Address: ${address}<br>
为什么这样一个简单的标签就可以获取到另外一个页面的输入信息,我们使用上面链接中的代码并在其基础上加以改进以得到答案!
我们知道 struts 默认的请求类型为 dispatcher,即请求转发,那么我们尝试在 show.jsp 中利用 request 域对象打印输入值,如下(在前面加上标识以区分):
UserDesc: ^+^<%= request.getAttribute("userDesc")%><br>
结果如下图:
如上图所示,此时的 request 是已经被 struts2 封装的 request,在 IDEA 中双击 Shift 查找 StrustsRequestWrapper 源代码,找到其 getAttributte() 方法,如下:
public class StrutsRequestWrapper extends HttpServletRequestWrapper {
public Object getAttribute(String key) {
if (key == null) {
throw new NullPointerException("You must specify a key value");
}
if (disableRequestAttributeValueStackLookup || key.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(key);
}
ActionContext ctx = ActionContext.getContext();
Object attribute = super.getAttribute(key);
if (ctx != null && attribute == null) {
boolean alreadyIn = isTrue((Boolean) ctx.get(REQUEST_WRAPPER_GET_ATTRIBUTE));
// note: we don't let # come through or else a request for
// #attr.foo or #request.foo could cause an endless loop
if (!alreadyIn && !key.contains("#")) {
try {
// If not found, then try the ValueStack
ctx.put(REQUEST_WRAPPER_GET_ATTRIBUTE, Boolean.TRUE);
ValueStack stack = ctx.getValueStack();
if (stack != null) {
attribute = stack.findValue(key);
}
} finally {
ctx.put(REQUEST_WRAPPER_GET_ATTRIBUTE, Boolean.FALSE);
}
}
}
return attribute;
}
}
为了一探究竟我们 Debug 一步步调试查看,首先 Debug 运行程序,在输入页面输入信息之后再在源代码页面上打断点(在源代码页面的 ValueStack 前一行打断点),再点击提交将会跳转到调试页!
至此我们得知显示页面的底层实现,即从 ValueStack 中获取,其默认从栈顶开始寻找与 key 值匹配的属性,依次往下,也了解到值栈的基本概念,接下来让我们着手利用 OGNL 获取值栈里对象的属性。