免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1897 | 回复: 0
打印 上一主题 下一主题

OGNL & ValueStack 入门 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-11-06 13:48 |只看该作者 |倒序浏览
h1. 一个例子
请看下面的需求,假设有如下用户对象模型:
Java代码

  • public interface User {   
  •     public String getName();   
  •     public Date getRegisterDate();   
  •     public Customer getCustomer();   
  • }   
  • public interface Customer {   
  •     public String getId();   
  •     public String getName();   
  •     public boolean isVip();   
  • }   
  • public interface EntCustomer extends Customer {   
  •     public String getTrustId(); // 组织机构代码证号   
  • }  public interface User {
        public String getName();
        public Date getRegisterDate();
        public Customer getCustomer();
    }
    public interface Customer {
        public String getId();
        public String getName();
        public boolean isVip();
    }
    public interface EntCustomer extends Customer {
        public String getTrustId(); // 组织机构代码证号
    }
    对于给定的用户jack,且该用户所属客户是企业客户,那么我们如何获取该用户的姓名?如何获取用户所属客户的名称?如何判断该用户所属客户是否是VIP客户?如何取jack所属企业的组织机构代码证号?
    * 采用java代码的方式,我们可以用如下的API调用得到所需信息:
    Java代码

  • jack.getName();   
  • jack.getCustomer().getName();   
  • jack.getCustomer().isVip();   
  • ((EntCustomer)jack.getCustomer()).getTrustId();  jack.getName();
    jack.getCustomer().getName();
    jack.getCustomer().isVip();
    ((EntCustomer)jack.getCustomer()).getTrustId();
    * 但我们现在在讲述OGNL,因此通过采用OGNL,我们可以用如下方式取得我们所需要的信息:
    Java代码

  • jack.name   
  • jack.customer.name   
  • jack.vip   
  • jack.customer.trustId  jack.name
    jack.customer.name
    jack.vip
    jack.customer.trustId
    由此我们可以看到OGNL的表达方式与java表达方式有以下几点不同:
    ** 不需关注对象类型,不需进行类型转换
    ** 表达方式更简短和直观
    OGNL表达式最大的优点就是:*简单* 和 *直观*,你不这样认为吗? 如果你觉得上面的表达式还不够简单和直观,那我们再来看:
    Java代码

  • name  name
    这也是一个OGNL表达式,也就是取姓名!简单吗?至少足够直观了吧:)
    h1. 基本概念
    我们前面看到了OGNL的一个最简单的例子,事实上OGNL确实很简单,如果能理解上面那个例子的用法,那么我们就掌握了OGNL的80%的用法了。
    上面的例子虽然简单,但其中却含有OGNL的两个最基本的概念:*表达式(expression)* 和 *上下文(context)*,我们先看*表达式*。
    h3. 表达式
    OGNL就是表达式!它能让我们用简洁直观的语法表达我们的想法,如同上面的例子一般。简洁直观就是表达式的最大优点!我们知道表达式总是有一个结果,也就是说表达式总是会求值出一个结果,这个结果可能是一个字符串(如名称、组织机构代码证号等),或者是一个布尔值(如是否是VIP客户等),至于这个结果要怎么使用,那就是我们自己来决定的了。
    h3. 上下文(context)
    表达式的概念,我相信很好理解,但什么是上下文(context)?简单来说上下文就是环境,表达式求值的环境!还是不理解吗?我们来看一个例子:
    还是上面最后那个例子:
    Java代码

  • name  name
    细心的你是否会问,这个表达式要取谁的姓名呢?OK,很好!这就是环境,"谁"就存在于环境之中,也就是存在上下文之中。对于不同的环境/上下文,相同的表达式会有不同的结果!而环境/上下文的实质是什么呢?就是一组带名称的对象集合。
    引用
    思考:表达环境或上下文这个概念的最好的数据结构是什么?
    h3. OGNL上下文概念详解
    我们前面说上下文就是一组名称-对象对的集合,如下图所示就是一个简单的上下文:
    Java代码

  • user ---> User(name:"jack", ...)   
  • request ---> HttpServletRequest(header: ...)  user ---> User(name:"jack", ...)
    request ---> HttpServletRequest(header: ...)
    那么在上面的环境中,我们可以有如下的OGNL表达式:
    Java代码

  • #user.name // 取用户的姓名   
  • #user.age // 取用户年龄   
  • #user.birthday // 取用户生日   
  • #user.customer.name // 取用户所属客户的名称   
  • #request.parameters // 取请求参数  #user.name // 取用户的姓名
    #user.age // 取用户年龄
    #user.birthday // 取用户生日
    #user.customer.name // 取用户所属客户的名称
    #request.parameters // 取请求参数
    请注意上面表达式中的"#user"和"#request"的用法,"#"表示访问环境/上下文中的对象。
    现在可以很方便地访问环境中的对象了,那么如果你比较懒惰的话(记住:在程序员群体,懒惰是褒义词!),你是否觉得访问用户的姓名,年龄,生日,等等其它属性如果全部要使用"#user"来访问会不会太麻烦了呢?OK,ONGL的设计者早就考虑了这个问题,我们可以指定user为环境中的特权对象,访问该对象可以不需要使用#user的方式,如下所示代码与上面的完全等价,当然,前提是要预先指定user为特权对象:
    Java代码

  • name // 取用户的姓名   
  • age // 取用户年龄   
  • birthday // 取用户生日   
  • customer.name // 取用户所属客户的名称   
  • #request.parameters // 取请求参数  name // 取用户的姓名
    age // 取用户年龄
    birthday // 取用户生日
    customer.name // 取用户所属客户的名称
    #request.parameters // 取请求参数
    我们上面所说的"特权对象"在OGNL中称为"根对象"(root)
    h3. 小结
    综上所述,理解OGNL表达式的关键是理解其上下文的概念,因为OGNL的上下文概念中引入了"根对象"的概念,所以初学者往往会在这里迷失方向。
    引用
    OGNL的中文全称是对象图导航语言,也就是说OGNL是一门语言,如同java是一门语言一样。你是否会认为OGNL的作者太夸张了,竟敢把表达式谎称为语言?不,OGNL的语法确实非常简洁,OGNL的代码(我没有说表达式,因为代码是和语法相匹配的词语)通常不会换行,这意味着我们不可能把OGNL的代码写得很长,但是,这并不意味着OGNL的表达能力很弱。事实上,OGNL的语法设计非常简洁,但其功能却相当强大,如果你有兴趣,可以深入阅读OGNL参考手册的集合与lambda章节。
    慢着,事情还未至此结束!struts2对OGNL中的上下文的概念又定义了新的含义,且听我慢慢道来!
    h3. struts2中的OGNL上下文
    struts2对OGNL上下文的概念又做了进一步扩充,在struts2中,OGNL上下文通常如下所示:
    Java代码

  • |   
  •                      |--request   
  •                      |   
  •                      |--application   
  •                      |   
  •        context map---|--OgnlValueStack(root) [ user, action, OgnlUtil, ... ]   
  •                      |   
  •                      |--session   
  •                      |   
  •                      |--attr   
  •                      |   
  •                      |--parameters  |
                         |--request
                         |
                         |--application
                         |
           context map---|--OgnlValueStack(root) [ user, action, OgnlUtil, ... ]
                         |
                         |--session
                         |
                         |--attr
                         |
                         |--parameters
    我们可以使用"#requet"访问HttpServletRequest对象, "#session"访问HttpSession对象,但请注意"根对象"是什么?是ValueStack!
    那么ValueStack是什么?值栈。也就是一组对象的堆栈。也就是说,在struts2中,根对象不是我们通常的一个对象,而是一组对象。我们可以push新的对象到值栈中,也可以弹出值栈的栈顶对象。如上图所示,假设我们将user对象push到值栈中,那么如下的表达式将与之前我们见过的表达式一样,具有相同的结果:
    Java代码

  • name // 取用户的姓名   
  • age // 取用户年龄   
  • birthday // 取用户生日   
  • customer.name // 取用户所属客户的名称   
  • #request.parameters // 取请求参数  name // 取用户的姓名
    age // 取用户年龄
    birthday // 取用户生日
    customer.name // 取用户所属客户的名称
    #request.parameters // 取请求参数
    也就是说,我们使用name这个表达式的时候,ONGL会取"根对象"的name属性,但现在根对象是ValueStack!那么访问ValueStack的name属性意味着什么呢?这意味着: ValueStack会先查看栈顶元素是否有name属性,如果有就返回该属性值,否则取出栈顶下的元素,继续查看,直到栈底为止。
    以上就是OGNL表达式的核心概念,你理解了吗?下一步,你需要了进一步了解OGNL的语法,以发掘其更强大的功能!

    关于#request的用法补充

    使用#request的值,可以使用struts2的标签库来实现,如下:
    首先:在页面中加入
    然后:通过的value属性进行显示;
    此行的作用是显示所有的request内容(包含默认的服务器信息),
    结果如下:
    {struts.view_uri=/showAll.jsp, struts.request_uri=/ch18/showAll.action, javax.servlet.forward.servlet_path=/showAll.action, javax.servlet.forward.context_path=/ch18, javax.servlet.forward.request_uri=/ch18/showAll.action, struts.valueStack=com.opensymphony.xwork2.util.OgnlValueStack@1cf8de2,
    all=[com.javaweb.po.Product@1b2cb9, com.javaweb.po.Product@154ec5, com.javaweb.po.Product@e67c12, com.javaweb.po.Product@1db8962, com.javaweb.po.Product@18a0a8, com.javaweb.po.Product@db81f3]}

    其中的all属性是程序调用中加入的,是个list对象而如果使用则将获取自己想要值信息,
    结果如下(显示传递了3个Product对象):
    [com.javaweb.po.Product@11b456f, com.javaweb.po.Product@16b7e0e, com.javaweb.po.Product@20d10a, com.javaweb.po.Product@7c15c0, com.javaweb.po.Product@7800e9, com.javaweb.po.Product@106bde8]

    通过上述中的#request.all或者#request,可方便的测试request的值是否传递到本页面。

    本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u1/35830/showart_2087870.html
  • 您需要登录后才可以回帖 登录 | 注册

    本版积分规则 发表回复

      

    北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
    未成年举报专区
    中国互联网协会会员  联系我们:huangweiwei@itpub.net
    感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

    清除 Cookies - ChinaUnix - Archiver - WAP - TOP