《研磨struts2》第七章 值栈和OGNL 之 7.3 使用OGNL访问复杂对象

7.3  使用OGNL访问复杂对象

7.3.1  访问域对象

通过ognl访问域对象,这件事情其实在好早以前,我们就已经做过了,只是那个时候不知道罢了,还是来示例一下。

(1)先来准备一个域对象,很简单,只有两个属性,代码示例如下:

 

java代码:
  1. package cn.javass.ognl.vo;  
  2. public class UserModel {  
  3.     private String userId;  
  4.     private String name;  
  5.     public String getUserId() {  
  6.         return userId;  
  7.     }  
  8.     public void setUserId(String userId) {  
  9.         this.userId = userId;  
  10.     }  
  11.     public String getName() {  
  12.         return name;  
  13.     }  
  14.     public void setName(String name) {  
  15.         this.name = name;  
  16.     }  
  17. }  

(2)写一个新的Action,定义一个UserModel类型的属性,并给出对应的getter/setter,然后在execute方法中对其进行赋值:

 

java代码:
  1. package cn.javass.ognl.action;  
  2.   
  3. import cn.javass.ognl.vo.UserModel;  
  4. import com.opensymphony.xwork2.ActionSupport;  
  5.   
  6. public class OgnlAction extends ActionSupport{  
  7.     private UserModel um = new UserModel();  
  8.     public UserModel getUm() {  
  9.         return um;  
  10.     }  
  11.     public void setUm(UserModel um) {  
  12.         this.um = um;  
  13.     }  
  14.       
  15.     public String execute(){  
  16.         System.out.println("您输入的用户编号="+um.getUserId());  
  17.         System.out.println("您输入的用户姓名="+um.getName());  
  18.         um.setUserId("在action中修改了UserId");  
  19.         um.setName("在action中修改了name");  
  20.         return this.SUCCESS;  
  21.     }  
  22. }  

(3)在struts.xml中的配置很简单,示例如下:

 

java代码:
  1. <action name="ognlAction" class="cn.javass.ognl.action.OgnlAction">  
  2.             <result>/ognl/result.jsp</result>  
  3.         </action>  

(4)作一个用户新增的页面,示例如下:

 

java代码:
  1. <form action="/helloworld/ognlAction.action" method="post">  
  2.     用户编号:<input type="text" name="um.userId"><br>  
  3.     用户姓名:<input type="text" name="um.name"><br>  
  4.     <input type="submit" value="提交">  
  5. </form>  

(5)然后制作一个结果页面,新增成功过后跳转到这个页面,示例如下:

 

java代码:
  1. <%@ taglib prefix="s" uri="/struts-tags"%>  
  2. 用户编号为: <s:property value="um.userId"/>  
  3. <br>  
  4. 用户姓名为: <s:property value="um.name"/>  

(6)运行测试一下看看,新增页面如下图所示:

《研磨struts2》第七章 值栈和OGNL 之 7.3 使用OGNL访问复杂对象

图7.4  新增页面

点击提交按钮过后,会跳转到结果页面,如下图所示:

 


《研磨struts2》第七章 值栈和OGNL 之 7.3 使用OGNL访问复杂对象

图7.5  新增后的结果页面

此时后台输出如下所示:

 

java代码:
  1. 您输入的用户编号=u1  
  2. 您输入的用户姓名=张三  

(7)小结

       在这里要强调两点:

  • getter/setter方法优先

什么意思呢?

就是说如果属性有对应的getter/setter方法,其实OGNL在对应的时候,是先对应getter/setter方法,如果getter/setter方法已经对应上了,那就不会对应属性了。

比如上例中的“um.userId”这个OGNL中的“um”,在访问的时候,并不是直接访问的OgnlAction中的um这个属性,而是先去对应getUm和setUm方法,只有getter/setter对应不上,才去访问属性,当然,直接访问属性的时候需要属性的访问权限为public。

来示范一下,先把Action中对应um的getter/setter方法修改一下,示例如下:

 

java代码:
  1. public class OgnlAction extends ActionSupport{  
  2.     private UserModel um = new UserModel();  
  3.   
  4.     public UserModel getUm1() {  
  5.         return um;  
  6.     }  
  7.     public void setUm1(UserModel um) {  
  8.         this.um = um;  
  9.     }  
  10.       
  11.     public String execute(){  
  12.         System.out.println("您输入的用户编号="+um.getUserId());  
  13.         System.out.println("您输入的用户姓名="+um.getName());  
  14.         um.setUserId("在action中修改了UserId");  
  15.         um.setName("在action中修改了name");  
  16.         return this.SUCCESS;  
  17.     }  
  18. }  

再去测试看看,会发现后台和结果页面都没有能够取到值,为什么呢?

       因为优先对应getter/setter方法,我们在新增页面里面写的是“um.userId”,也就是优先对应getUm和setUm方法,由于我们把方法名称改掉了,对应不上,那么就去对应属性,可是,um属性是私有的,也对应不到,于是就没有能跟这个OGNL表达式对应的东西,所以值也就为null了。

       把新增页面中的“um.userId”改为“um1.userId”,“um.name”改为“um1.name”,同理去修改结果页面的表达式,再次运行测试,会发现后台和结果页面都能够取到值了。

  • 私有属性 vs 公有属性。

在前面的例子中使用了私有属性um,及其对应的getter/setter,其实也可以直接定义一个public的属性,但是请注意,声明公有属性的时候,必须在声明的时候直接初始化,否则会报错,如:

 

java代码:
  1. public UserModel um = new UserModel();  

其实两种写法是等价的。

7.3.2  访问List或数组

通过ognl访问数组或List的时候,只需要指明索引即可访问数组或List中的指定元素。

(1)首先,来修改一下OgnlAction,声明一个List类型的属性及其getter/setter,并在execute方法中对其设置值,示例代码如下:

 

java代码:
  1. package cn.javass.ognl.action;  
  2. import java.util.ArrayList;  
  3. import java.util.List;  
  4. import cn.javass.ognl.vo.UserModel;  
  5. import com.opensymphony.xwork2.ActionSupport;  
  6.   
  7. public class OgnlAction extends ActionSupport{  
  8.     private List<UserModel> umList = new ArrayList<UserModel>();  
  9.     public List<UserModel> getUmList() {  
  10.         return umList;  
  11.     }  
  12.     public void setUmList(List<UserModel> umList) {  
  13.         this.umList = umList;  
  14.     }     
  15.       
  16.     public String execute(){  
  17.         System.out.println("您输入的用户编号="+umList.get(0).getUserId());  
  18.         System.out.println("您输入的用户姓名="+umList.get(0).getName());  
  19.         UserModel um = new UserModel();  
  20.         um.setUserId("在action中修改了UserId");  
  21.         um.setName("在action中修改了name");  
  22.           
  23.         umList.add(um);  
  24.         return this.SUCCESS;  
  25.     }     
  26. }  

(2)这时候,Action中有一个名为umList属性,在外界引用的时候,需要用索引来引用。比如新增页面,修改示例如下:

 

java代码:
  1. <form action="/helloworld/ognlAction.action" method="post">  
  2.     用户编号:<input type="text" name="umList[0].userId"><br>  
  3.     用户姓名:<input type="text" name="umList[0].name"><br>  
  4.     <input type="submit" value="提交">  
  5. </form>  

(3)而结果页面也需要做相应的修改,示例如下:

 

java代码:
  1. <%@ taglib prefix="s" uri="/struts-tags"%>  
  2. 用户编号为: <s:property value="umList[0].userId"/>  
  3. <br>  
  4. 用户姓名为: <s:property value="umList[0].name"/>  

(4)去运行测试看看,后台或者结果页面都应该能够正确获取值。

(5)把List类型换成数组类型,访问方式和写法基本类似。但是要注意一个问题,就是换成数组类型过后,必须在OGNL访问之前要初始化索引所对应的对象,最简单的方法就是在定义的时候直接初始化,示例如下:

 

java代码:
  1. public class OgnlAction extends ActionSupport{  
  2.     private UserModel[] umList = {new UserModel(),new UserModel()};  
  3.     public UserModel[] getUmList() {  
  4.         return umList;  
  5.     }  
  6.     public void setUmList(UserModel[] umList) {  
  7.         this.umList = umList;  
  8.     }     
  9.       
  10.     public String execute(){  
  11.         System.out.println("您输入的用户编号="+umList[0].getUserId());  
  12.         System.out.println("您输入的用户姓名="+umList[0].getName());  
  13.         UserModel um = new UserModel();  
  14.         um.setUserId("在action中修改了UserId");  
  15.         um.setName("在action中修改了name");  
  16.           
  17.         umList[0] = um;  
  18.         return this.SUCCESS;  
  19.     }  
  20. }  

如果没有在OGNL访问前进行初始化,那么会报出“NullPointerException”的例外。

(6)还可以访问数组的length属性,也可以访问集合的方法,比如:

  • OGNL表达式为:array.length,就表示访问array这个数组的length属性
  • OGNL表达式为:list.size,就表示访问list这个集合的size()方法
  • OGNL表达式为:list.isEmpty,就表示访问list这个集合的isEmpty()方法

(7)直接在OGNL中构建集合,比如:

  • OGNL表达式为:{1,2,3},就表示构建一个包含3个值的集合,值分别是1,2,3
  • OGNL表达式为:{1,2,3}[0],就表示构建一个包含3个值的集合,值分别是1,2,3 ,然后获取索引为0的值,也就是1了。

7.3.3  访问Map

通过ognl访问Map的时候,通常的格式为“Map名称[‘键的名称’]”,当然也可以用“Map名称.键的名称”的方式来访问Map中的值,但建议使用前面一种方式。

(1)对OgnlAction稍作修改来示范,声明一个Map类型的属性及其getter/setter,并在execute方法中对其初始化:

 

java代码:
  1. public class OgnlAction extends ActionSupport{  
  2.     private Map<String,UserModel> userMap = new HashMap<String,UserModel>();  
  3.     public Map<String, UserModel> getUserMap() {  
  4.         return userMap;  
  5.     }  
  6.     public void setUserMap(Map<String, UserModel> userMap) {  
  7.         this.userMap = userMap;  
  8.     }  
  9.       
  10.     public String execute(){  
  11.         System.out.println("您输入的用户编号="+userMap.get("umtest").getUserId());  
  12.         System.out.println("您输入的用户姓名="+userMap.get("umtest").getName());  
  13.         UserModel um = new UserModel();  
  14.         um.setUserId("在action中修改了UserId");  
  15.         um.setName("在action中修改了name");  
  16.           
  17.         userMap.put("umtest",um);  
  18.         return this.SUCCESS;  
  19.     }  
  20. }  

(2)修改新增页面的OGNL表达式,示例如下:

 

java代码:
  1. <form action="/helloworld/ognlAction.action" method="post">  
  2.     用户编号:<input type="text" name="userMap['umtest'].userId"><br>  
  3.     用户姓名:<input type="text" name="userMap['umtest'].name"><br>  
  4.     <input type="submit" value="提交">  
  5. </form>  

(3)修改结果页面的OGNL表达式,示例如下:

 

java代码:
  1. <%@ taglib prefix="s" uri="/struts-tags"%>  
  2. 用户编号为: <s:property value="userMap['umtest'].userId"/>  
  3. <br>  
  4. 用户姓名为: <s:property value="userMap['umtest'].name"/>  

(4)去运行测试看看,结果页面和后台应该都能正确地获取到值了。

(5)还可以访问Map的方法,比如:

  • OGNL表达式为:map.size,就表示访问map这个Map的size()方法
  • OGNL表达式为:map.isEmpty,就表示访问map这个Map的isEmpty()方法

(6)也可以直接在OGNL中构建Map,比如:

  • OGNL表达式为:#{'one':'aa','two':'bb'},就表示构建一个包含2组值的Map,key值分别是one和two,对应的值分别是aa和bb
  • OGNL表达式为:#{'one':'aa','two':'bb'}['one'],就表示构建一个包含2组值的Map,key值分别是one和two,对应的值分别是aa和bb,然后获取key为one的值,也就是aa了。

7.3.4  组合使用

通过前面的讲述,你可以发现,OGNL可以访问不同的对象、属性和方法,那么可不可以把这些复杂的对象结构组合起来,让OGNL去访问呢?

假如在Session中,有一个List作为Session的属性,对应的key值是“users”,List里面放的全是UserModel类型的对象,现在要访问其中的第3个元素的userId属性,应该怎样用OGNL去访问呢?

       回答这个问题需要层层分解,一步一步来:

  • 要获取Session中一个key值为“users”的List,对应的OGNL应为#session[‘users’],或者#session.users
  • 要操作这个List的第3个元素,对应的OGNL应为#session[‘users’][2],或者#session.users[2]
  • 要操作这个对象的userId属性,对应的OGNL应为#session[‘users’][2].userId,或者#session.users[2].userId

这样,就得到了最终的OGNL,可以去测试一下,看看好用不。

       OGNL本身有很多的知识,这里只是介绍了OGNL中最常用的知识,更多的知识可以去http://www.ognl.org查看,那里有很详细的文档。

 

私塾在线网站原创《研磨struts2》系列

转自请注明出处:【http://sishuok.com/forum/blogPost/list/0/4070.html

欢迎访问http://sishuok.com获取更多内容