mybatis全自动ORM二次封装(像hibernate一样使用mybatis)

入职新公司 选定了mybatis作为orm框架,mybatis的好处简单明了直接写sql语句就行,但是对于已经习惯了hibernate的我来说mybatis每个单表查询都要新建接口和xml映射文件就有点麻烦了,我在想能不能和hibernate一样直接调用save(),update(),query()方法就直接能执行dml语句呢,于是尝试封装mybatis做一个基础的mapper。

在这里使用mybatis java api的 provider动态执行sql

basemapper接口

import java.util.Map;

import org.apache.ibatis.annotations.InsertProvider;
import org.apache.ibatis.annotations.SelectProvider;
import org.apache.ibatis.annotations.UpdateProvider;

import com.github.pagehelper.Page;

/**
 * 通用mapper
 * @author zwt
 *
 */
public interface MybaseMapper {
    

    @InsertProvider(method = "saveEntity", type = com.huadi.xcx.dao.provider.MybaseProvider.class)
    public <T> int saveEntity(String tableName,T t);
    
    @UpdateProvider(method = "updateEntity", type = com.huadi.xcx.dao.provider.MybaseProvider.class)
    public <T> int updateEntity(String tableName,T t,Map<String,Object> params);
    
    @SelectProvider(method = "queryAllByParams", type = com.huadi.xcx.dao.provider.MybaseProvider.class)
    public List<Map<String,Object>> queryAllByParams(Class<?> cls,String tableName,Map<String,Object> params);
    
    @SelectProvider(method = "queryPageByParams", type = com.huadi.xcx.dao.provider.MybaseProvider.class)
    public Page<Map<String,Object>> queryPageByParams(Class<?> cls,String tableName,Map<String,Object> params);
}

mapper对应的provider

import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.apache.ibatis.jdbc.SQL;

import com.huadi.xcx.common.util.FieldUtils;

/**
 * 通用provider
 * @author zwt
 *
 */
public class MybaseProvider{
    
    public <T> String saveEntity(String tableName,T t) throws Exception {
        Field[] fields =t.getClass().getDeclaredFields();
        return new SQL(){
                {
                    INSERT_INTO(tableName);
                    for(Field f:fields) {
                        f.setAccessible(true);
                        String key=f.getName();
                        Object value =f.get(t);
                        if(value!=null) {
                            VALUES(f.getName(), "#{t."+key+"}");
                        }
                    }
                }
            }.toString();
    }
    
    public <T> String updateEntity(String tableName,T t,Map<String,Object> params) throws Exception {
        if(params==null || params.keySet().size()<1)
        {
            throw new Exception("updateEntity 方法必须有条件参数");
        }
        
        Field[] fields =t.getClass().getDeclaredFields();
        return new SQL(){
                {
                    UPDATE(tableName);
                    for(Field f:fields) {
                        f.setAccessible(true);
                        String key=f.getName();
                        Object value =f.get(t);
                        if(value!=null) {
                            SET(f.getName()+" = #{t."+key+"}");
                        }
                    }
                    
                    if(params !=null )
                    {
                        Set<String> keys=params.keySet();
                        Iterator<String> it=keys.iterator();
                        while(it.hasNext()) {
                            String key= it.next();
                            String filedName=FieldUtils.UnderlineToHump(key);
                            for(Field f:fields) {
                                if(filedName.equals(f.getName()))
                                {
                                    if(String.class.toString().equals(f.getGenericType().toString()))
                                    {
                                        WHERE("to_char("+key+") = #{params."+key+"}");
                                    }else
                                    {
                                        WHERE(key+" = #{params."+key+"}");
                                    }
                                    break;
                                }
                            }
                        }
                    }
                }
            }.toString();
    }
    
    public String queryAllByParams(Class<?> cls,String tableName,Map<String,Object> params) {
        return queryPageByParams(cls,tableName,params);
    }
    
    public String queryPageByParams(Class<?> cls,String tableName,Map<String,Object> params) {
        Field[] fields =cls.getDeclaredFields();
        return new SQL() {
            {
                SELECT("*");
                FROM(tableName);
                
                if(params !=null )
                {
                    Set<String> keys=params.keySet();
                    Iterator<String> it=keys.iterator();
                    while(it.hasNext()) {
                        String key= it.next();
                        String filedName=FieldUtils.UnderlineToHump(key);
                        for(Field f:fields) {
                            if(filedName.equals(f.getName()))
                            {
                                if(String.class.toString().equals(f.getGenericType().toString()))
                                {
                                    WHERE("to_char("+key+") = #{params."+key+"}");
                                }else
                                {
                                    WHERE(key+" = #{params."+key+"}");
                                }
                                break;
                            }
                        }
                    }
                }
            }
        }.toString();
    }

}

此时baseMapper 相当于传统意义的baseDao,但是由于查询出来的是resultSet 集合并不能直接使用,如果要使用对象还需要手动转型,十分麻烦,如何才能和hibernate一样查出来的直接是java对象呢

此时便定义一个baseService提供基础增删该查功能
需要注意的是数据库类型与javabean类型不同需要转型 此处暂时只转了BigDecimal与CLOB型

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.huadi.xcx.common.util.FieldUtils;
import com.huadi.xcx.dao.MybaseMapper;

import oracle.sql.CLOB;
/**
 * 通用增删改查方法
 * @author zwt
 *
 */

@Service("MyBaseService")
public class MyBaseService {
    
    @Autowired
    private MybaseMapper mybaseDao;
    
    //保存暂时还不支持带出自增主键 有需求可以以后添加
    public <T> void saveEntity(String tableName,T t) {
        int row=mybaseDao.saveEntity(tableName, t);
    }
    
    public <T> void updateEntity(String tableName,T t,Map<String,Object> params) {
        int row=mybaseDao.updateEntity(tableName, t, params);
    }
    
    @SuppressWarnings("unchecked")
    public <T> List<T> queryAllByParams(Class<?> cls,String tableName,Map<String,Object> params) {
        List<Map<String,Object>>  queryResult=mybaseDao.queryAllByParams(cls, tableName, params);
        List<T> backResult = new ArrayList<>();
        Field[] fields = cls.getDeclaredFields();
        T nt;
        for(int i=0;i<queryResult.size();i++)
        {
            try {
                nt=(T) cls.newInstance();
                Map<String,Object> map =queryResult.get(i);
                StringBuffer sb = new StringBuffer();
                Set<String> keys=map.keySet();
                Iterator<String> it =keys.iterator();
                while(it.hasNext()) {
                    String key=it.next();
                    String fieldName=FieldUtils.UnderlineToHump(key);
                    Object value =map.get(key);
                    for(Field f:fields) {
                        if(fieldName.equals(f.getName())) {
                            f.setAccessible(true);
                            //需要转型
                            if(BigDecimal.class.toString().equals(value.getClass().toString())) {
                                Type type=f.getGenericType();
                                Class fieldClass =Class.forName(type.getTypeName());
                                Method method=fieldClass.getMethod("valueOf",String.class);
                                value=method.invoke(value, value.toString());
                                f.set(nt, value);
                            }else if(CLOB.class.toString().equals(value.getClass().toString())) {
                                f.set(nt, FieldUtils.ClobToString((CLOB)value));
                            }
                            else {
                                f.set(nt, value);
                            }
                            break;
                        }
                    }
                }
                backResult.add(nt);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        return backResult;
    }
    
    @SuppressWarnings("unchecked")
    public <T> PageInfo<T> queryPageByParams(Class<?> cls,String tableName,Map<String,Object> params,int pageNum,int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        Page<Map<String,Object>>  queryPage=mybaseDao.queryPageByParams(cls, tableName, params);
        PageInfo pageinfo =new PageInfo(queryPage);
        List<Map<String,Object>> queryResult = pageinfo.getList();
        List<T> resultList = new ArrayList<>();
        Field[] fields = cls.getDeclaredFields();
        T nt;
        for(int i=0;i<queryResult.size();i++)
        {
            try {
                nt=(T) cls.newInstance();
                Map<String,Object> map =queryResult.get(i);
                StringBuffer sb = new StringBuffer();
                Set<String> keys=map.keySet();
                Iterator<String> it =keys.iterator();
                while(it.hasNext()) {
                    String key=it.next();
                    String fieldName=FieldUtils.UnderlineToHump(key);
                    Object value =map.get(key);
                    for(Field f:fields) {
                        if(fieldName.equals(f.getName())) {
                            f.setAccessible(true);
                            //需要转型
                            if(BigDecimal.class.toString().equals(value.getClass().toString())) {
                                Type type=f.getGenericType();
                                Class fieldClass =Class.forName(type.getTypeName());
                                Method method=fieldClass.getMethod("valueOf",String.class);
                                value=method.invoke(value, value.toString());
                                f.set(nt, value);
                            }else if(CLOB.class.toString().equals(value.getClass().toString())) {
                                f.set(nt, FieldUtils.ClobToString((CLOB)value));
                            }
                            else {
                                f.set(nt, value);
                            }
                            break;
                        }
                    }
                }
                resultList.add(nt);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        pageinfo.setList(resultList);
        return pageinfo;
    }

    @SuppressWarnings("unchecked")
    public <T> T selectOne(Class<?> cls,String tableName,Map<String,Object> params) {
        PageHelper.startPage(1, 1);
        Page<Map<String,Object>>  queryPage=mybaseDao.queryPageByParams(cls, tableName, params);
        PageInfo pageinfo =new PageInfo(queryPage);
        List<Map<String,Object>> queryResult = pageinfo.getList();
        List<T> resultList = new ArrayList<>();
        Field[] fields = cls.getDeclaredFields();
        T nt;
        for(int i=0;i<queryResult.size();i++)
        {
            try {
                nt=(T) cls.newInstance();
                Map<String,Object> map =queryResult.get(i);
                StringBuffer sb = new StringBuffer();
                Set<String> keys=map.keySet();
                Iterator<String> it =keys.iterator();
                while(it.hasNext()) {
                    String key=it.next();
                    String fieldName=FieldUtils.UnderlineToHump(key);
                    Object value =map.get(key);
                    for(Field f:fields) {
                        if(fieldName.equals(f.getName())) {
                            f.setAccessible(true);
                            //需要转型
                            if(BigDecimal.class.toString().equals(value.getClass().toString())) {
                                Type type=f.getGenericType();
                                Class fieldClass =Class.forName(type.getTypeName());
                                Method method=fieldClass.getMethod("valueOf",String.class);
                                value=method.invoke(value, value.toString());
                                f.set(nt, value);
                            }else if(CLOB.class.toString().equals(value.getClass().toString())) {
                                f.set(nt, FieldUtils.ClobToString((CLOB)value));
                            }
                            else {
                                f.set(nt, value);
                            }
                            break;
                        }
                    }
                }
                return nt;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

}

有了这个baseService 便可以和hibernate一样查询出来直接是想要的对象了

思考:由于大量使用反射会不会造成性能问题,而且是基于mybatis的二次封装相当于多了一倍的结果对象,会消耗一倍的内存。
根据POJO类生成数据库表也可以写一套简易的,以后有空再写。

最后编辑于
?著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,029评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,238评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事?!?“怎么了?”我有些...
    开封第一讲书人阅读 159,576评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,214评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,324评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,392评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,416评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,196评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,631评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,919评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,090评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,767评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,410评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,090评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,328评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,952评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,979评论 2 351

推荐阅读更多精彩内容