




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
與MVC框架解耦的OGNL:前世今生
及其基本用法一.OGNL概述1、 OGNL的前世今生WebWork是建立在稱為XWork的Command模式框架之上的強大的基于Web的MVC框架。關于WebWork我們大多數人可能不太熟悉,最多只是有一種在哪里見過的感覺,但是我一提Struts2,估計大家就能想起來了。眾所周知,Struts2是Struts的下一代產品,是在Strutsl和WebWork的技術基礎上進行了合并的全新框架。需要特別注意的是,全新的Struts2的體系結構與Strutsl差別巨大,因為Struts2是以WebWork為核心的,繼承了更多的WebWork血統。實際上,WebWork已經完全從Web層脫離出來的一個非常優秀的框架,其提供了很多核心的、Struts2還在使用的功能,包括前端攔截器(interceptor)、運行時表單屬性驗證、類型轉換、IoC(InversionofControl)容器等,其中就有我們今天的主角,強大的表達式語言——OGNL(ObjectGraphNotationLanguage)。2、 OGNL帶給我們的實惠OGNL是ObjectGraphNavigationLanguage的縮寫,全稱為對象圖導航語言,是一種功能強大的表達式語言。它通過簡單一致的語法,可以存取Java對象樹中的任意屬性、調用Java對象樹的方法,并能夠自動實現必要的類型轉化。更形象地說,如果我們把OGNL表達式看做是一個帶有語義的字符串,那么OGNL無疑是這個語義字符串與Java對象之間溝通的橋梁。我們知道,在我們使用MVC架構模式進行開發Web應用時,數據往往需要在各層之間進行流轉。由于數據在不同層次中的表現形式不盡相同,所以這種流轉會很麻煩,特別是在Controller與View之間進行流轉。實際上,數據在Controller層與View層之間流轉的真正痛點就在于:數據在View層(視圖頁面)的表現形式是一個扁平的、不帶任何數據類型的字符串,而在Controller層(Java世界)完全可以表現為一個具有豐富數據結構和數據類型的Java對象,正是由于這種數據表現形式的差異,導致我們手工執行這種轉換將是一項非常復雜、低效的工作。正因為如此,為了更好地解決數據在不同層之間的數據流轉問題,作為一個優秀成熟的框架,Struts2集成了WebWork中的OGNL來幫助我們解決個問題。因此,當我們在使用Struts2時,會發現OGNL充斥在前后臺數據傳遞與存儲的方方面面,也給我們帶來了極大的方便。3、小結OGNL是模板語言的一個重要補充,對表現層技術而言是一次里程碑式的進步。在我們常見的視圖組件,包括Jsp2.0,Velocity,Jelly等,雖然都有類似的功能,比如,在Jsp2.0中我們可以使用其提供的EL表達式完成類似的功能。但是,OGNL比它們要完善的多得多,而且以一個獨立的庫文件出現,十分方便我們構建自己的框架。二.OGNL深度解讀:從一個例子說起我們在上文已經提到,OGNL以一個獨立的庫文件出現,十分方便我們構建自己的框架。那么,我們首先新建一個JavaProject,然后從Struts2的相關依賴包中導入ognl-x.x.xx.jar(本人使用的struts-2.1.6中的ognl-2.6.11.jar),搭建完畢后項目結構如下:J◎OGNL*4lr£電毋€n.tju.?duirico.test團匚plhtgH吋事¥■①Slwdentij-trvaiBiiJR£ library[Ja-wSE:7j■崟lR^ferenc-edLilprarie-s申 L:n鬥二慣凸zkiup總1、OGNL應用實例上述的JavaProject包含兩個JavaBean類和一個OGNL測試類,我們將圍繞這個Project展開對OGNL的介紹。我們先看一下該Project中各個類的源碼:.兩個JavaBeanpackage.rico.test;importjava.util.HashSet;importjava.util.Set;//JavaBean:StudentpublicclassStudent{privateCollegeCollege;privateStringname;privateStringgentle;privatedoubleheight;privateintage;//無參構造器publicStudent(){}publicStudent(Stringname,intage,doubleheight){super();=name;this.height=height;this.age=age;//getter&setterpublicCollegegetCollege(){returnCollege;}publicvoidsetCollege(CollegeCollege){this.College=College;}publicStringgetName(){returnname;}publicvoidsetName(Stringname){=name;}publicStringgetGentle(){returngentle;}publicvoidsetGentle(Stringgentle){this.gentle=gentle;}publicdoublegetHeight(){returnheight;}publicvoidsetHeight(doubleheight){this.height=height;}publicintgetAge(){returnage;}publicvoidsetAge(intage){this.age=age;@OverridepublicStringtoString(){return"Student[name="+name+",height="+height+",age="+age+"]";}}//JavaBean:CollegeclassCollege{privateStringname;privateSet<Student>Students=newHashSet<Student>();//無參構造器publicCollege(){}//getter&setterpublicStringgetName(){returnname;}publicvoidsetName(Stringname){=name;}publicSet<Student>getStudents(){returnStudents;}publicvoidsetStudents(Set<Student>Students){this.Students=Students;}}.OGNL測試類package.rico.test;importognl.Ognl;importognl.OgnlContext;importognl.OgnlException;publicclassOGNLTest{publicstaticvoidmain(String[]args)throwsOgnlException{//新建一個學校對象Collegecollege=newCollege();college.setName("TJU");//新建一個學生對象Studentstu=newStudent();stu.setName("Rico");//構建一個OgnlContext對象,并將上述學校、學生對象放入Ognl上下文環境(本質是一個Map)中OgnlContextcontext=newOgnlContext();context.put("college",college);context.put("stu",stu);//將學生設置為根對象context.setRoot(stu);//構建Ognl表達式的樹狀表示Objectexpression】=Ognl.parseExpression("#");Objectexpression2=Ognl.parseExpression("name");Objectexpression3=Ognl.parseExpression("#");//根據Ognl表達式給Java對象設置值,將TJU改為NEUOgnl.setValue(expression1,context,context.getRoot(),"NEU");//根據Ognl表達式獲取Java對象的(屬性)值ObjectcollegeName=Ognl.getValue(expression1,context,context.getRoot());ObjectstuName2=Ognl.getValue(expression2,context,context.getRoot());ObjectstuName3=Ognl.getValue(expression3,context,context.getRoot());System.out.println(collegeName);System.out.println(stuName2);System.out.println(stuName3);}}/*Output:
NEURicoRico*///:~上面的輸出結果對我們來說一點也不意外,因為在Struts2中,我們常常使用上述方式訪問StackContext(ActionContext)及其根對象ValueStack。根據這個例子我們也能夠看出,所謂的對象圖導航語言本質上就是通過類似”放置到OgnlContext中的名字?屬性名字”的方式去獲取對應對象的屬性值。特別的是,對于根對象的屬性的訪問,我們只需直接利用屬性名字訪問即可,因為根對象只有一個,OGNL會默認從OgnlContext中的根對象中去尋找;而對于普通對象的屬性的訪問,我們使用類似”#放置到OgnlContext中的名字?屬性名字”的方式去訪問,這時OGNL在解析表達式的時候發現表達式開頭帶有”#”,就會去普通對象中去尋找。當然,使用這種方式也可以訪問根對象的屬性,但是若在訪問普通對象時不加前綴“#”,將會拋出ognl.OgnlException。2、OGNL三要素卜-17^QE盹上下文是一個閘彳融它含有銀上I乂-對対氧具審就垃播口刖I龜対魚事實上,OGNL表達式的計算是圍繞OGNL上下文(OgnlContext)進行的,而OGNL上下文實際上就是一個Map對象。我們從上述的例子可以看出,無論是setValue方法還是getValue方法,它們均包含三個核心參數,即tree(OGNL表達式卜-17^QE盹上下文是一個閘彳融它含有銀上I乂-對対氧具審就垃播口刖I龜対魚OGML根對繚(1).表達式(Expression)表達式是整個OGNL的核心,所有的OGNL操作都是對表達式解析后進行的。準確的來說,表達式表達了此OGNL操作的語義,即表明了此OGNL操作“要干什么”。(2).上下文環境(Context)我們在上文提到,所有的OGNL操作都是在一個特定的環境中進行的,這個環境就是OGNL的上下文環境(OGNLContext)。更直白地說,OGNL上下文為OGNL表達式的提供了具體的運行環境。需要指出的是,我們完全可以像操作Map那樣將一些數據設置到OGNLContext中,以便我們通過OGNL訪問。準確的來說,Context為OGNL表達式提供了具體環境,為OGNL操作“提供支持”.根對象(RootObject)根對象是OGNLContext中的一員,并且整個OGNLContext最多只允許有一個根對象。也就是說,OGNLContext中共有兩類對象,即根對象和普通對象,它們的差異具體表現在訪問方式上,我們針對根對象的存取操作的表達式不需要增加任何前綴(下文會具體提到)。根對象從側面指明了OGNL操作所針對的對象類別,也就是說,在表達式規定了“干什么”之后,根對象指明了我們到底“對誰干”(根對象還是普通對象)。3、 OGNL源碼解讀在上述的例子中,無論是setValue方法還是getValue方法,都是ognl.Ognl類提供的兩個靜態方法。事實上,在OGNL中,我們最常用到的兩個類是ognl.Ognl與ognl.OgnlContext。ognl.Ognl類是一個抽象類,并提供了一系列用于解析和解釋執行Ognl表達式的方法,而抽象類則是專門用來繼承的;ognl.OgnlContext類則為Ognl表達式提供了一個執行環境,這個類實現了Map接口,所以允許我們通過使用Map的put(key,value)方法向OgnlContext添加各種類型的對象。需要注意的是,在OgnlContext中一共有兩種對象,第一種是根對象,根對象在整個OgnlContext中有且最多只能有一個,我們可以通過調用OgnlContext.setRoot(obj)設置根對象。另外一種就是普通對象,它的個數不受限制。它們最重要的一個區別是在對象屬性的獲取方式上,前者可直接訪問,后者需使用類似”#放置到OgnlContext中的名字.屬性名字”的方式去訪問。下面給出了ognl.Ognl與ognl.OgnlContext的聲明方式,關于它們更多的細節本文不在贅述,讀者若想進一步了解,請自行閱讀源碼。//Ognl是一個抽象類,而抽象類則是專門用來繼承的publicabstractclassOgnl{}//OgnlContext是一個MappublicclassOgnlContextextendsObjectimplementsMap{}4、 小結到此為止,我相信通過上面的例子和表述,我們對Ognl表達式有了一個更深入的了解和認識。此外,我們知道對于普通對象的屬性的訪問,我們只能使用類似”#放置到OgnlContext中的名字.屬性名字”的方式去訪問,而對于根對象的屬性的訪問,我們可以通過以下兩種方式去訪問:直接利用屬性名字訪問;類似”#放置到OgnlContext中的名字?屬性名字”的方式去訪問;下文我們將著重講述Ognl的基本用法,拋開MVC框架單獨了解它的用法便于我們進一步理解Ognl在Struts2中的使用方式。三?使用OGNL去訪問方法我們除了利用Ognl表達式訪問對象的屬性,還可以使用它來訪問方法。當然,對于方法的訪問,又可以分為對靜態方法的訪問、對實例方法的訪問和對構造方法的訪問,我們先看下面的例子:package.rico.test;importognl.Ognl;importognl.OgnlContext;importognl.OgnlException;publicclassOGNLTest2{publicstaticvoidmain(String[]args)throwsOgnlException{//新建一個學校對象Collegecollege=newCollege();college.setName("NEU");//新建一個學生對象Studentstu=newStudent();stu.setName("Livia");stu.setCollege(college);stu.setGentle("boy");//構建一個OgnlContext對象,并將上述學校和學生對象放入Ognl上下文環境中OgnlContextcontext=newOgnlContext();context.put("college",college);context.put("stu",stu);//將學生對象設置為根對象context.setRoot(stu);//訪問實例方法Objectexpression1=Ognl.parseExpression("getGentle()");Objectlength1=Ognl.getValue(expression1,context,context.getRoot());Objectexpression2=Ognl.parseExpression("#.length()");Objectlength2=Ognl.getValue(expression2,context,context.getRoot());System.out.println(length1);System.out.println(length2);//訪問靜態方法Objectexpression3=Ognl.parseExpression("@java.lang.Math@max(2,4)");Objectlength3=Ognl.getValue(expression3,context,context.getRoot());Objectexpression4=Ognl.parseExpression("@java.lang.String@valueOf(name.length())");Objectlength4=Ognl.getValue(expression4,context,context.getRoot());System.out.println(length3);System.out.println(length4);//訪問構造方法:通過Ognl表達式構建一個LinkedList對象,注意使用全類名Objectexpression5=Ognl.parseExpression("newjava.util.LinkedList()");Listlist=(List)Ognl.getValue(expression5,context,context.getRoot());list.add("list");list.add("rico");System.out.println(list);}}/*Output:boy345[list,rico]*///:~四.使用OGNL去訪問容器對象我們還可以利用Ognl表達式訪問容器對象,包括數組,List,Set,Map等,看下面的例子:package.rico.test;importjava.util.ArrayList;importjava.util.HashMap;importjava.util.List;importjava.util.Map;importognl.Ognl;importognl.OgnlContext;importognl.OgnlException;publicclassOGNLTest3{publicstaticvoidmain(String[]args)throwsOgnlException{OgnlContextcontext=newOgnlContext();//處理數組類型String[]strs=newString[]{"a","b","c"};context.put("strs",strs);System.out.println(Ognl.getValue("#strs[2]",context,context.getRoot()));//處理List類型List<String>words=newArrayList<String>();words.add("rico");words.add("livia");words.add("neu");context.put("words",words);System.out.println(Ognl.getValue("#words[0]",context,context.getRoot()));//處理Map類型Map<String,String>map=newHashMap<String,String>();map.put("ad","d");map.put("Rico","China");map.put("campus","neu");context.put("map",map);System.out.println(Ognl.getValue("#map['Rico']",context,context.getRoot()));//處理Set類型:由于Set的無序性,所以不能通過這種訪問Set(只能迭代輸出),會拋出ognl.NoSuchPropertyException;SetvString>set=newHashSetvString>();set.add("rico");set.add("livia");set.add("neu");context.put("set",set);System.out.println(Ognl.getValue("#set[2]",context,context.getRoot()));}/*Output:cricoChinaExceptioninthread"main"ognl.NoSuchPropertyException:java.util.HashSet.2*///:~由于Set是無序的且沒有索引,所以我們只能對其進行迭代輸出。Struts2提供了一組邏輯控制標簽,其中就有iterator,它可以完美完成這件事情。關于Struts2的邏輯控制標簽的敘述詳見本文的姊妹篇《再述OGNL:在Struts2中的應用》五.使用OGNL對容器進行操作我們還可以利用Ognl表達式對容器對象作一些操作,比如過濾和投影。過濾指的是將原集合中不符合條件的對象過濾掉,然后將滿足條件的對象,構建一個新的集合對象返回,Ognl過濾表達式的寫法是:collection.{?LI$expression};投影指的是將原集合中所有對象的某個屬性抽取出來,單獨構成一個新的集合對象返回,基礎語法為:collection.{expression}。特別需要注意的是,無論是過濾操作還是投影操作,它們的操作對象和操作結果都是一個容器。package.rico.test;importjava.util.ArrayList;importjava.util.Collections;importjava.util.List;importognl.Ognl;importognl.OgnlContext;importognl.OgnlException;publicclassOGNLTest4{publicstaticvoidmain(String[]args)throwsOgnlException{Students1=newStudent("Tom",22,170.3);Students2=newStudent("Jack",21,176.2);Students3=newStudent("Tomas",23,180.1);Students4=newStudent("Lucy",20,163.3);List<Student>stus=newArrayList<Student>();Collections.addAll(stus,s1,s2,s3,s4);//新建OgnlContext對象OgnlContextcontext=newOgnlContext();context.put("stus",stus);//過濾(filtering)‘collection」?expression}//利用過濾獲取身高在175以上的所有學生集合//輸出結果:[Student[name=Jack,age=21,height=176.2],Student[name=Tomas,age=23,height=180.1]]System.out.println(Ognl.getValue("#stus.{?#this.height> 175.0}",context,context.getR
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 江西科技學院附屬中學2025屆聯合模擬考試化學試題含解析
- 西藏昌都地區八宿縣2025屆初三三校聯考數學試題含解析
- 羽毛球場地租賃合同范文榜樣
- 江蘇省江陰市華士片、澄東片重點達標名校2025年初三年級下學期物理試題周末卷含附加題含解析
- 技術總監合同翻譯
- 事業單位勞動合同樣本
- 租賃合同與租賃訂單
- 江西省萍鄉市2024-2025學年七年級下學期期中生物學試題(含答案)
- 多功能會議室租賃合同
- 廚衛設備定制合同協議
- 2025年商丘職業技術學院單招職業技能考試題庫附答案
- 礦山地質環境保護與土地復墾方案報告正文
- IATF16949-應急計劃評審報告
- 輸血病人的個案護理
- 企業生產安全臺賬資料填寫模板
- 江蘇省淮安市2025屆高三上學期第一次調研測試化學
- 《照明培訓手冊》課件
- 智能傳感器銷售合同
- 臨床合理用藥指導
- 口腔科院感知識培訓課件
- 裝配式住宅建筑施工要點及質量管控措施
評論
0/150
提交評論