java 小工具 | 封裝通用的 Mybatis 生成模板 |1 秒寫完增刪改查

2021-02-19 java技術大本營
項目背景

前段時間我們介紹了如何使用thymeleaf去生成mybatis相關的模板:
https://www.lixiang.red/articles/2019/07/23/1563857782748.html
今天小刀和各位小夥伴們一起來深入下這個問題,我們來研究下怎麼去封裝一個通用的Mybatis模板,讓簡單的增刪改查操作,直接通過我們的代碼生成工具就能解決,讓工具從demo級別上升到生產可用的項目

mybatis簡單介紹

相信很多小夥伴都已經用過Mybatis了,很簡單方便, 在springboot的集成環境裡面,寫個DAO接口,加上註解,然後寫個xml和DAO關聯起來,然後xml裡面方法和DAO裡面的方法關聯起來,然後就可以通過調用DAO方法的形式來調用這個sql,並獲得相應的返回結果,代碼結構如圖下所示:

這是以往的方式,在新版Mybatis中,我們有了一個新的選擇,用java類和註解的方式去完成一個sql ,官方文檔如下:
http://www.mybatis.org/mybatis-3/statement-builders.html
寫法如下:

只建議簡單的sql用註解的方式去處理,複雜的還是要手寫sql , 可以重新建一個DAO , 或者在provider裡面用字符串拼接的方式去完成
具體用法,大家可以參考上面的官方文檔中的地址

設計封裝的方法封裝規則要求

我們總說,我們一直都在做重複的增刪改查工作,現在我們就可以把這些基本的操作都封裝起來,把更多的精力放在應用高可用,高響應,業務邏輯的梳理上面
因此 ,我們的封裝也是以增刪改查四大方向為主.
在封裝之前,我們先約定以下規定:
1.資料庫對應的實體對象,我們用DO(domain object)來表示
2.資料庫對應的查詢對應,我們用QC(query object)來表示
3.各種操作方法的命名,如,getModel,listModels,saveModels等等
這樣把資料庫實體對象和查詢對象分開,因為我們的在加查詢條件的時候,比如通過idList去查詢,如果在DO裡面新加欄位就不太好,所以抽象了一個QC的概念,專門做資料庫查詢對象。

從前到後的對應關係

為什麼我們項目可以用模板生成工具進行生成呢,大家仔細研究下手中的項目可以發現我們的項目從controller開始,到最後的DAO其實都是有名字對應起來的,我們以查詢為例: listItems,通過這個名字我們可以直觀的看到,是獲取商品列表的.
Controller中的代碼:

@GetMapping("/item/query")@ResponseBodypublic BaseResponse<PageData<ItemDO>> queryItem(ItemDO item, Integer pageIndex , Integer pageSize){
List<ItemDO> items = itemManager.queryItem(item, pageIndex, pageSize);Long totalCount = itemManager.countItem(item);
pageIndex = pageIndex == null?1:pageIndex; pageSize = pageSize == null?20:pageSize;return BaseResponse.assemblePageResponse(items,totalCount,pageIndex,pageSize);    }

模板:

@GetMapping("/[(${table.javaCamelName})]/query")    @ResponseBody    public BaseResponse<PageData<[(${table.javaTableName})]DO>> query[(${table.javaTableName})]([(${table.javaTableName})]DO [(${table.javaCamelName})], Integer pageIndex , Integer pageSize){
List<[(${table.javaTableName})]DO> [(${table.javaCamelName})]s = [(${table.javaCamelName})]Manager.query[(${table.javaTableName})]([(${table.javaCamelName})], pageIndex, pageSize); Long totalCount = [(${table.javaCamelName})]Manager.count[(${table.javaTableName})]([(${table.javaCamelName})]);
pageIndex = pageIndex == null?1:pageIndex; pageSize = pageSize == null?20:pageSize; return BaseResponse.assemblePageResponse([(${table.javaCamelName})]s,totalCount,pageIndex,pageSize);    }

Manager中的代碼:

public List<ItemDO> queryItem(ItemDO item, int pageIndex , int pageSize);

模板:

    public List<[(${table.javaTableName})]DO> query[(${table.javaTableName})]([(${table.javaTableName})]DO [(${table.javaCamelName})], int pageIndex , int pageSize);

ManagerImpl中的代碼:

@Overridepublic List<ItemDO> queryItem(ItemDO item, int pageIndex , int pageSize){        Page page = new Page(pageIndex,pageSize);        ItemQC qc  = new ItemQC();        qc.setPage(page);        BeanUtils.copyProperties(item,qc);        List<ItemDO> items = itemMapper.listItems(qc);return items;    }

模板:

@Override    public List<[(${table.javaTableName})]DO> query[(${table.javaTableName})]([(${table.javaTableName})]DO [(${table.javaCamelName})], int pageIndex , int pageSize){        Page page = new Page(pageIndex,pageSize);        [(${table.javaTableName})]QC qc  = new [(${table.javaTableName})]QC();        qc.setPage(page);        BeanUtils.copyProperties([(${table.javaCamelName})],qc);        List<[(${table.javaTableName})]> [(${table.javaCamelName})]s = [(${table.javaCamelName})]Mapper.list[(${table.javaTableName})]s(qc);return [(${table.javaCamelName})]s;    }

Mapper中的代碼:

@SelectProvider(type = ItemProvider.class)    List<ItemDO> listItems(ItemQC itemQC);

模板:

@SelectProvider(type = [(${table.javaTableName})]Provider.class)    List<[(${table.javaTableName})]DO> list[(${table.javaTableName})]s([(${table.javaTableName})]QC [(${table.javaCamelName})]QC);

Provider中的代碼:

public String listItems(ItemQC itemQC){        SQL sql = new SQL() {{            SELECT(TABLE_FIELDS);            FROM("item");        }};        MapperUtils.richWhereSql(sql, itemQC);
return sql.toString();    }

模板:

public String list[(${table.javaTableName})]s([(${table.javaTableName})]QC [(${table.javaCamelName})]QC){        SQL sql = new SQL() {{            SELECT(TABLE_FIELDS);            FROM("[(${table.javaCamelName})]");        }};        MapperUtils.richWhereSql(sql, [(${table.javaCamelName})]QC);
return sql.toString();    }

這樣我們從前到後看過來,發其實都是圍繞著一個關鍵詞在走: Item , 有時候把他變成大寫的,有時候把他變成駝峰命名,有時候把他加個DO後綴,有時候把他加個Mapper後綴.

生成文件到對應目錄中

在上篇文章中,我們只是生成了對應的字符串,但是在實際開發中,我們是需要生成文件的,最好是能在對應文件夾中.
所以這就有兩步,1是生成文件.2是找到對應文件夾

生成對應文件

生成文件這個應該是很簡單的,直接一句代碼搞定:

Files.write(Paths.get(pathMap.get("model")+tableInfo.getJavaTableName() + "DO.java"),model.getBytes());Files.write(Paths.get(pathMap.get("mapper")+tableInfo.getJavaTableName() + "Mapper.java"),dao.getBytes());Files.write(Paths.get(pathMap.get("provider")+tableInfo.getJavaTableName() + "Provider.java"),provider.getBytes());Files.write(Paths.get(pathMap.get("manager")+tableInfo.getJavaTableName() + "Manager.java"),manager.getBytes());Files.write(Paths.get(pathMap.get("managerImpl")+tableInfo.getJavaTableName() + "ManagerImpl.java"),managerImpl.getBytes());            Files.write(Paths.get(pathMap.get("controller")+tableInfo.getJavaTableName() + "Controller.java"),controller.getBytes());

輸出到對應文件夾中

這一步,就要我們明確,我們的每個文件是放在什麼地方在,如Mapper/Provider是查詢資料庫用的, 我們把他放在business-impl模塊中的dao文件夾中,下面小刀把自己項目中放的位置列出來和大家分享下,大家有好的想法可以一起交流:
XXXDO放在 business 模塊中 models.dos文件夾中
XXXController 放在admin 模塊中 controller 文件夾中
XXXManager 放在business模塊中 business文件夾中
XXXManagerImpl 放在business-impl模塊中 business.impl文件夾中
XXXMapper/XXXProvider 放在 business-impl模塊中 dao 文件夾中
這樣我們就可以用代碼去定位到對應的文件夾中了:

// 獲得當前項目的文件夾String currentDir  = System.getProperty("user.dir");            currentDir=currentDir.substring(0,currentDir.lastIndexOf("/"));            pathMap.put("model",currentDir);            pathMap.put("mapper",currentDir);            pathMap.put("provider",currentDir);            pathMap.put("manager",currentDir);            pathMap.put("managerImpl",currentDir);            pathMap.put("controller",currentDir);//如果設置了自動路徑,就YY一下路徑if(autoFilePath){                Files.list(Paths.get(currentDir)).forEach(file->{if(Files.isDirectory(file)){String fileName = file.toString();
if(fileName.endsWith("admin")){ pathMap.put("controller",fileName+"/src/main/java/"+packageName.replaceAll("\\.","/")+"/admin/controller/"); }if(fileName.endsWith("business")){ pathMap.put("model",fileName+"/src/main/java/"+packageName.replaceAll("\\.","/")+"/models/dos/"); pathMap.put("manager",fileName+"/src/main/java/"+packageName.replaceAll("\\.","/")+"/business/manager/"); }if(fileName.endsWith("business-impl")){ pathMap.put("managerImpl",fileName+"/src/main/java/"+packageName.replaceAll("\\.","/")+"/business/manager/impl/"+domainName+"/"); pathMap.put("mapper",fileName+"/src/main/java/"+packageName.replaceAll("\\.","/")+"/dao/"+domainName+"/"); pathMap.put("provider",fileName+"/src/main/java/"+packageName.replaceAll("\\.","/")+"/dao/"+domainName+"/"); } }
});            }

這樣我們就可以做到,把增刪改查從controller到dao直接一鍵生成到對應文件夾啦,只要把表建好,剩下的事就一步搞定啦

最後說兩句

這個工具一般是做後臺管理頁面,增刪改查的時候用, 業務邏輯不建議用工具類生成,業務邏輯一般是提供dubbo接口出來,不要直接把manager中的增刪改查提供出去,提供出去的一定是要先有業務,再有接口,然後在serviceImpl中調用manager去完成業務邏輯
大家有什麼想法,歡迎留言或者加小刀微信: best396975802

相關焦點

  • Java Mybatis CRUD增刪改查
    編寫接口package com.cy.dao;import com.cy.pojo.User;import java.util.List;public interface UserMapper { List<User> getUserList(); User getUserById(int id
  • Springboot+MybatisPlus高效實現增刪改查
    mybatis-plus-generator依賴:用於生成集成Mybatis-plus的代碼。freemarker依賴:因為生成代碼需要用到模板。mysql連接依賴:用於資料庫連接,生成代碼和資料庫操作時都需要該依賴。
  • 使用mybatis框架,完成增刪改查操作
    mybatis框架的繼續學習,安排如下:對昨天學習的內容做個小結,其中補充一個昨天忽視的問題。資料庫無外乎就是增刪改查,所以使用mybatis做一個完整的crud操作。1UserDao接口資料庫四大操作:增刪改查在dao層中編寫一個接口,包含這四種操作的方法,其中查詢有全表和單條查詢。
  • 老成FMS 5.0 發布:多處更新,通用的模板告別拷貝 jsp
    老成 FMS 5.0 版本除了修改以前版本的各種 bug 外,功能增強是最大特色增強 mybatis
  • 精講Mybatis框架對資料庫增刪改查操作
    有時候我們在某個網站註冊完一個帳號時,系統會生成一段ID或者用戶名,或帳號,這是怎麼做到的呢?請看下面的sql語句原來啊,在insert 內部還要一個selectKey選項。因為啊,在不同資料庫主鍵生成策略是不一樣的,mysql默認主鍵生成策略是在插入語句執行完成生成新的id,所以order要寫after在插入之後執行。如果設置主鍵為uuid或者oracle數據,他們的主鍵是在插入之前就已經存在了的,所以要使用before選項。但是插入記錄的ID是通過什麼形式返回給java程序的呢?
  • MyBatis學習--簡單的增刪改查(三)
    java類型和jdbc類型轉換,#{}可以有效防止sql注入。  3、添加用戶  映射文件: 1 <insert id="insertUser" parameterType="com.luchao.mybatis.first.po.User">2         <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer
  • Java程式設計師開發必備 MyBatis高級應用之逆向工程自動生成SQL語句
    MyBatis的一個主要的特點就是需要程式設計師自己編寫sql,那麼如果表太多的話,難免會很麻煩,所以mybatis官方提供了一個逆向工程,可以針對單表自動生成mybatis執行所需要的代碼,一般在開發中,常用的逆向工程方式是通過資料庫的表生成代碼。
  • 五大框架之MyBatis面試經常被問到的問題
    解決: Mybatis自動將java對象映射至sql語句。④ 對結果集解析麻煩,sql變化導致解析代碼變化,且解析前需要遍歷,如果能將資料庫記錄封裝成pojo對象解析比較方便。解決:Mybatis自動將sql執行結果映射至java對象。
  • 重學Java 設計模式:實戰代理模式「模擬mybatis-spring中定義DAO...
    使用過的一些中間件例如;RPC框架,在拿到jar包對接口的描述後,中間件會在服務啟動的時候生成對應的代理類,當調用接口的時候,實際是通過代理類發出的socket信息進行通過。另外像我們常用的MyBatis,基本是定義接口但是不需要寫實現類,就可以對xml或者自定義註解裡的sql語句進行增刪改查操作。
  • MyBatis-Plus為啥這麼牛?
    本文轉載自【微信公眾號:java進階架構師,ID:java_jiagoushi】經微信公眾號授權轉載,如需轉載與原文作者聯繫前言大家有用過MyBatis-Plus(簡稱MP)的都知道它是一個MyBatis的增強工具,旨在MyBatis的基礎上只做增強不做改變
  • Mybatis 通用 Mapper 3.5.0 發布
    MyBatis 通用 Mapper 極其方便的使用 MyBatis 單表的增刪改查,支持單表操作,不支持通用的多表聯合查詢。通用 Mapper 可以極大的方便開發人員。可以隨意的按照自己的需要選擇通用方法,還可以很方便的開發自己的通用方法。通用 Mapper 更新日誌兼容 mbg 1.3.6 版本。
  • mybatis源碼分析-反射基礎MetaClass
    1. WHAT我們知道mybatis是一個ORM(Object Relation Mapping)框架,既然是ORM框架,那麼資料庫與java的pojo之間的相互映射必然是其重要工作之一。而這兩者之間相互映射的實現手段就是反射,而MetaClass.java就是這樣一個反射工具類,幫我們封裝了在映射過程中需要用到的反射方法,並會去緩存這些我們經常使用到的數據2. WHYJDK已經為我們提供了所有反射的方法,那麼mybatis為什麼還要去二次封裝呢?
  • Mybatis_day01
    我們從前面的優化來看,以及將獲取連接、設置傳入參數、執行SQL語句、釋放資源這些都封裝起來了,只剩下結果處理這塊還沒有進行封裝,如果能封裝起來,每個資料庫操作都不用自己寫那麼一大堆Java代碼,直接調用一個封裝的方法就可以搞定了。
  • 寫了10年的代碼,我最怕寫Mybatis這些配置,現在有詳解了
    還好, mybatis 為我們提供了強大的代碼生成--MybatisGenerator。通過簡單的配置, 我們就可以生成各種類型的實體類, Mapper接口, MapperXML文件, Example對象等。通過這些生成的文件, 我們就可以方便的進行單表進行增刪改查的操作。
  • BeetlSQL 2.11.1 發布,Java Dao 工具
    @Override public String toSql(AbstractDBStyle dbStyle, String fieldName, String colName, Annotation an, TableDesc tableDesc){ return "jackson("+fieldName+")"; }BeetSql是一個全功能DAO工具
  • Mybatis 通用 Mapper 3.5.2 發布
    MyBatis 通用 Mapper 極其方便的使用 MyBatis 單表的增刪改查,支持單表操作,不支持通用的多表聯合查詢。通用 Mapper 可以極大的方便開發人員。可以隨意的按照自己的需要選擇通用方法,還可以很方便的開發自己的通用方法。
  • Java使用Freemarke模板生成Word文檔
    一、準備工作二、創建模板將Word模板中需要自動生成的地方用
  • MyBatis dynamic SQL 1.1.4 發布,生成動態 SQL 的框架
    MyBatis dynamic SQL 1.1.4 已發布,MyBatis Dynamic SQL 是生成動態 SQL 語句的框架,可把它看作是一個類型安全的 SQL 模板庫,它還支持 MyBatis3
  • springboot+jpa+thymeleaf實現信息增刪改查功能
    掃碼關注回復【增刪該查】獲取源碼如果你在運行這個代碼的過程中有遇到問題,請加小編微信xxf960513,我拉你進對應微信學習群!!幫助你快速掌握這個功能代碼!"今天", clear : "清除",        format : "yyyy-mm-dd", titleFormat : "yyyy MM", weekStart : 1 }; $('.date1').datepicker({ format: 'yyyy-mm-dd', language: 'cn