《研磨struts2》第七章 值栈跟OGNL 之 7.3 使用OGNL访问复杂对象
7.3 使用OGNL访问复杂对象
7.3.1 访问域对象
通过ognl访问域对象,这件事情其实在好早以前,我们就已经做过了,只是那个时候不知道罢了,还是来示例一下。
(1)先来准备一个域对象,很简单,只有两个属性,代码示例如下:
- package cn.javass.ognl.vo;
- public class UserModel {
- private String userId;
- private String name;
- public String getUserId() {
- return userId;
- }
- public void setUserId(String userId) {
- this.userId = userId;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- }
(2)写一个新的Action,定义一个UserModel类型的属性,并给出对应的getter/setter,然后在execute方法中对其进行赋值:
- package cn.javass.ognl.action;
- import cn.javass.ognl.vo.UserModel;
- import com.opensymphony.xwork2.ActionSupport;
- public class OgnlAction extends ActionSupport{
- private UserModel um = new UserModel();
- public UserModel getUm() {
- return um;
- }
- public void setUm(UserModel um) {
- this.um = um;
- }
- public String execute(){
- System.out.println("您输入的用户编号="+um.getUserId());
- System.out.println("您输入的用户姓名="+um.getName());
- um.setUserId("在action中修改了UserId");
- um.setName("在action中修改了name");
- return this.SUCCESS;
- }
- }
(3)在struts.xml中的配置很简单,示例如下:
- <action name="ognlAction" class="cn.javass.ognl.action.OgnlAction">
- <result>/ognl/result.jsp</result>
- </action>
(4)作一个用户新增的页面,示例如下:
- <form action="/helloworld/ognlAction.action" method="post">
- 用户编号:<input type="text" name="um.userId"><br>
- 用户姓名:<input type="text" name="um.name"><br>
- <input type="submit" value="提交">
- </form>
(5)然后制作一个结果页面,新增成功过后跳转到这个页面,示例如下:
- <%@ taglib prefix="s" uri="/struts-tags"%>
- 用户编号为: <s:property value="um.userId"/>
- <br>
- 用户姓名为: <s:property value="um.name"/>
(6)运行测试一下看看,新增页面如下图所示:
图7.4 新增页面
点击提交按钮过后,会跳转到结果页面,如下图所示:
图7.5 新增后的结果页面
此时后台输出如下所示:
- 您输入的用户编号=u1
- 您输入的用户姓名=张三
(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方法修改一下,示例如下:
- public class OgnlAction extends ActionSupport{
- private UserModel um = new UserModel();
- public UserModel getUm1() {
- return um;
- }
- public void setUm1(UserModel um) {
- this.um = um;
- }
- public String execute(){
- System.out.println("您输入的用户编号="+um.getUserId());
- System.out.println("您输入的用户姓名="+um.getName());
- um.setUserId("在action中修改了UserId");
- um.setName("在action中修改了name");
- return this.SUCCESS;
- }
- }
再去测试看看,会发现后台和结果页面都没有能够取到值,为什么呢?
因为优先对应getter/setter方法,我们在新增页面里面写的是“um.userId”,也就是优先对应getUm和setUm方法,由于我们把方法名称改掉了,对应不上,那么就去对应属性,可是,um属性是私有的,也对应不到,于是就没有能跟这个OGNL表达式对应的东西,所以值也就为null了。
把新增页面中的“um.userId”改为“um1.userId”,“um.name”改为“um1.name”,同理去修改结果页面的表达式,再次运行测试,会发现后台和结果页面都能够取到值了。
- 私有属性 vs 公有属性。
在前面的例子中使用了私有属性um,及其对应的getter/setter,其实也可以直接定义一个public的属性,但是请注意,声明公有属性的时候,必须在声明的时候直接初始化,否则会报错,如:
- public UserModel um = new UserModel();
其实两种写法是等价的。
7.3.2 访问List或数组
通过ognl访问数组或List的时候,只需要指明索引即可访问数组或List中的指定元素。
(1)首先,来修改一下OgnlAction,声明一个List类型的属性及其getter/setter,并在execute方法中对其设置值,示例代码如下:
- package cn.javass.ognl.action;
- import java.util.ArrayList;
- import java.util.List;
- import cn.javass.ognl.vo.UserModel;
- import com.opensymphony.xwork2.ActionSupport;
- public class OgnlAction extends ActionSupport{
- private List<UserModel> umList = new ArrayList<UserModel>();
- public List<UserModel> getUmList() {
- return umList;
- }
- public void setUmList(List<UserModel> umList) {
- this.umList = umList;
- }
- public String execute(){
- System.out.println("您输入的用户编号="+umList.get(0).getUserId());
- System.out.println("您输入的用户姓名="+umList.get(0).getName());
- UserModel um = new UserModel();
- um.setUserId("在action中修改了UserId");
- um.setName("在action中修改了name");
- umList.add(um);
- return this.SUCCESS;
- }
- }
(2)这时候,Action中有一个名为umList属性,在外界引用的时候,需要用索引来引用。比如新增页面,修改示例如下:
- <form action="/helloworld/ognlAction.action" method="post">
- 用户编号:<input type="text" name="umList[0].userId"><br>
- 用户姓名:<input type="text" name="umList[0].name"><br>
- <input type="submit" value="提交">
- </form>
(3)而结果页面也需要做相应的修改,示例如下:
- <%@ taglib prefix="s" uri="/struts-tags"%>
- 用户编号为: <s:property value="umList[0].userId"/>
- <br>
- 用户姓名为: <s:property value="umList[0].name"/>
(4)去运行测试看看,后台或者结果页面都应该能够正确获取值。
(5)把List类型换成数组类型,访问方式和写法基本类似。但是要注意一个问题,就是换成数组类型过后,必须在OGNL访问之前要初始化索引所对应的对象,最简单的方法就是在定义的时候直接初始化,示例如下:
- public class OgnlAction extends ActionSupport{
- private UserModel[] umList = {new UserModel(),new UserModel()};
- public UserModel[] getUmList() {
- return umList;
- }
- public void setUmList(UserModel[] umList) {
- this.umList = umList;
- }
- public String execute(){
- System.out.println("您输入的用户编号="+umList[0].getUserId());
- System.out.println("您输入的用户姓名="+umList[0].getName());
- UserModel um = new UserModel();
- um.setUserId("在action中修改了UserId");
- um.setName("在action中修改了name");
- umList[0] = um;
- return this.SUCCESS;
- }
- }
如果没有在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方法中对其初始化:
- public class OgnlAction extends ActionSupport{
- private Map<String,UserModel> userMap = new HashMap<String,UserModel>();
- public Map<String, UserModel> getUserMap() {
- return userMap;
- }
- public void setUserMap(Map<String, UserModel> userMap) {
- this.userMap = userMap;
- }
- public String execute(){
- System.out.println("您输入的用户编号="+userMap.get("umtest").getUserId());
- System.out.println("您输入的用户姓名="+userMap.get("umtest").getName());
- UserModel um = new UserModel();
- um.setUserId("在action中修改了UserId");
- um.setName("在action中修改了name");
- userMap.put("umtest",um);
- return this.SUCCESS;
- }
- }
(2)修改新增页面的OGNL表达式,示例如下:
- <form action="/helloworld/ognlAction.action" method="post">
- 用户编号:<input type="text" name="userMap['umtest'].userId"><br>
- 用户姓名:<input type="text" name="userMap['umtest'].name"><br>
- <input type="submit" value="提交">
- </form>
(3)修改结果页面的OGNL表达式,示例如下:
- <%@ taglib prefix="s" uri="/struts-tags"%>
- 用户编号为: <s:property value="userMap['umtest'].userId"/>
- <br>
- 用户姓名为: <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获取更多内容