结合脚本生成 实现 ibatis sqlmap 的"继承"
在使用ibatis实现数据库层映射时, sqlmap提供了很好的灵活性,可以方便的调试,改进sql语句的性能。将ibatis访问数据库操作作了一层封装后,原来的ibatis sqlmap 生成工具就不能很好的满足要求了。对于很多的表都对应于业务实体,需要手工一个个的写过来,这个实在是有点…… 后来使用了一款代码生成工具,编写脚本,自动生成自定义格式的dao和sqlmap,感觉还不错。不过美中不足的是,自动生成的sqlmap只是实现了基本的增、删、改、查功能,若需要自定义的sql脚本,就必须修改生成的sqlmap文件,一旦数据库修改,再次生成后就不能简单的覆盖了事,还需要手工修改,誊抄,这样一来就比较烦,也容易乱。
后来,就想,要是sqlmap文件也能像类那样能够继承,有修改或添加只需要修改“派生类”的sqlmap文件,而“父类”sqlmap文件可以多次自动生成, 那多好。查看相关资料后,发现派生org.springframework.orm.ibatis.SqlMapClientFactoryBean类,实现mappingLocations的重载,可以将多个目录中的sqlmap文件按次序加载,当然,加载的先后次序一定要保证“父类”的sqlmap文件先于“派生类”的sqlmap文件。
1. 为org.springframework.orm.ibatis.SqlMapClientFactoryBean派生类的部分代码:
/**
* 用于生成SqlMapClient,但增加设置sqlExecutor属性,以便用于扩展ibatis使用数据库物理分页
*
*/
public class SqlMapClientFactoryBeanEx extends org.springframework.orm.ibatis.SqlMapClientFactoryBean{
。。。。。。
private Resource[] extMappingLocations;
private Resource[] mappingLocations;
/**
* 将截获的mappingLocations,和扩展的extMappingLocations合并,再调用父类的set函数,完成mappingLocations的注入
* @param extMappingLocations
*/
public void setExtMappingLocations(Resource[] extMappingLocations) {
this.extMappingLocations = extMappingLocations;
List<Resource> lists = new ArrayList<Resource>();
if(this.mappingLocations.length >0){
for(Resource r : this.mappingLocations){
lists.add(r);
}
}
for(Resource r : this.extMappingLocations){
lists.add(r);
}
Resource[] extMaps = lists.toArray(new Resource[0]);
super.setMappingLocations(extMaps);
}/**
* 重载父类的mappingLocations注入,截获Resource[],已被和扩展的extMappingLocations组合
*/
@Override
public void setMappingLocations(Resource[] mappingLocations) {
this.mappingLocations = mappingLocations;
}
。。。。。。
}
2.有关ibatis的配置文件片断:
<!-- sqlMapClient -->
<bean id="sqlMapClient" class="com.cgnw.sns.dbaccess.ibatis.SqlMapClientFactoryBeanEx">
<property name="configLocation">
<value>WEB-INF/conf/SqlMapConfig.xml</value>
</property>
<!-- 自动解析*_sqlmap.xml文件, 注意先后顺序,不能搞反了-->
<property name="mappingLocations">
<value>classpath:com/cgnw/sns/dbaccess/sqlmapxml/*_SqlMap.xml</value>
</property>
<property name="extMappingLocations">
<value>classpath:com/cgnw/sns/businessweb/sqlmapxmlExt/*_SqlMap.Ext.xml
</value>
</property>
<property name="dataSource" ref="dataSource" />
<!--指定数据库分页方言Dialect -->
<property name="sqlExecutor">
<bean class="com.cgnw.sns.dbaccess.ibatis.LimitSqlExecutor">
<property name="dialect">
<bean class="com.cgnw.sns.dbaccess.ibatis.OracleDialect" />
</property>
</bean>
</property>
</bean>
3. sqlmap文件样本
<!--
File: com.cgnw.sns.domain.City_SqlMap.xml.
Description:These codes were generated by CodeSmith.
Copyright 2006-2011 cgnw Corporation. All rights reserved.
-->
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap namespace="City">
<typeAlias alias="City" type="com.cgnw.sns.dbaccess.domain.City" />
<resultMap class="City" id="CityMap">
<result property="cityCd" column="city_cd" />
<result property="stateCd" column="state_cd" />
<result property="cityName" column="city_name" />
<result property="cityClass" column="city_class" />
<result property="parentCity" column="parent_city" />
<result property="cityOrder" column="city_order" />
<result property="cityNote" column="city_note" />
</resultMap>
<!-- INSERT -->
<insert id="insert" parameterClass="City">
INSERT INTO
<dynamic prepend="t_city" open="(" close=")">
city_cd,
state_cd,
city_name,
<isNotNull prepend="," property="cityClass">city_class</isNotNull>
<isNotNull prepend="," property="parentCity">parent_city</isNotNull>
<isNotNull prepend="," property="cityOrder">city_order</isNotNull>
<isNotNull prepend="," property="cityNote">city_note</isNotNull>
</dynamic>
<dynamic open="(" close=")" prepend="VALUES">
s_t_city.nextval,
#stateCd#,
#cityName#,
<isNotNull prepend="," property="cityClass">#cityClass#</isNotNull>
<isNotNull prepend="," property="parentCity">#parentCity#</isNotNull>
<isNotNull prepend="," property="cityOrder">#cityOrder#</isNotNull>
<isNotNull prepend="," property="cityNote">#cityNote#</isNotNull>
</dynamic>
<selectKey resultClass="String">
SELECT s_t_city.CURRVAL FROM DUAL
</selectKey>
</insert>
<!-- UPDATE -->
<update id="update" parameterClass="City" >
UPDATE t_city
<dynamic prepend="SET">
<isNotNull prepend="," property="stateCd" removeFirstPrepend="true">state_cd=#stateCd#</isNotNull>
<isNotNull prepend="," property="cityName" removeFirstPrepend="true">city_name=#cityName#</isNotNull>
<isNotNull prepend="," property="cityClass" removeFirstPrepend="true">city_class=#cityClass#</isNotNull>
<isNotNull prepend="," property="parentCity" removeFirstPrepend="true">parent_city=#parentCity#</isNotNull>
<isNotNull prepend="," property="cityOrder" removeFirstPrepend="true">city_order=#cityOrder#</isNotNull>
<isNotNull prepend="," property="cityNote" removeFirstPrepend="true">city_note=#cityNote#</isNotNull>
</dynamic>
WHERE city_cd=#cityCd#
</update>
<!-- select an object by primaryKey -->
<select id="selectByPrimaryKey" resultMap="CityMap" parameterClass="String">
SELECT * FROM T_CITY WHERE CITY_CD=#cityCd#
</select>
<select id="select" resultMap="CityMap" parameterClass="Map">
SELECT * FROM T_CITY
<dynamic prepend="WHERE">
<isNotNull prepend=" AND " property="stateCd" removeFirstPrepend="true">state_cd=#stateCd#</isNotNull>
<isNotNull prepend=" AND " property="cityName" removeFirstPrepend="true">city_name=#cityName#</isNotNull>
<isNotNull prepend=" AND " property="cityClass" removeFirstPrepend="true">city_class=#cityClass#</isNotNull>
<isNotNull prepend=" AND " property="parentCity" removeFirstPrepend="true">parent_city=#parentCity#</isNotNull>
<isNotNull prepend=" AND " property="cityOrder" removeFirstPrepend="true">city_order=#cityOrder#</isNotNull>
<isNotNull prepend=" AND " property="cityNote" removeFirstPrepend="true">city_note=#cityNote#</isNotNull>
</dynamic>
<dynamic prepend="ORDER BY">
<isNotNull property="orderBy">$orderBy$</isNotNull>
</dynamic>
</select>
<select id="count" resultClass="Integer" parameterClass="Map">
SELECT COUNT(*) FROM T_CITY
<dynamic prepend="WHERE">
<isNotNull prepend=" AND " property="stateCd" removeFirstPrepend="true">state_cd=#stateCd#</isNotNull>
<isNotNull prepend=" AND " property="cityName" removeFirstPrepend="true">city_name=#cityName#</isNotNull>
<isNotNull prepend=" AND " property="cityClass" removeFirstPrepend="true">city_class=#cityClass#</isNotNull>
<isNotNull prepend=" AND " property="parentCity" removeFirstPrepend="true">parent_city=#parentCity#</isNotNull>
<isNotNull prepend=" AND " property="cityOrder" removeFirstPrepend="true">city_order=#cityOrder#</isNotNull>
<isNotNull prepend=" AND " property="cityNote" removeFirstPrepend="true">city_note=#cityNote#</isNotNull>
</dynamic>
</select>
<!-- DELETE -->
<delete id="delete" parameterClass="String">
DELETE FROM T_CITY WHERE
city_cd=#cityCd#
</delete>
</sqlMap>
<!-- Generating End -->
4. sqlmapex文件样本
<?xml version="1.0" encoding="UTF-8"?>
<!--
File: com.cgnw.sns.domain.City_SqlMap.Ext.xml.
Description:These codes were generated by CodeSmith.
Copyright 2006-2011 cgnw Corporation. All rights reserved.
-->
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap namespace="City"><!--注意namespace和“父类”的相同,共用resultmap-->
<!--
<resultMap class="City" id="CityMap">
<result property="cityCd" column="city_cd" />
<result property="stateCd" column="state_cd" />
<result property="cityName" column="city_name" />
<result property="cityClass" column="city_class" />
<result property="parentCity" column="parent_city" />
<result property="cityOrder" column="city_order" />
<result property="cityNote" column="city_note" />
</resultMap>
-->
<!-- Here are your's codes... -->
</sqlMap>
这样,开发时可以只修改sqlmapex文件,而sqlmap文件有工具来维护,感觉比较方便。
5. 参考文章
http://www.iteye.com/topic/930092 让sqlmap文件 "继承" 起来