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

一.简介

    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)设置参数值,执行返回结果

    











评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农_程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值