`
allwefantasy
  • 浏览: 46993 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Struts2 与 OGNL ( 投影 过滤 ) 以及pojo依赖注入的方法

阅读更多
   ORM(这里我们以hibernate为例子)的对象关联使得对象之间的导航变得十分清晰与明了。对开发员而言,感觉到的是优雅与实用。
    想下通过Orm的关联,我们不用再和sql打交道(这个也不一定,我的看法是绝不勉强用哪一个,哪一个合适,就用哪一个),
    我们可以相当的方便拿到与之相关的对象。当然取出来的数据还是要显示在页面上给用户看的。这里便是Ognl显神通的地方了。
    Ognl是个脚本语言,弱类型,可以运行时判断对象类型。和Struts2标签结合相当不错。之前 javaeye有个struts2系列教程,作者对Ognl的介绍就很不错。有空大家可以看看。
    今天我们研究一个案例。
    有个站内信类,我们叫它Message,如下:
   public class Message implements java.io.Serializable
	{

		// Fields

		private Integer id;
		private User user;//收件人
		private Integer fromId;//发信人Id
		}


由于信件Message和User类有两个关联,但是当时设计的话只是用了一次一对多关联,发信人则直接使用其Id,这就丧失了导航的优势
但我在页面显示相关信息的时候 比如我想显示发件人的头像 headIcon,姓名等,但Message并没有这个字段,同时也无法通过 getUser()之类的导航来得到,,也就是我们必须通过显示连接查询获得fromId对象。
       于是我想到了另外一个解决方案
也就是在页面通过Message中的fromId取得会员对象,通过加载的User对象取得headIcon.
这时我写了一个新的类,我们称之为PageHelper 代码如下:
package com.snail.commons.util;
import org.apache.log4j.Logger;
import com.snail.commons.basedao.IBaseDAO;

public class PageHelper 
{
	private IBaseDAO baseDAO;//一个负责持久层的对象
	public PageHelper(IBaseDAO baseDAO)
	{
		this.baseDAO=baseDAO;
	}
	private final static Logger logger=Logger.getLogger(PageHelper.class);
	/*
	clz:String 类的全名(包括包名,例如import com.snail.commons.beans.User)
	id :integer 需要加载的id
	*/
	public  Object loadEntity(String clz,Integer id)
	{
		Class temClz=null;
		try {
			 temClz=Class.forName(clz);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		Object obj=baseDAO.findEntity(temClz, id);
		return obj;
	}
	}

通过这个类,我们就能动态加载需要的类,并且取得相应的持久化对象。
我们看下在页面如何调用:
	<s:property value="(new com.snail.commons.util.PageHelper(baseDAO)).loadEntity('com.snail.component.beans.User',fromId).headPic"/>


      我们首先实例化PageHelper类,需要注意的是,在Ognl表达式中,必须使用全类名,接着直接调用其方法。
       当然也可以将loadEntity定义为静态方法,相应的,你应该改成
<s:property value="@com.snail.commons.util.PageHelper@loadEntity('com.snail.component.beans.User',fromId).headPic"/>

当然对于上面的案例来说,我们可以通过构造方法传入baseDAO对象(第一种调用方法),也可以通过(参数传递baseDAO,不过这里的例子没有体现)我这里只是作为Ognl静态方法调用的一个示例。
(个人感觉上面的方案破坏了MVC的封层,这相当于数据库经过Service层直接到了展示层。同事效率也大了折扣,假设我要显示一百条信息,必须调用一百次Sql操作才能取出
相应的User对象。有点像n+1问题);
Rails 里面有个ApplicationHelper 帮助程序,我觉得很好,加强了页面的表现能力,我们可以在页面调用ApplicationHelper中的任何公开方法,比如实现一些截取规定长度字符等功能,当然在struts中我们可以通过标签实现,或者通过已有标签组合实现类似功能,不过都比较麻烦,哪有调用一个静态方法来得爽?
   ognl就为我们提供了类似于ApplicationHelper 的实用类。
比如我们可以新建一个类假设叫PageHelper:里面有个静态方法==》
public static String substring(String str,List params)
			{
				
				 if(params.size()==1)
					 {
						 Integer end=(Integer)params.get(0);
					     return str.substring(0,end<=str.length()?end:str.length());
					 }
				 else if(params.size()==2)
					 {
						 Integer start=(Integer)params.get(0);
						 Integer end=(Integer)params.get(1);
						  return str.substring(start,end<=str.length()?end:str.length() );
					 }
				 return str;
			}


然后我们可以直接在页面上调用
<s:property value="@com.snail.commons.util.PageHelper@sustring('abc',{})"/>

    这样便实现了字符截取功能。另外上面代码中的"{}",代表新建的一个List对象,很简洁吧,恩 ognl具有很多动态语言的特性。
另外我很想知道的是,如何在一个普通的Pojo类中拿到spring的bean,而且该类是我们自己直接实例化的。如果哪位大大知道的话,不妨告知一声。([color=orange]后来才理清头绪,如果解决了这个问题,也就解决了富领域模型的问题。
关于富领域模型问题,javaeye讨论了很多,到hibernate模块有很多精华好贴。我这里不讨论其优劣,只是提几句实现的方案:
第一种:
ps:也是最好的方案
在spring2.0之后,已经通过aspectj支持静态织入持久化工具类,我这里不展开,大家可以参看spring文档(或许我会另起一文详细说说步骤),不过唯一不爽的是要个什么
设置 javaagent=aspectj jar包路径
第二种:
ps:比较繁琐,但对于新新项目也是比较保险,可控性高一点的
在pojo类设置一个set方法,每次使用该pojo之前,给它set一个持久化工具类,之后pojo类里面的方法就具有了持久化功能,或者严格点,给每个Pojo类用到持久化工具类的方法全部以持久化工具类为其中之一的参数
第三种:
ps:很有技巧性
不管你pojo是谁产生的,你的静态成员总是所有实例共享的吧,我如果给你的静态成员设置上持久化工具类,那所有的pojo实例都可以共享吧。
这种实现方案有两个:
no1 :通过spring拦截pojo在加载时的静态方法,赋值。这样省事,不过
no2 :有三个类,A, B,C, A用spring加载,实现ApplicatioContextAware接口,注入context.类B有一个静态域,该静态域通过set属性注入。这个可能不是很好理解,我们举个例子,
@Component
public class B
{
  private static ApplicationContext context;

 
  @Autowired(required = true)
  public void setUserAccessor(A a) {
    B.context = a.context;
  }
}


这样应该容易理解一些
接着在C类中我们可以直接使用B中的静态域,很棒是吧
这样我们就可以将很多东东注入到不归spring管理的的自己实例化的类里面去了。
再次ps:我个人最喜欢这个方案最简洁
第四种:
ps:hibernate自己的解决方案
可以参看https://www.hibernate.org/182.html
这种方案就是通过hibernate拦截器在加载pojo类的时候注入。

当然还有很去哦其他的方案,大家可以google一下。

[/color])

Ognl的另外一个比较重要的用法是投影与过滤。网上好像讲的比较少。我在这里提一下。
第一个示例是 如何迭代一个数字,最简单的比如分页,我的pageSize=7,如何迭代出七个Option呢,如下。
<select>
	<s:iterator value="pageSize.{#this}" status="sta">
  <option> <s:property value="#sta.index+1"/></option>
	</s:iterator>
	</select>


上面有个重点: pageSize.{#this} 这是个过滤操作,得到的是一个集合。this指当前正在迭代的对象。前面的#不用说了,是ognl本省语法需要的。

       假设我想迭代出大于3的几个数字,
这个时候可以这样pageSize.{#this>3}
      
结合ongl的过滤与投影操作,可以使得页面也有强大的逻辑操作以及过滤功能。
我们在看一个稍微复杂一点的例子:
        三个类
       Gequ(歌曲) ,Gequzhuanji(歌曲专辑),Gequgequzhuanji(歌曲歌曲专辑 中间表)。
Gequ=> Gequgequzhuanji 一对多关系
Gequzhuanji=> Gequgequzhuanji 一对多关系
现在我拿到了一个Gequgequzhuanji的集合,对这个集合我想显示出拥有者为master的专辑的名称,而且只要第一个。
下面的代码可以实现:
  <s:property value="gequgequzhuanjis.{^#this.gequzhuanji.huiyuan.name eq  'master')}[0].zhuanJiMing" default="单曲"/>

我们来解释一下:
显然gequgequzhuanjis.{}是一个过滤操作。过滤得到的也是一个集合,这个结合需要[n]操作拿到某个元素,最终通过.拿到起属性值。
就这么简单


恩 不知道讲清楚了。大家可以再参考下ognl的官方文档。个人觉得Ognl是个强大的脚本语言。支持常用的一些操作符,比如基本类型使用==等,对象比较可以使用
eq 之类的。在传统的MVC结构中,V层有点瘦客户端的感觉,有时也可以让他胖起来!(*^__^*) 嘻嘻……
分享到:
评论
1 楼 wenxiang_tune 2011-01-20  
给力!这文章好,不过我想知道Map<String,List<xxx>> 中如果投影的话怎么判断xxx中的值,怎么写?因为我要在每次循环之前就判断一下xxx中的某个属性是否。。。

相关推荐

    struts2中的OGNL的源码

    6. **安全机制**:为了防止OGNL注入攻击,Struts2提供了安全配置,限制可以访问的对象和属性。 源码阅读可以帮助我们了解OGNL的工作原理,如如何解析表达式,如何找到正确的ValueResolver,以及如何处理上下文中的...

    Struts2 使用OGNL表达式

    7. **表达式过滤器**:为了安全考虑,Struts2允许配置OGNL表达式过滤器,防止潜在的OGNL注入攻击。 8. **异常处理**:当OGNL表达式无法解析时,Struts2会抛出相应的异常,如`ValueExpressionException`,帮助开发者...

    struts2_OGNL Demo

    Struts2_OGNL Demo 是一个用于演示Struts2框架中OGNL(Object-Graph Navigation Language)表达式语言的实例。这个项目旨在帮助开发者理解和学习如何在Struts2中使用OGNL来操纵对象和数据。OGNL是Struts2中一个重要的...

    Struts2_OGNL

    OGNL(Object-Graph Navigation Language)是Struts2框架中的一个重要组件,用于在Web应用中访问和操作Java对象的属性,调用其方法,以及执行类型转换等操作。 OGNL是对象图导航语言的缩写,它是一种功能强大的...

    很全面的struts2_ognl总结

    在 Struts2 中,OGNL 是一个强大的工具,允许开发者访问和操作 ValueStack 中的对象的属性和方法。 一、访问 ValueStack 中的对象属性 在 Struts2 中,可以使用 OGNL 来访问 ValueStack 中的对象属性,例如: ...

    struts2 中 OGNL表达式的使用

    struts2 中 OGNL表达式的使用struts2 中 OGNL表达式的使用

    struts2 ognl用法项目

    在Struts2中,OGNL用于处理动作类的属性到JSP页面的传递,以及用户输入到动作类的绑定。 首先,让我们了解OGNL的基本语法。OGNL表达式通常包含两个部分:对象引用和属性访问。例如,`user.name`表示获取名为`user`...

    Struts2核心包ognl-2的源代码

    5. **安全特性**:在Struts2中,OGNL的不当使用可能导致安全漏洞,如著名的Struts2 OGNL注入攻击。源代码中包含了对这种风险的防护措施,如输入过滤和安全配置选项。 深入学习这些源代码,开发者不仅可以了解OGNL的...

    Struts2之Ognl详解案例TextOgnl

    因此,在实际应用中,应确保对用户输入进行严格的校验和过滤,或者使用Struts2的安全插件来防止OGNL注入。 五、总结 OGNL在Struts2中扮演着关键角色,它简化了数据绑定和对象交互。然而,开发者也需要注意其潜在的...

    struts2 标签 OGNL

    在Struts2中,OGNL被广泛用于访问Action中的属性,以及在视图层(如JSP)中绑定和操作数据。 首先,OGNL使得访问对象属性变得非常直观。它支持点符号(.)和方括号([''])两种方式来访问属性。例如,如果在Action...

    struts2对Ognl的封装--PropertyAccessor

    - Struts2中OGNL与Action、ValueStack的关系。 - OGNL的安全性问题,如OGNL注入攻击,以及如何防范。 在压缩包文件`struts-ognl.asta`中,可能包含了一些示例或测试用例,用于演示Struts2中PropertyAccessor的使用...

    Struts2 & OGNL

    在这个主题中,我们将深入探讨Struts2与OGNL的整合以及它们在实际开发中的应用。 **Struts2框架概述** Struts2是Apache软件基金会的开源项目,它是Struts1的升级版,提供了更多的特性和灵活性。Struts2的核心设计...

    struts2 ognl的用法

    4. **与Struts2的集成**:OGNL可以无缝集成到Struts2的Action、拦截器等组件中。 5. **动态性**:OGNL表达式可以在运行时动态解析。 #### 二、OGNL在Struts2中的使用方式 OGNL在Struts2中主要用于页面显示数据、...

    STRUTS2+ognl

    本文将详细介绍Struts2、Webwork以及Ognl的相关知识点,并提供入门指导。 **Struts2框架** Struts2是在原有的Struts1基础上发展起来的,它整合了Webwork框架的优势,提供了更灵活的控制流和更强大的拦截器机制。...

    struts2-OGNL表达式测试

    Struts2是一个流行的Java Web应用程序框架,它极大地简化了MVC(模型-视图-控制器)架构的实现。...在学习过程中,记得关注OGNL表达式的语法、安全问题(如防止OGNL注入攻击)以及性能优化等方面的知识。

    Struts2 ognl

    Struts2 OGNL(Object-Graph Navigation Language)是一种强大的表达式语言,它在Struts2框架中扮演着核心角色,用于数据绑定、控制流程以及动态方法调用。这篇博文可能详细介绍了Struts2框架中OGNL的使用、工作原理...

    struts2对Ognl的封装--TypeConverter

    这篇博客文章"Struts2对Ognl的封装--TypeConverter"探讨了Struts2如何通过TypeConverter机制来增强OGNL的功能。 首先,我们来看一下OGNL。OGNL允许开发者用简洁的语法来获取和设置对象的属性,甚至可以进行复杂的...

    struts2_ognl实验代码

    这篇文档将深入探讨在Struts2中使用OGNL表达式的实验代码,以及其相关知识点。 首先,了解OGNL的基本概念至关重要。OGNL允许我们直接通过字符串表达式来访问和修改对象的属性。例如,如果我们有一个用户对象`user`...

Global site tag (gtag.js) - Google Analytics