<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    瘋狂

    STANDING ON THE SHOULDERS OF GIANTS
    posts - 481, comments - 486, trackbacks - 0, articles - 1
      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

    1.     數(shù)據(jù)傳輸背后機制:ValueStack(值棧)
     

    在這一切的背后,是因為有了ValueStack(值棧)!

     

    ValueStack基礎(chǔ):OGNL
    要了解ValueStack,必須先理解OGNL(Object Graphic Navigatino Language)!

    OGNL是Struts2中使用的一種表達式語言,它可以用于JSP的標簽庫中,以便能夠方便的訪問各種對象的屬性;它用于界面將參數(shù)傳遞到Action(并進行類型轉(zhuǎn)換)中;它還可以用于struts2的配置文件中!所以,非常有必要理解OGNL的基本機制。

     

    Root對象
    OGNL稱為對象圖導(dǎo)航語言。所謂對象圖,即以任意一個對象為根,通過OGNL可以訪問與這個對象關(guān)聯(lián)的其它對象。如:

    package cn.com.leadfar.struts2.actions;

     

    public class User {

        private String username;

        private Group group;

       

        public String getUsername() {

           return username;

        }

        public void setUsername(String username) {

           this.username = username;

        }

       

        public Group getGroup() {

           return group;

        }

        public void setGroup(Group group) {

           this.group = group;

        }

    }

     
     
    package cn.com.leadfar.struts2.actions;

     

    public class Group {

        private String name;

        private Organization org;

        public String getName() {

           return name;

        }

     

        public void setName(String name) {

           this.name = name;

        }

     

        public Organization getOrg() {

           return org;

        }

     

        public void setOrg(Organization org) {

           this.org = org;

        }

    }

     
     
    package cn.com.leadfar.struts2.actions;

     

    public class Organization {

        private String orgId;

     

        public String getOrgId() {

           return orgId;

        }

     

        public void setOrgId(String orgId) {

           this.orgId = orgId;

        }

    }

     
     

     

    上面三個類,描述了通過一個User對象,可以導(dǎo)航到Group對象,進而導(dǎo)航到Organization對象,以User對象為根,一個對象圖如下所示:

     

    User(root)

       -- username

       -- group

          -- name

          -- org

             -- orgId

     

    在真實的環(huán)境下,這個對象圖可能會極其復(fù)雜,但是通過基本的getters方法,都應(yīng)該能夠訪問到某個對象的其它關(guān)聯(lián)對象。【對象圖的導(dǎo)航,必須通過getters方法進行導(dǎo)航】

     

    下述代碼將創(chuàng)建一個User對象,及其相關(guān)的一系列對象:

           User user = new User();

           Group g = new Group();

           Organization o = new Organization();

            o.setOrgId("ORGID");

           g.setOrg(o);

           user.setGroup(g);
     

     

    如果通過JAVA代碼來進行導(dǎo)航(依賴于getters方法),導(dǎo)航到Organization的orgId屬性,如下所示:

     

    //用JAVA來導(dǎo)航訪問

    user.getGroup().getOrg().getOrgId();

     
     

     

    【注意:導(dǎo)航的目的,是為了獲取某個對象的值或設(shè)置某個對象的值或調(diào)用某個對象的方法!】

    【注意:OGNL表達式語言的真正目的,是為了在那些不能寫JAVA代碼的地方執(zhí)行JAVA代碼,或者是為了更方便地執(zhí)行JAVA代碼】

     

    利用OGNL進行導(dǎo)航的代碼如下:

     

           //利用OGNL表達式訪問

           String value = (String)Ognl.getValue("group.org.orgId", user);

     
     

    Ognl.getValue()方法的第一個參數(shù),就是一條OGNL表達式,第二個參數(shù)是指定在表達式中需要用到的root對象!

    完整代碼如下:

        public void testOgnl01() throws Exception{

           User user = new User();

           user.setUsername("張三");

          

           //利用OGNL表達式訪問user對象的username屬性

           String value = (String)Ognl.getValue("username", user);

           log(value);

        }

       

        public void testOgnl02() throws Exception{

           User user = new User();

           Group g = new Group();

           Organization o = new Organization();

           o.setOrgId("ORGID");

           g.setOrg(o);

           user.setGroup(g);

          

           //用JAVA來導(dǎo)航訪問

           log(user.getGroup().getOrg().getOrgId());

          

           //利用OGNL表達式訪問

           String value = (String)Ognl.getValue("group.org.orgId", user);

           log(value);

        }

       

        public void testOgnl03() throws Exception{

           User user = new User();

           Group g = new Group();

           Organization o = new Organization();

           o.setOrgId("ORGID");

           g.setOrg(o);

           user.setGroup(g);

          

           //用JAVA來導(dǎo)航訪問

           log(user.getGroup().getOrg().getOrgId());

          

           //也可以在表達式中使用#root來代表root對象

           String value = (String)Ognl.getValue("#root.group.org.orgId", user);

           log(value);

        }

        private void log(Object o){

           System.out.println(o);

        }
     

     

     

    Context對象
    在OGNL的表達式中,有可能需要訪問到多個毫不相干的對象,這時候,我們需要給OGNL傳遞一個Map類型的對象,把表達式中需要用到的對象放到Map中即可!這個Map對象,稱為context。

     

    要在表達式中訪問到context中的對象,需要使用“#對象名稱”的語法規(guī)則。

    如:

        public void testOgnl04() throws Exception{

           User user = new User();

           user.setUsername("張三");

           Group g = new Group();

           Organization o = new Organization();

           o.setOrgId("ORGID");

           g.setOrg(o);

           user.setGroup(g);

          

           User user2 = new User();

           user2.setUsername("李四");

          

           /**

            * 所謂context其實就是一個Map類型的對象。主要是因為在OGNL中,不支持多個root對象,那么

            * 如果需要在表達式中訪問更多毫不相干的對象時,只能通過一個Map來把這些對象統(tǒng)一傳遞給OGNL。

            */

           Map context = new HashMap();

           context.put("u1", user);

           context.put("u2", user2);

          

           //在表達式中需通過“#+對象的名稱”來訪問context中的對象

           //如果表達式中沒有用到root對象,那么可以用任意一個對象代表root對象!

           String value = (String)Ognl.getValue("#u1.username + ',' + #u2.username", context,new Object());

           log(value);

        }

       

        public void testOgnl05() throws Exception{

           User user = new User();

           user.setUsername("張三");

           Group g = new Group();

           Organization o = new Organization();

           o.setOrgId("ORGID");

           g.setOrg(o);

           user.setGroup(g);

          

           User user2 = new User();

           user2.setUsername("李四");

          

           User user3 = new User();

           user3.setUsername("王五");

          

           Map context = new HashMap();

           context.put("u1", user);

           context.put("u2", user2);

          

           //給OGNL傳遞root對象及context對象,以便解釋對應(yīng)的表達式

           String value = (String)Ognl.getValue("#u1.username + ',' + #u2.username + ',' + username", context,user3);

           log(value);

        }
     

     

    利用OGNL表達式進行賦值
     

    OGNL表達式也可以用于賦值操作。

        public void testOgnl06() throws Exception{

           User user = new User();

          

           //調(diào)用setValue()方法來進行賦值

           //第一個參數(shù):OGNL表達式

           //第二個參數(shù):root對象

           //第三個參數(shù):要賦的值     

           Ognl.setValue("username", user, "張三");

     

           log(user.getUsername());

        }

       

        public void testOgnl07() throws Exception{

           User user = new User();

          

           Map context = new HashMap();

           context.put("u", user);

          

           //調(diào)用setValue()方法來進行賦值

           //第一個參數(shù):OGNL表達式

           //第二個參數(shù):context對象

            //第三個參數(shù):root對象

           //第四個參數(shù):要賦的值

           Ognl.setValue("#u.username", context, new Object(), "張三");

     

           log(user.getUsername());

        }

       

        public void testOgnl08() throws Exception{

           User user = new User();

          

           Map context = new HashMap();

           context.put("u", user);

           

           //利用賦值符號"="來進行賦值

           Ognl.getValue("#u.username = '李四'", context, new Object());

     

           log(user.getUsername());

        }

       

        public void testOgnl09() throws Exception{

           User user1 = new User();

           User user2 = new User();

           Map context = new HashMap();

           context.put("u1", user1);

           context.put("u2", user2);

          

           //在一個表達式中可以用逗號分隔,同時執(zhí)行多個表達式

           Ognl.getValue("#u1.username = '李四',#u2.username='王五'", context, new Object());

     

           log(user1.getUsername());

           log(user2.getUsername());

        }
     

     

    利用OGNL調(diào)用對象的方法
     

        //************************* OGNL調(diào)用對象的方法 *****************************//

        public void testOgnl10() throws Exception{

           User user = new User();

          

           //如果是調(diào)用root對象的方法,可以直接使用方法的名稱來調(diào)用方法

           Integer value = (Integer)Ognl.getValue("addSomething(1,1)", user);

           log(value);

        }

       

        public void testOgnl11() throws Exception{

           User user = new User();

           user.setUsername("李四");

           //如果是調(diào)用root對象的方法,可以直接使用方法的名稱來調(diào)用方法

           String value = (String)Ognl.getValue("getUsername()", user);

           log(value);

        }

       

        public void testOgnl12() throws Exception{

           User user = new User();

           Ognl.getValue("setUsername('王五')", user);

           String value = (String)Ognl.getValue("getUsername()", user);

           log(value);

        }

       

        //************************* OGNL調(diào)用靜態(tài)方法和變量 *********************//

        public void testOgnl13() throws Exception{

           User user = new User();

           user.setUsername("王五");

           //調(diào)用靜態(tài)變量

           //注意:out是System中的靜態(tài)變量,out是PrintStream類型的一個對象

           //而println()則是out這個對象中的實例方法(不是靜態(tài)方法)

           //調(diào)用靜態(tài)方法,需要在類名和變量名前面加上@來調(diào)用,對于實例方法,用"."來調(diào)用

           Ognl.getValue("@System@out.println(username)", user);

        }

       

        public void testOgnl14() throws Exception{

           User user = new User();

           user.setUsername("wangwu");

           //調(diào)用靜態(tài)方法,注意使用全路徑類名

            Ognl.getValue("@System@out.println(@cn.com.leadfar.utils.Utils@toUpperCase(username))", user);

        }
     

     

    利用OGNL訪問數(shù)組、集合對象
     

        public void testOgnl15() throws Exception{

          

           Object root = new Object();

           Map context = new HashMap();

          

           //利用OGNL創(chuàng)建java.util.List對象

           List list = (List)Ognl.getValue("{123,'xxx','kdjfk'}", context, root);

           context.put("list", list);

          

           //利用OGNL創(chuàng)建數(shù)組

           int[] intarray = (int[])Ognl.getValue("new int[]{23,45,67}", context, root);

           context.put("intarray", intarray);

          

           //利用OGNL表達式創(chuàng)建java.util.Map對象

           Map mapvalue = (Map)Ognl.getValue("#{'listvalue':#list,'intvalue':#intarray}", context, root);

           context.put("mapvalue", mapvalue);

          

           //利用OGNL表達式訪問這些數(shù)組和集合對象

           Ognl.getValue("@System@out.println(#list[1])", context,root);

           Ognl.getValue("@System@out.println(#intarray[2])", context,root);

           Ognl.getValue("@System@out.println(#mapvalue.listvalue[0])", context,root);

           Ognl.getValue("@System@out.println(#mapvalue['intvalue'][0])", context,root);

        }

       

        public void testOgnl16() throws Exception{

          

           List root = new ArrayList();

           User user1 = new User();

           user1.setUsername("張三");

           User user2 = new User();

           user2.setUsername("李四");

           root.add(user1);

           root.add(user2);

          

           //如果root對象是List類型

           log(Ognl.getValue("#root[0].username", root));

           log(Ognl.getValue("#root[1].username", root));

        }
     

     

     

     

    更多的特性,請參考官方的文檔
     

    OGNL官方文檔地址:http://www.opensymphony.com/ognl/html/LanguageGuide/index.html

     

    應(yīng)用:ValueStack
     

    理解ValueStack的基本機制!對各種現(xiàn)象作出解釋。

    ValueStack實際上就是對OGNL的封裝,OGNL主要的功能就是賦值與取值,Struts2正是通過ValueStack來進行賦值與取值的!

     


    ValueStack是一個接口,而OgnlValueStack是strtus2中的缺省實現(xiàn)。ValueStack中的數(shù)據(jù),分兩個部分存放:root和context(這與OGNL中的概念一致),同時ValueStack暴露相關(guān)的接口:

    void setValue(String expr, Object value);

    Object findValue(String expr);

    用來通過OGNL表達式對ValueStack中的數(shù)據(jù)進行操作!

     

    ValueStack中的root對象是CompoundRoot,CompoundRoot繼承了ArraryList,提供了額外的方法:push()和pop()方法,用來對root對象中所包含的數(shù)據(jù)進行存取!

    public class CompoundRoot extends ArrayList {

     

        public CompoundRoot() {

        }

     

        public CompoundRoot(List list) {

            super(list);

        }

     

     

        public CompoundRoot cutStack(int index) {

            return new CompoundRoot(subList(index, size()));

        }

     

        public Object peek() {

            return get(0);

        }

     

        public Object pop() {

            return remove(0);

        }

     

        public void push(Object o) {

            add(0, o);

        }

    }
     

     

    正是通過這兩個方法,CompoundRoot變成了一個棧結(jié)構(gòu)!壓棧操作,將導(dǎo)致對象被放到CompoundRoot的第0個元素上(第0個元素是棧頂),其它對象被依次往后移動;出棧操作,將導(dǎo)致CompoundRoot的第0個元素被移除(即棧頂元素被彈出),其它對象被依次往前移動!

     

    OGNL不支持多個root對象,而struts2能夠支持多個root對象,它對OGNL做了擴展。

    如果某個OGNL表達式被傳遞給ValueStack(即調(diào)用ValueStack的setValue或findValue方法),而表達式中包含有對root對象的訪問操作,ValueStack將依次從棧頂往棧底搜索CompoundRoot對象中所包含的對象,看哪個對象具有相應(yīng)的屬性,找到之后,立刻返回。

     

    在Struts2中,一個請求在最終到達Action的方法之前,Action對象本身會被壓入ValueStack(實際上就是放到ValueStack的CompoundRoot中),所以Action對象是CompoundRoot中的一個元素。看下面的代碼:

    public class UserAction {

        private String username;

        private Integer age;

        private boolean valid;

       

        //查看用戶的詳細信息

        public String detail(){

          

           username = "張三";

           age = 18;

           valid = true;

          

           return "detail";

        }
     

    在Action中,給Action的username/age/valid賦值。Detail頁面如下:

    username:<s:property value="username"/> <br/>

    valid:<s:property value="valid"/> <br/>

    age:<s:property value="age"/> <br/>
     

    上述JSP頁面將能正確將它們的值取出。<s:property value=”ognl表達式”/>。在s:property標簽中的OGNL表達式,最終會交給ValueStack來解釋。username就是一個OGNL表達式,意思是調(diào)用root對象的getUsername()方法。Struts2將自動搜索CompoundRoot中有哪些元素(從第0個元素開始搜索),檢測這些元素是否有g(shù)etUsername()方法,如果第0個元素沒有g(shù)etUsername()方法,將繼續(xù)搜索第1、2、3……個元素是否有g(shù)etUsername()方法。

     

    在上面的例子中,CompoundRoot中只有一個對象,就是userAction對象,而這個對象中正好有g(shù)etUsername()方法,所以,上述JSP代碼將能夠?qū)⒅嫡_取出。

     

    再看下面的例子:

    public class UserAction {

        private String username;

        private String name;

       

        //查看用戶的詳細信息

        public String detail(){

           username = "張三";

           name = "王五";

          

           User u = new User();

           u.setUsername("趙毅");

           ActionContext.getContext().getValueStack().push(u);

          

           return "detail";

        }
     

    在上面這個UserAction的代碼中,我們直接調(diào)用ActionContext.getContext().getValueStack().push()方法,把一個User對象(這個對象擁有g(shù)etUsername()和setUsername()方法)直接壓入到ValueStack中,這時候,在ValueStack的CompoundRoot中將有兩個元素:第0個元素是剛剛壓入的user對象[趙毅],而第1個元素是userAction對象[張三],如果在JSP中使用下面的表達式來取值:

    <s:property value=”username”/> ,那么輸出的值將是“趙毅”!道理上面已經(jīng)講過了,struts2將會從第0個元素開始搜索CompoundRoot中的對象,第0個元素正是剛剛壓入的那個user對象!

    如果在JSP中使用<s:property value=”name”/>來取值,將取出“王五”,因為第0個元素user對象沒有name屬性,所以,會繼續(xù)搜索第1個元素userAction對象,在這個對象中就有name屬性了!

     

    再看下面的代碼:

    public class UserAction {

        private String username;

       

        //查看用戶的詳細信息

        public String detail(){

           username = "張三";

          

           List list = new ArrayList();

           for(int i=0; i<10; i++){

               User user = new User();

               user.setUsername("User"+i);

               list.add(user);

           }

           ActionContext.getContext().put("users", list);

          

           User u = new User();

           u.setUsername("趙毅");

           ActionContext.getContext().getValueStack().push(u);

          

           return "detail";

        }
     

     

    對應(yīng)的JSP如下:

    1:  <s:property value="username"/> <br/>

    2:  <s:iterator value="#users">

    3:     <s:property value="username"/>

    4:     <s:property value="#root[2].username"/><br/>

    5:  </s:iterator>

    6:  <s:property value="username"/>

    7:  <s:property value="#root[1].username"/> <!-- 張三 -->
     

     

    根據(jù)剛才的示例,我們知道,第1行的username是“趙毅”(因為JSP在執(zhí)行這行代碼的時候,CompoundRoot中有兩個元素:第0個是“user對象趙毅”,第1個是“userAction對象張三”),因此第1行的username將取出CompoundRoot中第0個元素的username屬性:趙毅

     

    第2行代碼是iterator標簽,只定義了一個value屬性,iterator標簽將循環(huán)訪問users這個List中的User對象,并把當(dāng)前循環(huán)的user對象壓入到CompoundRoot中!所以,在第3行和第4行代碼被執(zhí)行的時候,CompoundRoot中總共有3個元素:第0個元素是被iterator標簽壓入的當(dāng)前循環(huán)的user對象;第1個元素是“user對象趙毅”;第2個元素是“userAction對象張三”,因此第3行代碼的執(zhí)行結(jié)果就是輸出“UserX”,即當(dāng)前循環(huán)的user對象的username屬性!iterator標簽將會依次取出List中的user對象,并不斷壓入/彈出user對象(每次循環(huán),都將執(zhí)行一遍壓入/彈出)。而第4行代碼取第2個元素的username屬性,即userAction對象的username屬性:張三。

     

    第5行代碼執(zhí)行完成之后,在CompoundRoot中將剩下2個元素,與第2行代碼被執(zhí)行之前一樣。所以,第6行代碼的輸出和第1行代碼的輸出結(jié)果是一樣的,而第7行代碼將取出userAction對象的username屬性:張三

     

    本文來自CSDN博客http://blog.csdn.net/li_tengfei/archive/2010/12/25/6098134.aspx


    評論

    # re: Struts2數(shù)據(jù)傳輸?shù)谋澈髾C制:ValueStack(值棧)(轉(zhuǎn)載)  回復(fù)  更多評論   

    2011-04-04 14:51 by 好,很不錯!
    很深入,讓我對ognl的認識一下子提高了不少。以前總是模模糊糊的,不清楚怎么回事。

    # re: Struts2數(shù)據(jù)傳輸?shù)谋澈髾C制:ValueStack(值棧)(轉(zhuǎn)載)[未登錄]  回復(fù)  更多評論   

    2012-06-25 11:00 by duan
    很不錯,謝謝了

    # re: Struts2數(shù)據(jù)傳輸?shù)谋澈髾C制:ValueStack(值棧)(轉(zhuǎn)載)  回復(fù)  更多評論   

    2012-09-24 16:55 by 軾傭
    很不錯。。理解了。。

    # re: Struts2數(shù)據(jù)傳輸?shù)谋澈髾C制:ValueStack(值棧)(轉(zhuǎn)載)  回復(fù)  更多評論   

    2012-10-12 16:29 by struts2
    非常非常好!!!

    # re: Struts2數(shù)據(jù)傳輸?shù)谋澈髾C制:ValueStack(值棧)(轉(zhuǎn)載)[未登錄]  回復(fù)  更多評論   

    2013-03-19 22:09 by jason
    非常不錯!!!!!

    # re: Struts2數(shù)據(jù)傳輸?shù)谋澈髾C制:ValueStack(值棧)(轉(zhuǎn)載)[未登錄]  回復(fù)  更多評論   

    2013-04-08 16:26 by
    很好呀,謝謝

    # re: Struts2數(shù)據(jù)傳輸?shù)谋澈髾C制:ValueStack(值棧)(轉(zhuǎn)載)[未登錄]  回復(fù)  更多評論   

    2013-09-04 09:37 by feng
    搞明白了,非常感謝

    # re: Struts2數(shù)據(jù)傳輸?shù)谋澈髾C制:ValueStack(值棧)(轉(zhuǎn)載)  回復(fù)  更多評論   

    2013-09-22 10:21 by 黃全軍
    非常好 謝謝

    # re: Struts2數(shù)據(jù)傳輸?shù)谋澈髾C制:ValueStack(值棧)(轉(zhuǎn)載)  回復(fù)  更多評論   

    2013-12-25 18:04 by 李佳新
    好文,感謝博主讓我對Struts標簽和ValueStack有了比較清楚的認識了

    # re: Struts2數(shù)據(jù)傳輸?shù)谋澈髾C制:ValueStack(值棧)(轉(zhuǎn)載)  回復(fù)  更多評論   

    2014-01-04 22:57 by 小衛(wèi)
    終于弄懂了,真是太感謝了,我決定把網(wǎng)址下載下來與其他程序員朋友分享

    # re: Struts2數(shù)據(jù)傳輸?shù)谋澈髾C制:ValueStack(值棧)(轉(zhuǎn)載)  回復(fù)  更多評論   

    2014-04-22 21:23 by yidongtest@163.com
    最后一點沒看明白,為什么循環(huán)迭代的那個users會做出棧操作啊(壓棧我能理解)。其他的<s:property value="username"/>不會將趙毅或者王五出棧啊,難道是這個循環(huán)標簽里面做的出棧操作?

    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 久久精品国产免费观看| 爽爽日本在线视频免费| 激情综合亚洲色婷婷五月| 成年美女黄网站色大免费视频| 久久精品熟女亚洲av麻豆| 4338×亚洲全国最大色成网站| 四虎影视在线影院在线观看免费视频| 国产精品亚洲精品| 亚洲无码日韩精品第一页| 中文字幕免费视频一| 色窝窝亚洲AV网在线观看| 亚洲人成电影在在线观看网色| 天天摸天天操免费播放小视频 | 亚洲w码欧洲s码免费| 亚洲成片观看四虎永久| 久久永久免费人妻精品下载| 处破女第一次亚洲18分钟| 亚洲成在人天堂在线| 免费永久国产在线视频| 1000部拍拍拍18勿入免费凤凰福利| 黄网站色视频免费看无下截| 亚洲综合图片小说区热久久| 亚洲美女在线国产| 我要看WWW免费看插插视频| 西西人体免费视频| 亚洲av无码专区在线电影天堂 | 精品一区二区三区免费毛片| 亚洲网红精品大秀在线观看| 亚洲精品麻豆av| 无限动漫网在线观看免费| 水蜜桃视频在线观看免费播放高清 | 在线亚洲精品视频| 亚洲男人电影天堂| 国产AV无码专区亚洲Av| 青青青国产色视频在线观看国产亚洲欧洲国产综合 | 亚洲av无码国产精品色在线看不卡| 69式互添免费视频| 日本免费在线中文字幕| 一区二区三区AV高清免费波多| 99999久久久久久亚洲| 亚洲最新永久在线观看|