在這一切的背后,是因為有了ValueStack(值棧)! 2. ValueStack基礎:OGNL
要了解ValueStack,必須先理解OGNL(Object Graphic Navigatino Language)!
OGNL是Struts2中使用的一種表達式語言,它可以:
①用于jsp的標簽庫中,以便能夠方便的訪問各種對象的屬性;
②用于界面將參數傳遞到Action(并進行類型轉換)中;
③用于struts2的配置文件中!
所以,非常有必要理解OGNL的基本機制。 2.1 Root對象
OGNL稱為對象圖導航語言。所謂對象圖,即以任意一個對象為根,通過OGNL可以訪問與這個對象關聯的其它對象。如: [+]view code
package cn.com.leadfar.struts2.actions;
publicclass User { PRivate String username; private Group group; public String getUsername() { returnusername; } publicvoid setUsername(String username) { this.username = username; } public Group getGroup() { returngroup; } publicvoid setGroup(Group group) { this.group = group; }} [+]view codepackage cn.com.leadfar.struts2.actions;
publicclass Group { private String name; private Organization org; public String getName() { returnname; } publicvoid setName(String name) { this.name = name; } public Organization getOrg() { returnorg; } publicvoid setOrg(Organization org) { this.org = org; }} [+]view codepackage cn.com.leadfar.struts2.actions;
publicclass Organization { private String orgId; public String getOrgId() { returnorgId; } publicvoid setOrgId(String orgId) { this.orgId = orgId; }}上面三個類,描述了通過一個User對象,可以導航到Group對象,進而導航到Organization對象,以User對象為根,一個對象圖如下所示:
User(root)
-- username
-- group
-- name
-- org
-- orgId
在真實的環境下,這個對象圖可能會極其復雜,但是通過基本的getters方法,都應該能夠訪問到某個對象的其它關聯對象。【對象圖的導航,必須通過getters方法進行導航】
下述代碼將創建一個User對象,及其相關的一系列對象: [+]view code
User user = new User();
Group g = new Group(); Organization o = new Organization(); o.setOrgId("ORGID"); g.setOrg(o);user.setGroup(g);如果通過java代碼來進行導航(依賴于getters方法),導航到Organization的orgId屬性,如下所示:
//用JAVA來導航訪問
user.getGroup().getOrg().getOrgId();
【注意:導航的目的,是為了獲取某個對象的值或設置某個對象的值或調用某個對象的方法!】
【注意:OGNL表達式語言的真正目的,是為了在那些不能寫JAVA代碼的地方執行JAVA代碼,或者是為了更方便地執行JAVA代碼】
利用OGNL進行導航的代碼如下: [+]view code
//利用OGNL表達式訪問
String value = (String)Ognl.getValue("group.org.orgId", user);Ognl.getValue()方法:
第一個參數,就是一條OGNL表達式;
第二個參數是指定在表達式中需要用到的root對象!
完整代碼如下: [+]view code
publicvoid testOgnl01() throws Exception{
User user = new User(); user.setUsername("張三"); //利用OGNL表達式訪問user對象的username屬性 String value = (String)Ognl.getValue("username", user); log(value); } publicvoid 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來導航訪問 log(user.getGroup().getOrg().getOrgId()); //利用OGNL表達式訪問 String value = (String)Ognl.getValue("group.org.orgId", user); log(value); } publicvoid 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來導航訪問 log(user.getGroup().getOrg().getOrgId()); //也可以在表達式中使用#root來代表root對象 String value = (String)Ognl.getValue("#root.group.org.orgId", user); log(value); } privatevoid log(Object o){ System.out.println(o);} 2.2 Context對象在OGNL的表達式中,有可能需要訪問到多個毫不相干的對象,這時候,我們需要給OGNL傳遞一個Map類型的對象,把表達式中需要用到的對象放到Map中即可!這個Map對象,稱為context。
要在表達式中訪問到context中的對象,需要使用“#對象名稱”的語法規則。如: [+]view code
publicvoid 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來把這些對象統一傳遞給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); } publicvoid 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對象,以便解釋對應的表達式 String value = (String)Ognl.getValue("#u1.username + ',' + #u2.username + ',' + username", context,user3); log(value);} 2.3 利用OGNL表達式進行賦值OGNL表達式也可以用于賦值操作:
[+]view codepublicvoid testOgnl06() throws Exception{
User user = new User(); //調用setValue()方法來進行賦值 //第一個參數:OGNL表達式 //第二個參數:root對象 //第三個參數:要賦的值 Ognl.setValue("username", user, "張三"); log(user.getUsername()); } publicvoid testOgnl07() throws Exception{ User user = new User(); Map context = new HashMap(); context.put("u", user); //調用setValue()方法來進行賦值 //第一個參數:OGNL表達式 //第二個參數:context對象 //第三個參數:root對象 //第四個參數:要賦的值 Ognl.setValue("#u.username", context, new Object(),"張三"); log(user.getUsername()); } publicvoid 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()); } publicvoid testOgnl09() throws Exception{ User user1 = new User(); User user2 = new User(); Map context = new HashMap(); context.put("u1", user1); context.put("u2", user2); //在一個表達式中可以用逗號分隔,同時執行多個表達式 Ognl.getValue("#u1.username = '李四',#u2.username='王五'", context, new Object()); log(user1.getUsername()); log(user2.getUsername()); } 2.4 利用OGNL調用對象的方法 [+]view code//************************* OGNL調用對象的方法 *****************************//
publicvoid testOgnl10() throws Exception{ User user = new User(); //如果是調用root對象的方法,可以直接使用方法的名稱來調用方法 Integer value = (Integer)Ognl.getValue("addSomething(1,1)", user); log(value); } publicvoid testOgnl11() throws Exception{ User user = new User(); user.setUsername("李四"); //如果是調用root對象的方法,可以直接使用方法的名稱來調用方法 String value = (String)Ognl.getValue("getUsername()", user); log(value); } publicvoid testOgnl12() throws Exception{ User user = new User(); Ognl.getValue("setUsername('王五')", user); String value = (String)Ognl.getValue("getUsername()", user); log(value); } //************************* OGNL調用靜態方法和變量 *********************// publicvoid testOgnl13() throws Exception{ User user = new User(); user.setUsername("王五"); //調用靜態變量 //注意:out是System中的靜態變量,out是PrintStream類型的一個對象 //而println()則是out這個對象中的實例方法(不是靜態方法) //調用靜態方法,需要在類名和變量名前面加上@來調用,對于實例方法,用"."來調用 Ognl.getValue("@System@out.println(username)", user); } publicvoid testOgnl14() throws Exception{ User user = new User(); user.setUsername("wangwu"); //調用靜態方法,注意使用全路徑類名 Ognl.getValue("@System@out.println(@cn.com.leadfar.utils.Utils@toUpperCase(username))", user); } 2.5 利用OGNL訪問數組、集合對象 [+]view codepublicvoid testOgnl15() throws Exception{
Object root = new Object(); Map context = new HashMap(); //利用OGNL創建java.util.List對象 List list = (List)Ognl.getValue("{123,'xxx','kdjfk'}", context, root); context.put("list", list); //利用OGNL創建數組 int[] intarray = (int[])Ognl.getValue("new int[]{23,45,67}", context, root); context.put("intarray", intarray); //利用OGNL表達式創建java.util.Map對象 Map mapvalue = (Map)Ognl.getValue("#{'listvalue':#list,'intvalue':#intarray}", context, root); context.put("mapvalue", mapvalue); //利用OGNL表達式訪問這些數組和集合對象 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); } publicvoid 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));} 2.7 更多的特性,請參考官方的文檔OGNL官方文檔地址:http://www.opensymphony.com/ognl/html/LanguageGuide/index.html
3. 應用:ValueStack理解ValueStack的基本機制!對各種現象作出解釋。
ValueStack實際上就是對OGNL的封裝,OGNL主要的功能就是賦值與取值,Struts2正是通過ValueStack來進行賦值與取值的!
ValueStack是一個接口,而OgnlValueStack是strtus2中的缺省實現。ValueStack中的數據,分兩個部分存放:root和context(這與OGNL中的概念一致),同時ValueStack暴露相關的接口:
void setValue(String expr, Object value);
Object findValue(String expr);
用來通過OGNL表達式對ValueStack中的數據進行操作!
ValueStack中的root對象是CompoundRoot,CompoundRoot繼承了ArraryList,提供了額外的方法:push()和pop()方法,用來對root對象中所包含的數據進行存取! [+]view code
publicclass CompoundRoot extends ArrayList {
public CompoundRoot() { } public CompoundRoot(List list) { super(list); } public CompoundRoot cutStack(int index) { returnnew CompoundRoot(subList(index, size())); } public Object peek() { return get(0); } public Object pop() { return remove(0); }新聞熱點
疑難解答