论坛首页 Java企业应用论坛

java利用反射机制完成所有hibernate的模糊、非模糊查询。可以按条件查询

浏览 8736 次
精华帖 (0) :: 良好帖 (2) :: 新手帖 (1) :: 隐藏帖 (0)
作者 正文
   发表时间:2011-11-10  
利用反射机制完成所有hibernate的模糊、非模糊查询。可以按条件查询

有的时候我们会遇到这样的情况,比如图书馆有很多本书,这时候我们要按照书名查询,按照类别查询,按照作者查询,或者按照ISBN查询,并且有可能一次按照多个条件查询,这时候通常会需要如下的hql或者sql语句。

① from Book b

where b.bookName=”红楼梦“ and b.bookAuthor=”施耐庵” ……

② Select * from tb_book b where

b.bookName=”红楼梦“ and b.bookAuthor=”施耐庵” ……

并且在写servlet或者使用struts写action的时候需要针对不同的查询调用不同的DAO层,因此往往servlet或者dao需要写多个类似处理代码,他们几乎相同。

其实针对查询这些信息的时候我们完全可以利用反射机制来自动生成一条hql或者sql语句执行,不需要每次都写出新的语句,这样既不利于维护,也不利于开发。

我的设想就是,不管是否使用ORM框架,都需要有实体类对应数据库的表,而这些实体类的属性就对应了表的字段。

我们如果能利用一个实体类来进行针对自身不为null的属性生成hql或者sql语句,那么就可以利用一个查询的dao完成所有类型的查询了。

下面给出我写的hqlModel,这个类是一个用来生成查询语句的。

此类的中心思想就是自动生成查询语句,只要给定一个Object类型,就可以“自动”根据类的属性调用getter方法来获取值。如果值不为空,就按照该值来进行条件查询,如果没有任何属性被赋值,那么他将认为要生成form Book 这样的查询语句。

这样不管是查询所有数据,查询指定数据,多条件查询指定数据,都可以用同一个方法来执行。

至于模糊或者非模糊,只要给定一个boolean,然后判断就可以了。这样用setter作为其是否开启模糊查询的开关。

package com.leaves.daoUtil;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * 此类用来创建hql查询语句,能自动生成如下格式hql语句。<br>
 * from BookInfo where bookNameId='null' and bookName='《三国演义》' and
 * bookAuthor='施耐庵' ;<br>
 * 使用getHql()方法来创建hql语句,此方法调用会抛出异常。<br>
 * 此类需要你为其提供一个带有get和set方法的bean,类会根据其get的方法获得其值,如果get属性不为null则添加where条件。<br>
 * 如果没有设置任何方法,则默认生成from BookInfo形式HQL语句。
 * 
 * @version 1.0.0.0
 * @author leaves叶知泉,<a href="http://www.c5ms.com">官方网站www.c5ms.com</a>
 * 
 */
public class HqlModel {

	private Object object;

	/**
	 * 是否开启模糊查询
	 */
	private boolean likeSel;

	public boolean isLikeSel() {
		return likeSel;
	}

	/**
	 * 设置属性是否开启模糊查询
	 * 
	 * @param likeSel
	 */
	public void setLikeSel(boolean likeSel) {
		this.likeSel = likeSel;
	}

	public Object getObject() {
		return object;
	}

	public void setObject(Object object) {
		this.object = object;
	}

	/**
	 * 允许不带参数实例化
	 */
	private HqlModel() {
	}

	/**
	 * 使用指定的对象来获取一个HqlModel实例
	 * 
	 * @param object
	 *            实例化时所需要的DTO对象
	 */
	public static HqlModel newInstanceByObj(Object object) {
		HqlModel hqlModel = new HqlModel();
		hqlModel.setObject(object);
		return hqlModel;
	}

	/**
	 * 用来进行创建hql语句的方法, 此方法可能抛出异常
	 * 
	 * @return 根据传入对象的get方法构建的hql语句
	 */
	public String getHql() throws Exception {
		// 预准备好的hql语句。
		StringBuffer sbf = new StringBuffer("from Object where ");
		// 得道给定实例的类型。
		Class<?> theClass = this.getObject().getClass();
		// 使用类名替换Object字符串。
		sbf.replace(5, 11, theClass.getSimpleName());
		// 活的该类所有属性。
		Field[] fields = object.getClass().getDeclaredFields();

		// 遍历所有属性
		for (Field field : fields) {
			PropertyDescriptor pd = new PropertyDescriptor(field.getName(),
					theClass);
			// 获得所有属性的读取方法
			Method getMethod = pd.getReadMethod();
			// 执行读取方法,获得属性值
			Object objTemp = getMethod.invoke(object);
			// 如果属性值为null,就略过
			if (objTemp == null) {
				continue;
			}
			// 如果不为空。
			// 判断是否开启模糊查询,添加查询条件,并且加上%%符号。
			if (isLikeSel()) {
				sbf.append(field.getName() + " like '%" + objTemp + "%'");
				sbf.append(" and ");
			}//同理添加查询条件,不添加%%符号。
			else {
				sbf.append(field.getName() + "='" + objTemp + "'");
				sbf.append(" and ");
			}
		}
		//最后一个属性设置完成之后取出残余的and和尾部的空格。
		if (sbf.toString().endsWith("and ")) {
			sbf.delete(sbf.length() - "and".length() - 1, sbf.length());
		}
		//如果没有设置任何属性,则取出尾部的where字符串和后面的空格。
		if (sbf.toString().endsWith("where ")) {
			sbf.delete(sbf.length() - "where".length() - 1, sbf.length());
		}
		//返回生成好的语句。
		return sbf.toString();
	}

}









目前属于1.0版本,还不支持sql语句生成,其实都是一个道理,只要在类中修改 StringBuffer sbf = new StringBuffer(“from Object where ”);这一句就能完成。

希望朋友们修改出更好的生成器之后能跟小弟一起分享,多多指教。

此类不足之处:

·没有sql、hql切换的开关

·理论上还可以生成update和save这样的语句,只是小弟还没有想到设计。
   发表时间:2011-11-10  
这个貌似很有想法,标记下,继续look中
0 请登录后投票
   发表时间:2011-11-11  
  private boolean likeSel; 
 

不够细化,应该分字段是否使用like 还是=
0 请登录后投票
   发表时间:2011-11-11  
都用了hibernate还不用 Criteria

DetachedCriteria dc = DetachedCriteria.forClass(Xxx.class);
if(title!=null && !title.trim().equals("")){
  dc.add(Restrictions.ilike("title", title,MatchMode.ANYWHERE));
}
return getHibernateTemplate().findByCriteria(dc);
0 请登录后投票
   发表时间:2011-11-11  
这样的精神是不错的,不过似乎思路和代码的完整性不够。
0 请登录后投票
   发表时间:2011-11-11  
是可以自己写个save,  update , saveOrUpdate 方法

我已经这么做很久了。

楼主你没考虑实际应用中的组合查询和模糊查询配合使用的情况
0 请登录后投票
   发表时间:2011-11-11  
去看看asm,cglib!反射的效率太低啦!
0 请登录后投票
   发表时间:2011-11-12  
吃饱了~~
0 请登录后投票
   发表时间:2011-11-12  
LIKE的时候没考虑escape

比如,某个用户输入“90%”,他要到是百分之九十,而不是901,902
0 请登录后投票
   发表时间:2011-11-29  
反射效率低,楼主也没有考虑多个对象的组合查询
还有楼上说的escape 问题

现有的Criteria应该能实现
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics