




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
與MVC框架解耦的OGNL:前世今生
及其基本用法一.OGNL概述1、 OGNL的前世今生WebWork是建立在稱為XWork的Command模式框架之上的強(qiáng)大的基于Web的MVC框架。關(guān)于WebWork我們大多數(shù)人可能不太熟悉,最多只是有一種在哪里見過的感覺,但是我一提Struts2,估計(jì)大家就能想起來了。眾所周知,Struts2是Struts的下一代產(chǎn)品,是在Strutsl和WebWork的技術(shù)基礎(chǔ)上進(jìn)行了合并的全新框架。需要特別注意的是,全新的Struts2的體系結(jié)構(gòu)與Strutsl差別巨大,因?yàn)镾truts2是以WebWork為核心的,繼承了更多的WebWork血統(tǒng)。實(shí)際上,WebWork已經(jīng)完全從Web層脫離出來的一個(gè)非常優(yōu)秀的框架,其提供了很多核心的、Struts2還在使用的功能,包括前端攔截器(interceptor)、運(yùn)行時(shí)表單屬性驗(yàn)證、類型轉(zhuǎn)換、IoC(InversionofControl)容器等,其中就有我們今天的主角,強(qiáng)大的表達(dá)式語言——OGNL(ObjectGraphNotationLanguage)。2、 OGNL帶給我們的實(shí)惠OGNL是ObjectGraphNavigationLanguage的縮寫,全稱為對(duì)象圖導(dǎo)航語言,是一種功能強(qiáng)大的表達(dá)式語言。它通過簡單一致的語法,可以存取Java對(duì)象樹中的任意屬性、調(diào)用Java對(duì)象樹的方法,并能夠自動(dòng)實(shí)現(xiàn)必要的類型轉(zhuǎn)化。更形象地說,如果我們把OGNL表達(dá)式看做是一個(gè)帶有語義的字符串,那么OGNL無疑是這個(gè)語義字符串與Java對(duì)象之間溝通的橋梁。我們知道,在我們使用MVC架構(gòu)模式進(jìn)行開發(fā)Web應(yīng)用時(shí),數(shù)據(jù)往往需要在各層之間進(jìn)行流轉(zhuǎn)。由于數(shù)據(jù)在不同層次中的表現(xiàn)形式不盡相同,所以這種流轉(zhuǎn)會(huì)很麻煩,特別是在Controller與View之間進(jìn)行流轉(zhuǎn)。實(shí)際上,數(shù)據(jù)在Controller層與View層之間流轉(zhuǎn)的真正痛點(diǎn)就在于:數(shù)據(jù)在View層(視圖頁面)的表現(xiàn)形式是一個(gè)扁平的、不帶任何數(shù)據(jù)類型的字符串,而在Controller層(Java世界)完全可以表現(xiàn)為一個(gè)具有豐富數(shù)據(jù)結(jié)構(gòu)和數(shù)據(jù)類型的Java對(duì)象,正是由于這種數(shù)據(jù)表現(xiàn)形式的差異,導(dǎo)致我們手工執(zhí)行這種轉(zhuǎn)換將是一項(xiàng)非常復(fù)雜、低效的工作。正因?yàn)槿绱耍瑸榱烁玫亟鉀Q數(shù)據(jù)在不同層之間的數(shù)據(jù)流轉(zhuǎn)問題,作為一個(gè)優(yōu)秀成熟的框架,Struts2集成了WebWork中的OGNL來幫助我們解決個(gè)問題。因此,當(dāng)我們?cè)谑褂肧truts2時(shí),會(huì)發(fā)現(xiàn)OGNL充斥在前后臺(tái)數(shù)據(jù)傳遞與存儲(chǔ)的方方面面,也給我們帶來了極大的方便。3、小結(jié)OGNL是模板語言的一個(gè)重要補(bǔ)充,對(duì)表現(xiàn)層技術(shù)而言是一次里程碑式的進(jìn)步。在我們常見的視圖組件,包括Jsp2.0,Velocity,Jelly等,雖然都有類似的功能,比如,在Jsp2.0中我們可以使用其提供的EL表達(dá)式完成類似的功能。但是,OGNL比它們要完善的多得多,而且以一個(gè)獨(dú)立的庫文件出現(xiàn),十分方便我們構(gòu)建自己的框架。二.OGNL深度解讀:從一個(gè)例子說起我們?cè)谏衔囊呀?jīng)提到,OGNL以一個(gè)獨(dú)立的庫文件出現(xiàn),十分方便我們構(gòu)建自己的框架。那么,我們首先新建一個(gè)JavaProject,然后從Struts2的相關(guān)依賴包中導(dǎo)入ognl-x.x.xx.jar(本人使用的struts-2.1.6中的ognl-2.6.11.jar),搭建完畢后項(xiàng)目結(jié)構(gòu)如下:J◎OGNL*4lr£電毋€n.tju.?duirico.test團(tuán)匚plhtgH吋事¥■①Slwdentij-trvaiBiiJR£ library[Ja-wSE:7j■崟lR^ferenc-edLilprarie-s申 L:n鬥二慣凸zkiup總1、OGNL應(yīng)用實(shí)例上述的JavaProject包含兩個(gè)JavaBean類和一個(gè)OGNL測(cè)試類,我們將圍繞這個(gè)Project展開對(duì)OGNL的介紹。我們先看一下該P(yáng)roject中各個(gè)類的源碼:.兩個(gè)JavaBeanpackage.rico.test;importjava.util.HashSet;importjava.util.Set;//JavaBean:StudentpublicclassStudent{privateCollegeCollege;privateStringname;privateStringgentle;privatedoubleheight;privateintage;//無參構(gòu)造器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>();//無參構(gòu)造器publicCollege(){}//getter&setterpublicStringgetName(){returnname;}publicvoidsetName(Stringname){=name;}publicSet<Student>getStudents(){returnStudents;}publicvoidsetStudents(Set<Student>Students){this.Students=Students;}}.OGNL測(cè)試類package.rico.test;importognl.Ognl;importognl.OgnlContext;importognl.OgnlException;publicclassOGNLTest{publicstaticvoidmain(String[]args)throwsOgnlException{//新建一個(gè)學(xué)校對(duì)象Collegecollege=newCollege();college.setName("TJU");//新建一個(gè)學(xué)生對(duì)象Studentstu=newStudent();stu.setName("Rico");//構(gòu)建一個(gè)OgnlContext對(duì)象,并將上述學(xué)校、學(xué)生對(duì)象放入Ognl上下文環(huán)境(本質(zhì)是一個(gè)Map)中OgnlContextcontext=newOgnlContext();context.put("college",college);context.put("stu",stu);//將學(xué)生設(shè)置為根對(duì)象context.setRoot(stu);//構(gòu)建Ognl表達(dá)式的樹狀表示Objectexpression】=Ognl.parseExpression("#");Objectexpression2=Ognl.parseExpression("name");Objectexpression3=Ognl.parseExpression("#");//根據(jù)Ognl表達(dá)式給Java對(duì)象設(shè)置值,將TJU改為NEUOgnl.setValue(expression1,context,context.getRoot(),"NEU");//根據(jù)Ognl表達(dá)式獲取Java對(duì)象的(屬性)值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*///:~上面的輸出結(jié)果對(duì)我們來說一點(diǎn)也不意外,因?yàn)樵赟truts2中,我們常常使用上述方式訪問StackContext(ActionContext)及其根對(duì)象ValueStack。根據(jù)這個(gè)例子我們也能夠看出,所謂的對(duì)象圖導(dǎo)航語言本質(zhì)上就是通過類似”放置到OgnlContext中的名字?屬性名字”的方式去獲取對(duì)應(yīng)對(duì)象的屬性值。特別的是,對(duì)于根對(duì)象的屬性的訪問,我們只需直接利用屬性名字訪問即可,因?yàn)楦鶎?duì)象只有一個(gè),OGNL會(huì)默認(rèn)從OgnlContext中的根對(duì)象中去尋找;而對(duì)于普通對(duì)象的屬性的訪問,我們使用類似”#放置到OgnlContext中的名字?屬性名字”的方式去訪問,這時(shí)OGNL在解析表達(dá)式的時(shí)候發(fā)現(xiàn)表達(dá)式開頭帶有”#”,就會(huì)去普通對(duì)象中去尋找。當(dāng)然,使用這種方式也可以訪問根對(duì)象的屬性,但是若在訪問普通對(duì)象時(shí)不加前綴“#”,將會(huì)拋出ognl.OgnlException。2、OGNL三要素卜-17^QE盹上下文是一個(gè)閘彳融它含有銀上I乂-對(duì)対氧具審就垃播口刖I龜対魚事實(shí)上,OGNL表達(dá)式的計(jì)算是圍繞OGNL上下文(OgnlContext)進(jìn)行的,而OGNL上下文實(shí)際上就是一個(gè)Map對(duì)象。我們從上述的例子可以看出,無論是setValue方法還是getValue方法,它們均包含三個(gè)核心參數(shù),即tree(OGNL表達(dá)式卜-17^QE盹上下文是一個(gè)閘彳融它含有銀上I乂-對(duì)対氧具審就垃播口刖I龜対魚OGML根對(duì)繚(1).表達(dá)式(Expression)表達(dá)式是整個(gè)OGNL的核心,所有的OGNL操作都是對(duì)表達(dá)式解析后進(jìn)行的。準(zhǔn)確的來說,表達(dá)式表達(dá)了此OGNL操作的語義,即表明了此OGNL操作“要干什么”。(2).上下文環(huán)境(Context)我們?cè)谏衔奶岬?,所有的OGNL操作都是在一個(gè)特定的環(huán)境中進(jìn)行的,這個(gè)環(huán)境就是OGNL的上下文環(huán)境(OGNLContext)。更直白地說,OGNL上下文為OGNL表達(dá)式的提供了具體的運(yùn)行環(huán)境。需要指出的是,我們完全可以像操作Map那樣將一些數(shù)據(jù)設(shè)置到OGNLContext中,以便我們通過OGNL訪問。準(zhǔn)確的來說,Context為OGNL表達(dá)式提供了具體環(huán)境,為OGNL操作“提供支持”.根對(duì)象(RootObject)根對(duì)象是OGNLContext中的一員,并且整個(gè)OGNLContext最多只允許有一個(gè)根對(duì)象。也就是說,OGNLContext中共有兩類對(duì)象,即根對(duì)象和普通對(duì)象,它們的差異具體表現(xiàn)在訪問方式上,我們針對(duì)根對(duì)象的存取操作的表達(dá)式不需要增加任何前綴(下文會(huì)具體提到)。根對(duì)象從側(cè)面指明了OGNL操作所針對(duì)的對(duì)象類別,也就是說,在表達(dá)式規(guī)定了“干什么”之后,根對(duì)象指明了我們到底“對(duì)誰干”(根對(duì)象還是普通對(duì)象)。3、 OGNL源碼解讀在上述的例子中,無論是setValue方法還是getValue方法,都是ognl.Ognl類提供的兩個(gè)靜態(tài)方法。事實(shí)上,在OGNL中,我們最常用到的兩個(gè)類是ognl.Ognl與ognl.OgnlContext。ognl.Ognl類是一個(gè)抽象類,并提供了一系列用于解析和解釋執(zhí)行Ognl表達(dá)式的方法,而抽象類則是專門用來繼承的;ognl.OgnlContext類則為Ognl表達(dá)式提供了一個(gè)執(zhí)行環(huán)境,這個(gè)類實(shí)現(xiàn)了Map接口,所以允許我們通過使用Map的put(key,value)方法向OgnlContext添加各種類型的對(duì)象。需要注意的是,在OgnlContext中一共有兩種對(duì)象,第一種是根對(duì)象,根對(duì)象在整個(gè)OgnlContext中有且最多只能有一個(gè),我們可以通過調(diào)用OgnlContext.setRoot(obj)設(shè)置根對(duì)象。另外一種就是普通對(duì)象,它的個(gè)數(shù)不受限制。它們最重要的一個(gè)區(qū)別是在對(duì)象屬性的獲取方式上,前者可直接訪問,后者需使用類似”#放置到OgnlContext中的名字.屬性名字”的方式去訪問。下面給出了ognl.Ognl與ognl.OgnlContext的聲明方式,關(guān)于它們更多的細(xì)節(jié)本文不在贅述,讀者若想進(jìn)一步了解,請(qǐng)自行閱讀源碼。//Ognl是一個(gè)抽象類,而抽象類則是專門用來繼承的publicabstractclassOgnl{}//OgnlContext是一個(gè)MappublicclassOgnlContextextendsObjectimplementsMap{}4、 小結(jié)到此為止,我相信通過上面的例子和表述,我們對(duì)Ognl表達(dá)式有了一個(gè)更深入的了解和認(rèn)識(shí)。此外,我們知道對(duì)于普通對(duì)象的屬性的訪問,我們只能使用類似”#放置到OgnlContext中的名字.屬性名字”的方式去訪問,而對(duì)于根對(duì)象的屬性的訪問,我們可以通過以下兩種方式去訪問:直接利用屬性名字訪問;類似”#放置到OgnlContext中的名字?屬性名字”的方式去訪問;下文我們將著重講述Ognl的基本用法,拋開MVC框架單獨(dú)了解它的用法便于我們進(jìn)一步理解Ognl在Struts2中的使用方式。三?使用OGNL去訪問方法我們除了利用Ognl表達(dá)式訪問對(duì)象的屬性,還可以使用它來訪問方法。當(dāng)然,對(duì)于方法的訪問,又可以分為對(duì)靜態(tài)方法的訪問、對(duì)實(shí)例方法的訪問和對(duì)構(gòu)造方法的訪問,我們先看下面的例子:package.rico.test;importognl.Ognl;importognl.OgnlContext;importognl.OgnlException;publicclassOGNLTest2{publicstaticvoidmain(String[]args)throwsOgnlException{//新建一個(gè)學(xué)校對(duì)象Collegecollege=newCollege();college.setName("NEU");//新建一個(gè)學(xué)生對(duì)象Studentstu=newStudent();stu.setName("Livia");stu.setCollege(college);stu.setGentle("boy");//構(gòu)建一個(gè)OgnlContext對(duì)象,并將上述學(xué)校和學(xué)生對(duì)象放入Ognl上下文環(huán)境中OgnlContextcontext=newOgnlContext();context.put("college",college);context.put("stu",stu);//將學(xué)生對(duì)象設(shè)置為根對(duì)象context.setRoot(stu);//訪問實(shí)例方法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);//訪問靜態(tài)方法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);//訪問構(gòu)造方法:通過Ognl表達(dá)式構(gòu)建一個(gè)LinkedList對(duì)象,注意使用全類名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去訪問容器對(duì)象我們還可以利用Ognl表達(dá)式訪問容器對(duì)象,包括數(shù)組,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();//處理數(shù)組類型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(只能迭代輸出),會(huì)拋出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是無序的且沒有索引,所以我們只能對(duì)其進(jìn)行迭代輸出。Struts2提供了一組邏輯控制標(biāo)簽,其中就有iterator,它可以完美完成這件事情。關(guān)于Struts2的邏輯控制標(biāo)簽的敘述詳見本文的姊妹篇《再述OGNL:在Struts2中的應(yīng)用》五.使用OGNL對(duì)容器進(jìn)行操作我們還可以利用Ognl表達(dá)式對(duì)容器對(duì)象作一些操作,比如過濾和投影。過濾指的是將原集合中不符合條件的對(duì)象過濾掉,然后將滿足條件的對(duì)象,構(gòu)建一個(gè)新的集合對(duì)象返回,Ognl過濾表達(dá)式的寫法是:collection.{?LI$expression};投影指的是將原集合中所有對(duì)象的某個(gè)屬性抽取出來,單獨(dú)構(gòu)成一個(gè)新的集合對(duì)象返回,基礎(chǔ)語法為:collection.{expression}。特別需要注意的是,無論是過濾操作還是投影操作,它們的操作對(duì)象和操作結(jié)果都是一個(gè)容器。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對(duì)象OgnlContextcontext=newOgnlContext();context.put("stus",stus);//過濾(filtering)‘collection」?expression}//利用過濾獲取身高在175以上的所有學(xué)生集合//輸出結(jié)果:[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等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025至2030年中國青蘋果味醬行業(yè)投資前景及策略咨詢報(bào)告
- 2024年新干縣公辦區(qū)域性養(yǎng)老服務(wù)中心招聘真題
- 炸雞店的餐廳布局設(shè)計(jì)
- 國潮風(fēng)下的春節(jié)童趣世界
- 元旦的卡通插畫淡藍(lán)色的童年回憶
- 老年癡呆癥的護(hù)理與管理
- 制作個(gè)性動(dòng)漫妝 展現(xiàn)自我獨(dú)特風(fēng)格
- 2025年13年租期租賃違約金賠償合同樣本
- 護(hù)理中的急性疾病護(hù)理
- 2025至2030中國數(shù)字金融行業(yè)發(fā)展分析及競爭格局及有效策略與實(shí)施路徑評(píng)估報(bào)告
- 2025年安徽省高考物理試卷真題(含答案解析)
- 整套企業(yè)人事管理制度
- 大學(xué)學(xué)院輔導(dǎo)員工作考核基本指標(biāo)
- 中國鐵路濟(jì)南局集團(tuán)招聘筆試題庫2025
- 公司活動(dòng)中心管理制度
- 2025年江蘇省蘇州市太倉市英語八年級(jí)第二學(xué)期期末復(fù)習(xí)檢測(cè)試題含答案
- 2025南京市房屋買賣合同
- 2025年云南省中考數(shù)學(xué)-26題二次函數(shù)降次冪題35道
- 2025屆中考地理全真模擬卷 【江蘇專用】(含解析)
- 2025年河北省中考乾坤押題卷數(shù)學(xué)試卷A及答案
- 2025年煙臺(tái)市初中地理學(xué)業(yè)水平考試試題及答案
評(píng)論
0/150
提交評(píng)論