Mybatis 进行简单通用的封装

配置文件

当Spring和Mybatis集成时,可以利用通配符的形式注册Mapper配置文件

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations" value="classpath*:mybatis-mapper/**/*.xml"/>
    </bean>

Mapper

mapper的生成除了网上普遍的generator的jar包之外,自己还可以实现一个简单的模板生成:
我用的是Freemarker进行模板渲染,自动生成常用的sql:

package org.digdata.swustoj.client;

import freemarker.template.TemplateException;
import org.apache.commons.io.FileUtils;
import org.digdata.swustoj.annotation.Mapping;
import org.digdata.swustoj.util.BeanUtil;
import org.digdata.swustoj.util.FreeMarkerUtil;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.junit.Test;

import java.io.File;
import java.io.IOException;
import java.util.*;

/**
 * Created by hongfei.whf on 2016/11/26.
 */
public class MapperGenerator {

    private String output_dir = "E:\\tmp\\output";
    private String class_path = Thread.currentThread().getContextClassLoader().getResource("").getPath();

    private final static SAXReader reader = new SAXReader();

    private List<Class<?>> classes = BeanUtil.scan("org.digdata.swustoj.entity");
    private String path1 = "auto";
    private String path2 = "impl";

    @Test
    public void run() throws ClassNotFoundException, IOException, IllegalAccessException, InstantiationException, TemplateException, DocumentException {
        for (Class clazz : classes) {
            if (clazz.getSimpleName().endsWith("WithBLOBs")) continue;
            Mapping mapping = (Mapping) clazz.getAnnotation(Mapping.class);
            String className = clazz.getCanonicalName();
            String namespace = className.replace("entity", "dao") + "Mapper";
            String tableName = mapping.tableName();
            String resultMap = getResultMap(clazz);
            String queryType = mapping.queryType().getCanonicalName();

            Map<String, Object> map = new HashMap<>();
            map.put("namespace", namespace);
            map.put("queryType", queryType);
            map.put("tableName", tableName);
            map.put("resultMap", resultMap);
            ArrayList fields = new ArrayList();

            Class extendsClass = clazz;
            fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
            try {
                extendsClass = Class.forName(clazz.getCanonicalName() + "WithBLOBs");
                fields.addAll(Arrays.asList(extendsClass.getDeclaredFields()));
            } catch (Exception e) {
                //
            }
            map.put("ownType", extendsClass.getCanonicalName());
            map.put("fields", fields);
            String template_path = class_path + File.separator + "mybatis-mapper/template/TemplateMapper.ftl";
            String template = FileUtils.readFileToString(new File(template_path));

            String custom_path = class_path + File.separator + "mybatis-mapper/template/CustomMapper.ftl";
            String custom = FileUtils.readFileToString(new File(custom_path));

            String TemplateContent = FreeMarkerUtil.proccessTemplate(clazz.getCanonicalName(),
                    template, map);
            String auto_render_template_file_path = getRenderPath(clazz, true);
            FileUtils.write(new File(auto_render_template_file_path), TemplateContent);

            String CustomContent = FreeMarkerUtil.proccessTemplate(clazz.getCanonicalName(),
                    custom, map);
            String auto_render_custom_file_path = getRenderPath(clazz, false);
            FileUtils.write(new File(auto_render_custom_file_path), CustomContent);
        }
    }

    private String getResultMap(Class clazz) throws DocumentException {
        String mapperFilePath = class_path + File.separator + "mybatis-mapper" + File.separator + clazz.getSimpleName() + "Mapper.xml";
        Document document = reader.read(new File(mapperFilePath));
        Element root = document.getRootElement();
        if ("mapper".equals(root.getName())) {
            Iterator iter = root.elementIterator();
            while (iter.hasNext()) {
                Element currElement = (Element) iter.next();
                if ("resultMap".equals(currElement.getName())) {
                    if ("ResultMapWithBLOBs".equals(currElement.attributeValue("id"))) {
                        return "ResultMapWithBLOBs";
                    }
                }
            }
        }
        return "BaseResultMap";
    }

    private String getRenderPath(Class clazz, Boolean isTemplate) {
        return output_dir +
                File.separator +
                (isTemplate ? path1 : path2) +
                File.separator +
                clazz.getSimpleName() +
                "Mapper.xml";
    }
}

模板1:

<?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="${namespace}">

    <!-- query ${tableName} -->
    <select id="query" resultMap="${resultMap}"
            parameterType="${queryType}">
        select
        *
        from ${tableName}
        <include refid="condition"/>
        <include refid="orderby"/>
        <if test="start != null and rows != null">
        <#noparse>limit #{start},#{rows}</#noparse>
        </if>
    </select>

    <!-- count ${tableName} -->
    <select id="count" resultType="java.lang.Integer"
            parameterType="${queryType}">
        select
        count(*)
        from ${tableName}
        <include refid="condition"/>
    </select>

    <!-- query ${tableName} by ids -->
    <select id="queryByIds" parameterType="java.util.List" resultMap="${resultMap}">
        select
        *
        from ${tableName}
        <where>
            ${tableName}.id in
            <foreach collection="list" item="item" open="("
                     separator="," close=")">
                <#noparse>#{item}</#noparse>
            </foreach>
        </where>
    </select>

    <!-- delete ${tableName} by ids -->
    <delete id="delete" parameterType="${queryType}">
        delete from ${tableName}
        <include refid="condition"/>
    </delete>

    <!-- save batch ${tableName} -->
    <insert id="saveBatch" parameterType="java.util.List">
        insert into ${tableName}
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <#list fields as field>
                ${field.name},
            </#list>
        </trim>
        value
        <foreach item="item" index="index" collection="list" separator=",">
            <trim prefix="(" suffix=")" suffixOverrides=",">
                <#list fields as field>
                    <#noparse>#{item.</#noparse>${field.name}<#noparse>},</#noparse>
                </#list>
            </trim>
        </foreach>
    </insert>

    <!-- save ${tableName} And Return Id -->
    <insert id="saveAndRetId" parameterType="${ownType}"
            useGeneratedKeys="true" keyProperty="id">
        insert into ${tableName}
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <#list fields as field>
                <if test="${field.name} != null">
                    ${field.name},
                </if>
            </#list>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <#list fields as field>
                <if test="${field.name} != null">
                    <#noparse>#{</#noparse>${field.name}<#noparse>},</#noparse>
                </if>
            </#list>
        </trim>
    </insert>

</mapper>

模板2:

<?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="${namespace}">

    <!-- 若要进行修改,请在此补全sql,防止以后模板扩展带来的代码迁移的不便 -->
    <!-- 注意,此两处sql均被使用到,请勿注释或删除 -->
    <!-- where sql -->
    <sql id="condition">
        <where>
            1=1
        </where>
    </sql>
    <!-- orderby sql -->
    <sql id="orderby">

    </sql>

</mapper>

Dao层统一封装

我利用的是Spring4.0提供的泛型注入:

package org.digdata.swustoj.dao;

import org.digdata.swustoj.annotation.CacheAccess;
import org.digdata.swustoj.annotation.CacheFlush;
import org.digdata.swustoj.query.PageQuery;

import java.util.List;

/**
 * Created by hongfei.whf on 2016/8/27.
 */
public interface BaseDao<T, Q extends PageQuery> {

    /**
     * 删除指定id
     *
     * @param id
     * @return
     */
    @CacheFlush
    int deleteByPrimaryKey(Integer id);

    /**
     * 插入
     *
     * @param record
     * @return
     */
    @CacheFlush
    int insert(T record);

    /**
     * 条件插入
     *
     * @param record
     * @return
     */
    @CacheFlush
    int insertSelective(T record);

    /**
     * 查询指定id
     *
     * @param id
     * @return
     */
    @CacheAccess(type = Object.class)
    T selectByPrimaryKey(Integer id);

    /**
     * 根据id条件更新
     *
     * @param record
     * @return
     */
    @CacheFlush
    int updateByPrimaryKeySelective(T record);

    /**
     * 根据id更新
     *
     * @param record
     * @return
     */
    @CacheFlush
    int updateByPrimaryKey(T record);

    /**
     * 条件查询
     *
     * @param query
     * @return
     */
    @CacheAccess(type = List.class)
    List<T> query(Q query);

    /**
     * 根据ids查询
     *
     * @param ids
     * @return
     */
    @CacheAccess(type = List.class)
    List<T> queryByIds(List<Integer> ids);

    /**
     * 条件查询数量
     *
     * @param query
     * @return
     */
    @CacheAccess(type = Integer.class)
    Integer count(Q query);

    /**
     * 删除
     *
     * @param query
     * @return
     */
    @CacheFlush
    Boolean delete(Q query);

    /**
     * 添加
     *
     * @param record
     * @return
     */
    @CacheFlush
    Boolean save(T record);

    /**
     * 更新
     *
     * @param record
     * @return
     */
    @CacheFlush
    Boolean update(T record);

    /**
     * 批量插入
     *
     * @param list
     * @return
     */
    @CacheFlush
    Boolean saveBatch(List<T> list);

    /**
     * 插入并返回主键
     *
     * @param t
     * @return
     */
    @CacheFlush
    Integer saveAndRetId(T t) throws NoSuchFieldException, IllegalAccessException;

}

注意:这里的注解和Mybatis无关,主要实现与Memcache的统一操作

Dao统一封装实现类

package org.digdata.swustoj.dao.impl;

import org.digdata.swustoj.dao.BaseDao;
import org.digdata.swustoj.query.PageQuery;
import org.digdata.swustoj.util.BeanUtil;
import org.mybatis.spring.support.SqlSessionDaoSupport;

import java.util.List;

/**
 * Created by hongfei.whf on 2016/8/27.
 */
public abstract class BaseDaoImpl<T, Q extends PageQuery> extends SqlSessionDaoSupport implements BaseDao<T, Q> {

    /**
     * 获取mapper的namespace
     *
     * @return
     */
    public abstract String getNameSpace();

    /**
     * 获取子类型,推荐填写T的class,,用于缓存序列化和反序列化的实现
     *
     * @return
     */
    public abstract Class getSubType();

    @Override
    public int deleteByPrimaryKey(Integer id) {
        return this.getSqlSession().delete(getNameSpace() + ".deleteByPrimaryKey", id);
    }

    @Override
    public int insert(T record) {
        return this.getSqlSession().insert(getNameSpace() + ".insert", record);
    }

    @Override
    public int insertSelective(T record) {
        return this.getSqlSession().insert(getNameSpace() + ".insertSelective", record);
    }

    @Override
    public T selectByPrimaryKey(Integer id) {
        return this.getSqlSession().selectOne(getNameSpace() + ".selectByPrimaryKey", id);
    }

    @Override
    public int updateByPrimaryKeySelective(T record) {
        return this.getSqlSession().update(getNameSpace() + ".updateByPrimaryKeySelective", record);
    }

    @Override
    public int updateByPrimaryKey(T record) {
        return this.getSqlSession().update(getNameSpace() + ".updateByPrimaryKey", record);
    }

    @Override
    public List<T> query(Q query) {
        return this.getSqlSession().selectList(getNameSpace() + ".query", query);
    }

    @Override
    public List<T> queryByIds(List<Integer> list) {
        return this.getSqlSession().selectList(getNameSpace() + ".queryByIds", list);
    }

    @Override
    public Integer count(Q query) {
        return this.getSqlSession().selectOne(getNameSpace() + ".count", query);
    }

    @Override
    public Boolean delete(Q query) {
        return this.getSqlSession().delete(getNameSpace() + ".delete", query) > 0 ? true : false;
    }

    @Override
    public Boolean save(T record) {
        return this.insertSelective(record) > 0 ? true : false;
    }

    @Override
    public Integer saveAndRetId(T t) throws NoSuchFieldException, IllegalAccessException {
        if (this.getSqlSession().insert(getNameSpace() + ".saveAndRetId", t) > 0) {
            return BeanUtil.getFieldValue(t, "id", Integer.class);
        }
        return null;
    }

    @Override
    public Boolean update(T record) {
        return this.updateByPrimaryKeySelective(record) > 0 ? true : false;
    }

    @Override
    public Boolean saveBatch(List<T> list) {
        return this.getSqlSession().insert(getNameSpace() + ".saveBatch", list) > 0 ? true : false;
    }
}

使用方式:


@Repository
public class ProblemDaoImpl extends BaseDaoImpl<ProblemWithBLOBs, ProblemQuery> implements ProblemDao {
    // ....
}

这里写图片描述

Service层的统一封装

Service层的封装参考Dao层的封装即可,我主要封装的是分页,批量操作等。

这里写图片描述

  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值