struts2 ognl表達式訪問值棧

1:簡單的說,值棧是對應每個請求對象的輕量級的數據存儲中心,在這裏統一管理着數據,供Action、Result、Interceptor等Struts2的其餘部分使用,這樣數據被集中管理起來而不凌亂。html

      簡單的說,值棧可以線程安全的爲每一個請求提供公共的數據存取服務。java

      當有請求的時候,Struts2會爲每一個請求建立一個新的值棧,也就是說,棧和請求是一一對應的,不一樣的請求,值棧也不同,而值棧封裝了一次請求全部須要操做的相關的數據。express

     正是由於值棧和請求的對應關係,所以值棧能保證線程安全的爲每一個請求提供公共的數據存取服務。apache

 

2:狹義值棧api

     一般是指com.opensymphony.xwork2.util.ValueStack接口的對象,目前就是com.opensymphony.xwork2.ognl.OgnlValueStack對象。安全

     狹義值棧主要用來存放動態EL(表達式語言)運算須要的值和結果,固然OgnlValueStack對象主要是用來支持OGNL(對象圖導航語言)運算的。session

     狹義值棧中存放着一些OGNL能夠訪問的數據,以下:app

        a:action的實例,這樣就能夠經過OGNL來訪問Action實例中的屬性的值了。less

        b:OGNL表達式運算的值,能夠設置到值棧中,能夠主動訪問值棧對象,強行設置。jsp

        c:OGNL表達式產生的中間變量,好比使用Struts2標籤的時候,使用循環標籤,天然會有循環的變量,這些都放在值棧中。

 

3:廣義值棧

   一般是ActionContext對象,ActionContext是Action運行的上下文,每一個ActionContext是一個基本的容器,包含着Aciton運行須要的數據,好比請求參數,會話等。

  ActionContext也是線程安全的,每一個線程都有一個獨立的ActionContext,這樣就不用擔憂值棧中值得線程安全問題了。

  ActionContext裏面存儲着不少值,以下:

     a:Request的Parameters,請求中的參數,注意這裏的數據是從數據對象中複製來的,所以這裏的數據的變化是不會影響到請求對象裏面的參數的值的。

     b:Request的Attribute,請求中的屬性,這裏是一個Map,存放着請求對象的屬性數據,這些數據和請求對象的Attribute是聯動的。

     c:Application的Attribute,應用的屬性,這裏是一個Map,存放着應用對象的屬性數據,這些數據和應用對象的attribute是聯動的。

     d:ValueStack,也就是狹義值棧,ActionContext是以value stack做爲被OGNL訪問的根,簡單的說,OGNL在沒有特別指明的狀況下,訪問的就是value stack的值。

     e:attr,在全部的屬性範圍中獲取值,依次搜索page, request, session 和applicaion

 

4:ActionContext的使用

   獲取,經過兩種方式,第一種,使用ActionContext自身的方法來獲取

     ActionContext ctx = ActionContext.getContext();

   第二種,使用ActionInvocation來獲取

     ActionContext ctx = actionInvocation.getInvocationContext();

   它的典型方法以下:

   

 Objectget(String key):Returns a value that is stored in the current ActionContext by doing a lookup using the value's key.

  void put(String key,Object value):Stores a value in the current ActionContext.

  Map<String,Object>getApplication():  Returns a Map of the ServletContext when in a servlet environment or a generic application level Map otherwise.

                                         即返回ServletContext中返回的值

  Map<String,Object>getSession():Gets the Map of HttpSession values when in a servlet environment or a generic session map otherwise.

  Map<String,Object>getContextMap():Gets the context map.

  Map<String,Object>getParameters(): Returns a Map of the HttpServletRequest parameters when in a servlet environment or a generic Map of parameters otherwise.

  

 

5:ValueStack的使用

   ValueStack有一個特色,若是訪問的值棧裏有多個對象,且相同的屬性在多個對象中同時出現,則值棧會按照從棧頂到棧底的順序,尋找第一個匹配的對象。

   ValueStack的獲取:直接由ActionContext對象的getValueStack()方法便可得到。

   使用函數:

  

  ObjectfindValue(String expr): Find a value by evaluating the given expression against the stack in the default search order.

    voidsetValue(String expr,Object value):  Attempts to set a property on a bean in the stack with the given expression using the default search order.

     Object peek():Get the object on the top of the stack without changing the stack.

     Objectpop():Get the object on the top of the stack and remove it from the stack.

     voidpush(Object o):Put this object onto the top of the stack

 

 

6:例子,修改用戶輸入的參數信息,以下圖所示,

  


      圖:用戶輸入了aa的username

 


                   圖:用戶提交後發現username屬性的值發生了變化

 

實現:

  首先定義一個實現PreResultListener接口的類:MyPreResultListener

  

[html]  view plain  copy
 
import com.opensymphony.xwork2.ActionInvocation;  
import com.opensymphony.xwork2.interceptor.PreResultListener;  
  
public class MyPreResultListener implements PreResultListener {  
  
    @Override  
    public void beforeResult(ActionInvocation invocation, String resultCode) {  
        System.out.println("如今處理Result執行前的功能, result=" + resultCode);  
          
        //在Result處理以前修改value stack裏面的username對應的值  
        invocation.getInvocationContext().getValueStack().setValue("username", "被修改了");  
  
    }  
  
}  


 

而後在相應的Action中進行註冊:

  

[java] view plain copy
 
import com.capinfotech.listener.MyPreResultListener;  
import com.opensymphony.xwork2.ActionContext;  
import com.opensymphony.xwork2.ActionSupport;  
  
public class PreResultAction extends ActionSupport {  
  
    private String username;  
    private String password;  
  
    public String getUsername() {  
        return username;  
    }  
  
    public void setUsername(String username) {  
        this.username = username;  
    }  
  
    public String getPassword() {  
        return password;  
    }  
  
    public void setPassword(String password) {  
        this.password = password;  
    }  
      
    public String execute() {  
        System.out.println("用戶輸入的參數爲,username:" + username + ", password:" + password);  
          
        ActionContext context = ActionContext.getContext();  
        MyPreResultListener preListener = new MyPreResultListener();  
        context.getActionInvocation().addPreResultListener(preListener);  
          
        return "success";  
          
    }  
  
}  
/*
 * $Id$
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.apache.struts2.dispatcher;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.util.ValueStack;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import static org.apache.commons.lang3.BooleanUtils.isTrue;

/**
 * <!-- START SNIPPET: javadoc -->
 *
 * All Struts requests are wrapped with this class, which provides simple JSTL accessibility. This is because JSTL
 * works with request attributes, so this class delegates to the value stack except for a few cases where required to
 * prevent infinite loops. Namely, we don't let any attribute name with "#" in it delegate out to the value stack, as it
 * could potentially cause an infinite loop. For example, an infinite loop would take place if you called:
 * request.getAttribute("#attr.foo").
 *
 * <!-- END SNIPPET: javadoc -->
 *
 */
public class StrutsRequestWrapper extends HttpServletRequestWrapper {

    private static final String REQUEST_WRAPPER_GET_ATTRIBUTE = "__requestWrapper.getAttribute";
    private final boolean disableRequestAttributeValueStackLookup;

    /**
     * The constructor
     * @param req The request
     */
    public StrutsRequestWrapper(HttpServletRequest req) {
        this(req, false);
    }

    /**
     * The constructor
     * @param req The request
     * @param disableRequestAttributeValueStackLookup flag for disabling request attribute value stack lookup (JSTL accessibility)
     */
    public StrutsRequestWrapper(HttpServletRequest req, boolean disableRequestAttributeValueStackLookup) {
        super(req);
        this.disableRequestAttributeValueStackLookup = disableRequestAttributeValueStackLookup;
    }

    /**
     * Gets the object, looking in the value stack if not found
     *
     * @param key The attribute key
     */
    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;
    }
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page isELIgnored="false" %>
<html>
<body>
<h2>Hello World!</h2>
<h1><s:iterator value="list">
    <s:property value="userName"></s:property>
</s:iterator></h1>

<s:iterator value="list" var="item">
    <s:property value="#userName"></s:property>
</s:iterator>


<h3><s:property value="#info.userName"></s:property></h3>
<s:debug></s:debug>
</body>
</html>
相關文章
相關標籤/搜索