struts使用中el与ognl
本文基于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 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;
- }
3.JSP中的使用
JSP2.0可以直接使用EL表达式,方便变量的获取。使用struts2的标签,可以取到ActionContext中的对象,如action中的成员变量,非root中的变量使用标记方式。
另外,struts2标签中,非字符类型(如boolean,int型)的属性取值,需要使用%{expr}的方式。在JSP中也可以使用EL表达式获取
Action中的成员属性,原因是struts2对request进行了封装
(org.apache.struts2.dispatcher.StrutsRequestWrapper),重写了
request.getAttribute()方法,查找范围扩大到了ActionContext的root中,核心代码如下:
- 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;
- }
浙公网安备 33010602011771号