Struts2中的ActionContext、OGNL及EL的使用
本文基于struts2.1.8.1,xwork2.1.6
1.EL
EL(Expression Language)源于jsp页面标签jstl,后来被jsp2.0直接支持,因此可以在jsp页面中直接使用EL表达式。其使用语法为${expr},如${username},表达式expr中变量的获取,默认使用PageContext.findAttribute(String)方法,也就是从pageContext隐藏对象中查找,pageContext隐藏对象包含以下隐藏对象:request,response,session,servletContext.查找范围顺序是page, request,session, and application,找不到则返回null。指定对象查找则使用${implictObject.foo}语法,其中implictObject代表任意隐藏对象,除pageContext之外,还包含:param,paramValues,header,headerValues,cookie,initParam以及pageScope,requestScope,sessionScope,applicationScope等。
注意:自定义变量如果和隐藏对象同名,${implicitObject}将返回隐藏对象,而不是自定义对象的值。
2.OGNL in Struts2
struts2使用ActionContext作为OGNL的上下文,也就是ActionContext.context,其默认的root上下文是一个OGNL的值栈(OgnlValueStack),用于存放action的实例,其访问不需要标记,同时存放了其它的对象,如request,parameters,session,application,attr等,访问需要#标记并指明对象名称,如#session.username.由于ActionContext存放到ThreadLocal中,所以是线程安全的。在同一个请求经过不同的action转发(forward)处理的过程中,这些action实例都会压进root这个值栈中,最后的在最上面,查找变量值也是从上面开始顺序往下。
ActionContext是由org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter进行初始化的,在doFilter中调用prepare.createActionContext(request, response);追踪下去,核心代码在org.apache.struts2.dispatcher.ng.PrepareOperations中:
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); 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; }