一、前言
本人使用mybatis也有些年头了。对于mybatis的使用也有点个人的心得。个人感觉mybatis在使用起来比hibernate方便且轻量级,这也是我喜欢使用mybatis的原因之一。但是每次在过了一段时间之后就会出现mybatis的xml文件里面的sql语句越来越多,看起来也不是十分美观,也不是很方便。在之前我也试过建立通用的BaseMapper来解决这个问题,BaseMapper固然也能够解决这样的一个问题,但是在我看来着绝非是一个非常有效的方法,偶然的情况下,我接触到了tk.mybatis.mapper这个框架,简直就像干柴遇到烈火,我跟它一拍即合。
二、第一版的实现
但是,在使用过一段时间的通用mapper之后,虽然mapper这个框架已经做的很好了,但是我在实际项目中经常需要使用left join功能和按字段更新功能,这在目前的mapper框架中是不支持的,于是我就想到了自身来实现其功能,于是就有了下面所展示的第一版:
第一版重点类图:
图片可能看的不是很清楚,我来说明下:主要查询功能的封装是在BaseExample而SelectBaseExample扩展了order by,group by和查询字段的功能,UpdateBaseExample封装了更新的字段及值的功能。left join功能则是在MultipartSelectExample类中进行封装。所以在这里我们可以根据我们的需求来创建SelectBaseExample,UpdateBaseExample或者MultipartSelectExample这三个类。大家可能会感到疑惑为什么MultipartUpdateExample这个类里面好像一点东西都没有呢。其实我在设计的时候是感觉应该存在这样一个类,但是当我写出来之后我又不知道更新操作会用到什么更高级的功能,所以就暂时先空着啦,哈哈,看官老爷们可以无视。
介绍完重要的封装类之后,我们来看看Mapper的层级结构:
这三个类中主要的两个类是SelectBaseMapper和UpdateBaseMapper这两个类,分别有通用的查询和更新的方法,而BaseExampleMapper这个类则是为了集合查询和更新等功能的一个辅助类。在使用的时候只需要让业务Mapper继承BaseExampleMapper即可。
最后我们再来看看xml文件的实现。
<?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="com.example.test.mapper.BaseExampleMapper">
<select id = "getObjectByField" parameterType="com.example.test.example.select.SelectBaseExample" resultType="map">
select <foreach collection="baseExample.fields" index="index" item="item" separator=",">
${item}
</foreach> from ${baseExample.tableName[0]}
<if test="baseExample.tableAlias != null ">
${baseExample.tableAlias[0]}
</if>
<!-- 判断是不是MultipartSelectExample并且使用了left join功能 -->
<if test="baseExample instanceof com.example.test.example.select.multipart.MultipartSelectExample and baseExample.leftJoinFlag">
LEFT JOIN
<foreach collection="baseExample.tableAlias" item="key" index="index" separator="">
<if test="index >= 1">
${baseExample.tableName[1]} ${key}
</if>
</foreach>
ON ${baseExample.leftJoinOn}
</if>
<if test="baseExample.equalsWhere != null or baseExample.greaterThanWhere != null or baseExample.lessThanWhere != null or baseExample.notEqualsWhere != null">
<where>
<if test="baseExample.equalsWhere != null">
<foreach collection="baseExample.equalsWhere.keys" item="key" index="index" separator="AND">
<if test = "baseExample.tableAlias != null">
${baseExample.tableAlias[0]}.
</if>
${key} = #{baseExample.equalsWhere[${key}]}
</foreach>
<if test="baseExample.greaterThanWhere != null or baseExample.lessThanWhere != null or baseExample.notEqualsWhere != null">
AND
</if>
</if>
<if test="baseExample.greaterThanWhere != null">
<!-- 遍历map的key -->
<foreach collection="baseExample.greaterThanWhere.keys" item="key" index="index" separator="AND">
<!-- 获取key对应的value -->
${key} > #{baseExample.greaterThanWhere[${key}]}
</foreach>
<if test="baseExample.lessThanWhere != null or baseExample.notEqualsWhere != null">
AND
</if>
</if>
<if test="baseExample.lessThanWhere != null">
<foreach collection="baseExample.lessThanWhere.keys" item="key" index="index" separator="AND">
${key} < #{baseExample.lessThanWhere[${key}]}
</foreach>
<if test="baseExample.notEqualsWhere != null">
AND
</if>
</if>
<if test ="baseExample.notEqualsWhere != null">
<foreach collection="baseExample.notEqualsWhere.keys" item="key" index="index" separator="AND">
${key} != #{baseExample.notEqualsWhere[${key}]}
</foreach>
</if>
</where>
</if>
<if test="baseExample.equalsWhere == null and baseExample.greaterThanWhere == null and baseExample.lessThanWhere == null and baseExample.notEqualsWhere == null">
WHERE 1 = 1
</if>
<if test="baseExample.inFields != null and baseExample.inFields.size() > 0">
AND
<foreach collection="baseExample.inFields" item="field" index="index" separator="AND">
${field} in
<choose>
<when test="index == 0">
<foreach collection="baseExample.inValue1" item="value1" index="index1" separator="," open="(" close=")">
#{value1}
</foreach>
</when>
<otherwise>
<foreach collection="baseExample.inValue2" item="value2" index="index2" separator="," open="(" close=")">
#{value2}
</foreach>
</otherwise>
</choose>
</foreach>
</if>
<if test=" baseExample.likeFields != null">
<if test="baseExample.inFields != null and baseExample.inFields.size() > 0">
AND
</if>
<foreach collection="baseExample.likeFields" item="field" index="index" separator="AND">
${field} LIKE #{baseExample.likeValues[${index}]}
</foreach>
</if>
<!-- 判断是否含有group by -->
<if test="baseExample.groupBy != null">
GROUP BY ${baseExample.groupBy}
</if>
<!-- 判断是否含有order by -->
<if test="baseExample.orderBy != null">
ORDER BY
<foreach collection="baseExample.orderBy.keys" item="key" index="index" separator=",">
${key}
<choose>
<when test="baseExample.orderBy[key] == 'DESC'">
DESC
</when>
<otherwise>
ASC
</otherwise>
</choose>
</foreach>
</if>
</select>
</mapper>
以上是通用查询的xml实现,虽然有点多,但是并不复杂,并且其中的部分内容有注释相信看官们老爷能够理解。接下来是更新的通用方法。
<?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="com.example.test.mapper.BaseExampleMapper">
<update id = "updateObject" parameterType="com.example.test.example.update.UpdateBaseExample" >
UPDATE ${baseExample.tableName[0]} SET
<if test="baseExample.updateFields != null">
<foreach collection="baseExample.updateFields.keys" item="key" index="index" separator=",">
${key} = #{baseExample.updateFields[${key}]}
</foreach>
</if>
<if test="baseExample.equalsWhere != null or baseExample.greaterThanWhere != null or baseExample.lessThanWhere != null or baseExample.notEqualsWhere != null">
<where>
<if test="baseExample.equalsWhere != null">
<foreach collection="baseExample.equalsWhere.keys" item="key" index="index" separator="AND">
<if test = "baseExample.tableAlias != null">
${baseExample.tableAlias[0]}.
</if>
${key} = #{baseExample.equalsWhere[${key}]}
</foreach>
<if test="baseExample.greaterThanWhere != null or baseExample.lessThanWhere != null or baseExample.notEqualsWhere != null">
AND
</if>
</if>
<if test="baseExample.greaterThanWhere != null">
<foreach collection="baseExample.greaterThanWhere.keys" item="key" index="index" separator="AND">
${key} > #{baseExample.greaterThanWhere[${key}]}
</foreach>
<if test="baseExample.lessThanWhere != null or baseExample.notEqualsWhere != null">
AND
</if>
</if>
<if test="baseExample.lessThanWhere != null">
<foreach collection="baseExample.lessThanWhere.keys" item="key" index="index" separator="AND">
${key} < #{baseExample.lessThanWhere[${key}]}
</foreach>
<if test="baseExample.notEqualsWhere != null">
AND
</if>
</if>
<if test ="baseExample.notEqualsWhere != null">
<foreach collection="baseExample.notEqualsWhere.keys" item="key" index="index" separator="AND">
${key} != #{baseExample.notEqualsWhere[${key}]}
</foreach>
</if>
</where>
</if>
<choose>
<when test="baseExample.equalsWhere != null or baseExample.greaterThanWhere != null or baseExample.lessThanWhere != null">
AND
</when>
<otherwise>
WHERE
</otherwise>
</choose>
<if test="baseExample.inFields != null and baseExample.inFields.size() > 0">
<foreach collection="baseExample.inFields" item="field" index="index" separator="AND">
${field} in
<choose>
<when test="index == 0">
<foreach collection="baseExample.inValue1" item="value1" index="index1" separator="," open="(" close=")">
#{value1}
</foreach>
</when>
<otherwise>
<foreach collection="baseExample.inValue2" item="value2" index="index2" separator="," open="(" close=")">
#{value2}
</foreach>
</otherwise>
</choose>
</foreach>
</if>
<if test=" baseExample.likeFields.size() > 0">
<foreach collection="baseExample.likeFields" item="field" index="index" separator="AND">
${field} LIKE #{baseExample.likeValues[${index}]}
</foreach>
</if>
</update>
</mapper>
更新的通用方法和查询的通用方法比较类似,再次就不做过多解释了。
好啦,以上就是第一版全部内容,虽然功能非常全面,性能也不算低,但是我个人认为又有xml,内容还比较乱,代码的复用性很差,同时代码的侵入性很强,不符合我的语预期,所以在下一篇中我将会介绍我的2.0版本,跟1.0版本比较,看官老爷们一定会觉得有质的变化。