1. 程式人生 > >idea + groovy + mybatis 自動生成 Dao、mappings 和 實體類

idea + groovy + mybatis 自動生成 Dao、mappings 和 實體類

背景

在 windows 系統中,idea 在 C:\Users\使用者名稱\.IntelliJIdea2018.2\config\extensions\com.intellij.database\schema 目錄下預設存在如下 Groovy 檔案:Generate POJOs.groovy,配合 idea 的 Database 資料庫管理工具,可以快速生成 POJO 類。

於是我想何不基於這個類編寫 groovy 程式碼自動生成 mappings 和 dao 呢,並按自己專案需要改造 Generate POJOs.groovy

Groovy

groovy 是在 java 平臺上的、具有象 Python,Ruby 和 Smalltalk 語言特性的靈活動態語言,groovy 保證了這些
特性象 java 語法一樣被 java 開發者使用。 – 《Groovy in action》

Groovy 跟 java 一樣是運行於 JVM 之上的語言,比起 java 擁有許多語法上的便利,可以無縫使用 java 類庫及其特性,甚至可以直接用 Groovy 開發 Web 程式。

推薦一個 Youtube 上一小時多的視訊,看完 Groovy 的大部分語法也就掌握了: Groovy Tutorial

實現

無論是修改 Generate POJOs.groovy 還是在其基礎之上編寫新的 groovy 檔案都需要將其放於C:\Users\使用者名稱\.IntelliJIdea2018.2\config\extensions\com.intellij.database\schema

目錄下,這樣檔案中引入的 com.intellij.database.* 才能找到,新建 idea 專案也會在 Scratches and Consoles 目錄下找到。
image.png
連上資料庫後就可以選中要生成的表,滑鼠右鍵即可看到。
image.png

程式碼說明

先拿 Generate POJOs.groovy 舉例進行說明,關鍵程式碼如下:

FILES.chooseDirectoryAndSave("Choose directory", "Choose where to store generated files") { dir ->
    SELECTION.filter { it instanceof
DasTable }.each { generate(it, dir) } } def generate(table, dir) { def className = javaName(table.getName(), true) def fields = calcFields(table) // 實體類字尾需要手動設定,這裡為 Entity new File(dir, className + "Entity.java").withPrintWriter { out -> generate(out, className + "Entity", fields) } } def generate(out, className, fields) { ... }

FILES.chooseDirectoryAndSave 是在 idea 的 Database 視窗滑鼠右鍵點選 groovy 選項後彈出資料夾選擇框關閉時回撥的方法,DasTable 指代一張表,儲存了該張表中的一些資訊,如表名,欄位等,dir 是選中的資料夾。

generate 方法會根據 table 和 dir 生成目標檔案。generate(out, className, fields) 方法是正真進行模板生成並寫入檔案的地方。

def generate(out, className, fields) {
    def date = new Date().format("yyyy/MM/dd")
    out.println "package $packageName"
    out.println "import java.io.Serializable;"
    out.println "import java.util.Date;"
    out.println ""
    out.println "/**"
    out.println " * Created on $date."
    out.println " *"
    out.println " * @author XX" // 可自定義
    out.println " */"
    out.println "public class $className implements Serializable {"
    out.println ""
    fields.each() {

        if (isNotEmpty(it.comment)) {
            out.println "\t/**"
            out.println "\t * ${it.comment}"
            out.println "\t */"
        }

        if (it.annos != "")
            out.println "\t${it.annos}"

        out.println "\tprivate ${it.type} ${it.name};"
        out.println ""

    }
    fields.each() {
        out.println ""
        out.println "\tpublic ${it.type} get${it.name.capitalize()}() {"
        out.println "\t\treturn ${it.name};"
        out.println "\t}"
        out.println ""
        out.println "\tpublic void set${it.name.capitalize()}(${it.type} ${it.name}) {"
        out.println "\t\tthis.${it.name} = ${it.name};"
        out.println "\t}"
    }
    out.println "}"
}

另外還有兩個方法是比較重要的:

def calcFields(table) {
    DasUtil.getColumns(table).reduce([]) { fields, col ->
        def spec = Case.LOWER.apply(col.getDataType().getSpecification())
        def typeStr = typeMapping.find { p, t -> p.matcher(spec).find() }.value
        fields += [[
                           comment: col.getComment(), // 表字段說明
                           name   : javaName(col.getName(), false), // 欄位名對應到 java 駝峰變數名
                           type   : typeStr, // 將資料庫欄位型別對映到 java 型別
                           annos  : ""]]
    }
}

def javaName(str, capitalize) {
    def s = com.intellij.psi.codeStyle.NameUtil.splitNameIntoWords(str)
            .collect { Case.LOWER.apply(it).capitalize() }
            .join("")
            .replaceAll(/[^\p{javaJavaIdentifierPart}[_]]/, "_")
    name = capitalize || s.length() == 1 ? s : Case.LOWER.apply(s[0]) + s[1..-1]
}

calcFields 方法會遍歷並取出 DasTable 中每一個欄位的屬性並放入 fields 中,fields 型別相當於 java 中一個元素型別為 Map 的 List。
javaName 將資料庫欄位名對映為駝峰風格的 java 變數名。

同理 Generate Dao.groovyGenerate Mappings.groovy 都是對 generate(table, dir) 和 generate(out, className, fields) 進行修改就可以。

需要注意的是三個 groovy 檔案中有些屬性需要手動進行修改,如 Generate Mappings.groovy 中的 basePackage,生成 dao 時類的字尾,實體類的位置,或者要繼承的基礎類等,需要按需進行適當修改。

示例程式碼上傳 GitHub,你可以在這裡找到: DuanJiaNing/demos/tree/master/groovy-demo/src/tools