您的位置:首页 > 产品设计 > UI/UE

通过Velocity模板实现了Hibernate sql-query的动态(SQL/HQL)

2015-06-29 23:19 501 查看

一.简介

Hibernate对数据库结构提供了较为完整的封装,Hibernate的O/R Mapping实现了POJO 和数据库表之间的映射,以及SQL 的自动生成和执行。而MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架,MyBatis需要使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。在编写比较复杂的动态SQL语句时,Mybatis的SQL是手动编写的,所以可以按需求指定查询的字段,Hibernate就比较困难的实现。

二.解决问题的思路

MyBatis支持普通SQL查询,存储过程和高级映射的优秀持久层框架,MyBatis需要使用XML配置,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录,我们看一下MySql实现动态的SQL语句是什么样的,例如:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="cn.social.card.mybatis.persistence.SocialSecurityCardMapper" >
<resultMap id="BaseResultMap" type="cn.social.card.mybatis.domain.SocialSecurityCard">
<id column="ID" jdbcType="DECIMAL" property="id" />
<result column="PCH" jdbcType="VARCHAR" property="pch" />
<result column="DWBH" jdbcType="VARCHAR" property="dwbh" />
<result column="XM" jdbcType="VARCHAR" property="xm" />
<result column="XB" jdbcType="VARCHAR" property="xb" />
<result column="SFZH" jdbcType="VARCHAR" property="sfzh" />
<result column="SBKH" jdbcType="VARCHAR" property="sbkh" />
<result column="DWMC" jdbcType="VARCHAR" property="dwmc" />
<result column="YHKH" jdbcType="VARCHAR" property="yhkh" />
<result column="SWKZT" jdbcType="VARCHAR" property="swkzt" />
<result column="JSDWLXR" jdbcType="VARCHAR" property="jsdwlxr" />
<result column="JSDWLXDH" jdbcType="VARCHAR" property="jsdwlxdh" />
<result column="DJCKRY" jdbcType="VARCHAR" property="djckry" />
<result column="DJCKLXFS" jdbcType="VARCHAR" property="djcklxfs" />
<result column="DJSSDW" jdbcType="VARCHAR" property="djssdw" />
<result column="CZRY" jdbcType="VARCHAR" property="czry" />
<result column="CZRQ" jdbcType="VARCHAR" property="czrq" />
</resultMap>
<select id="findCountByCriteria" resultType="java.lang.Integer" >
select count(*) from T_SOCIAL_CARD T1
<include refid="find_where" />
</select>

<select id="findPageListByCriteria" resultMap="BaseResultMap">
<include refid="detail_select" />
<include refid="find_where" />
</select>
<sql id="find_where">
WHERE  1=1
<if test="param != null">
AND (T1.SFZH LIKE  '%'+#{param}+'%' OR T1.XM LIKE  '%'+#{param}+'%')
</if>
</sql>

</mapper>


resultMap 需要把一个一个字段配置,如果一个表字段太多了显示很臃肿也很容易配置出错,我们先抛开这个,我们来查看一下Mybatis怎么实现动态的sql的,采用了if、foreach 等标签,在执行SQL语句之前,先解析这些标签。

我们在页面上也有采用模板引擎,内置了很多web编程中很常用的方法(日期转换、数字格式化等)方便开发人员操作。比较常见的是FreeMarker是模板引擎,是一种基于模板的、用来生成输出文本的通用工具,是基于Java的开发包和类库的。我们可以借鉴MyBatis实现思想和采用模板引擎。

在给大家介绍另外一个Velocity,Velocity是一个基于java的模板引擎(templateengine)。它允许任何人仅仅简单的使用模板语言(template language)来引用由java代码定义的对象。它可以从模板(template)产生SQL和PostScript、XML,它也可以被当作一个独立工具来产生源代码和报告,或者作为其他系统的集成组件使用。Velocity也可以为Turbine web开发架构提供模板服务(template service)。

三.通过Velocity实现了sql-query动态sql

1.先介绍工程的结构,这样思路会比较清晰



2.实现hbm.xml的配置

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
Mapping file autogenerated by MyEclipse - Hibernate Tools
-->
<hibernate-mapping package="com.hibernate.model">
<class name="Card" table="t_card">
<id name="id" column="id" type="java.lang.Integer">
<generator class="native"/>
</id>
<property name="pch" column="pch" type="java.lang.String"/>
<property name="dwbh" column="dwbh" type="java.lang.String"/>
<property name="xm"  column="xm" type="java.lang.String"/>
<property name="xb" column="xb" type="java.lang.String"/>
<property name="sfzh" column="sfzh" type="java.lang.String"/>
<property name="sbkh"  column="sbkh" type="java.lang.String"/>
<property name="dwmc" column="dwmc" type="java.lang.String"/>
<property name="yhkh" column="yhkh" type="java.lang.String"/>
</class>
<sql-query name="Card.getCards">
<return-scalar column="id" type="java.lang.Integer"/>
<return-scalar column="pch" type="java.lang.String"/>
<return-scalar column="dwbh" type="java.lang.String"/>
<return-scalar column="xm" type="java.lang.String"/>
<return-scalar column="xb" type="java.lang.String"/>
<return-scalar column="sfzh" type="java.lang.String"/>
<![CDATA[
select t.id as id,
t.pch as pch,
t.dwbh as dwbh,
t.xm as xm,
t.xb as xb,
t.sfzh as sfzh
from t_card t
where 1=1
#if($xm)
and t.xm=:xm
#end
#if($pch)
and t.pch like '%$pch%'
#end
]]>
</sql-query>
</hibernate-mapping>


Velocity 是采用"#"用来标识的,例如#set、#if 、#else、#end、#foreach、#end、#iinclude、#parse、#macro等;

例如:

#if($xm)

and t.xm=:xm

#end

#if($pch)

and t.pch like '%$pch%'

#end

3.JAVA代码的实现

(一)CardDaoImpl

@Repository
public class CardDaoImpl extends BaseDaoImpl<Card> implements CardDao {

@SuppressWarnings("unchecked")
@Override
public List<Card> getCards(Map<String, Object> param) {
return getNamedQuery("Card.getCards", param).setResultTransformer(Transformers.aliasToBean(Card.class)).list();
}

}


(二)BaseDaoImpl

public class BaseDaoImpl<T> implements BaseDao<T> {

@Autowired
private SessionFactory sessionFactory;

public Session getCurrentSession() {
return sessionFactory.getCurrentSession();
}

@Override
public void add(Object entriy) {
getCurrentSession().save(entriy);
}

/**
* 设置动态的SQL
* @param queryName
* @param param
* @return
*/
@SuppressWarnings("rawtypes")
public Query getNamedQuery(String queryName,Map<String,Object>  param ){
Query query=getCurrentSession().getNamedQuery(queryName);
Query rsQuery=null;
try {
//初始化运行时引擎, 默认初始化
Velocity.init();
//建立context, 并放入数据
VelocityContext context=new VelocityContext();
Set<String> keys=param.keySet();
for (Iterator iterator = keys.iterator(); iterator.hasNext();) {
String key = (String) iterator.next();
context.put(key, param.get(key));
}
//解析后数据的输出目标,java.io.Writer的子类
StringWriter sql=new StringWriter();
//进行解析
Velocity.evaluate(context, sql, "myQuery", query.getQueryString());
rsQuery=getCurrentSession().createSQLQuery(sql.toString());
} catch (Exception e) {
e.printStackTrace();
}
setQueryNameParameters(rsQuery,param);
return rsQuery;

}

/**
* 设置参数
* @param query
* @param param
* @return
*/
public Query setQueryNameParameters(Query query,Map<String,Object>  param){
String[] nameParams=query.getNamedParameters();
for(String nameParam:nameParams){
Object obj=param.get(nameParam);
if(obj instanceof Collection){
query.setParameterList(nameParam, (Collection)obj);
}else if(obj.getClass().isArray()){
query.setParameterList(nameParam, (Object[])obj);
}else{
query.setParameter(nameParam,obj);
}

}

return query;

}

}


是通过Velocity模板和传递进去的parameters参数对模板进行解析,得到最终的语句(纯sql/hql)。

1)获取最原始的SQL语句Query query=getCurrentSession().getNamedQuery(queryName);



2)通过Velocity模板和传递进去的parameters参数对模板进行对标签进行解析,Velocity.evaluate(context, sql, "myQuery", query.getQueryString());



3)然后重新创建成sql/hql语句,rsQuery=getCurrentSession().createSQLQuery(sql.toString());



4)设置参数值,执行返回结果

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: