自定義groovy腳本在IDEA中為數(shù)據(jù)庫生成PO實體類

自定義groovy腳本在IDEA中為數(shù)據(jù)庫生成PO實體類

在文章底部有完整的代碼實現(xiàn)

前言

我們可能會遇到下列這種問題:

公司的一個小項目,被拆分成了API和后臺管理兩個服務(wù),但是因為二者共用一個數(shù)據(jù)庫,所以存在著大量相同的數(shù)據(jù)庫實體定義.

因此我們不得不在這兩個服務(wù)中分別提供一樣的實體定義,當(dāng)我們的表結(jié)構(gòu)發(fā)生變更時,我們可能會忘記修改某一個項目中對應(yīng)的實體,久而久之,我們會發(fā)現(xiàn),某個項目中的某個實體對象和數(shù)據(jù)庫表定義相差甚遠.

這時候,我們就可以考慮拆出一個common項目用來存放二者公共的代碼,數(shù)據(jù)實體類作為一個不可變的對象,單獨維護在common項目中,并保證common中的實體對象和數(shù)據(jù)庫一一對應(yīng).

那么,我們需要手動的去為每個表建立相應(yīng)的實體類嗎?如果表結(jié)構(gòu)發(fā)生變化,我們還要手動去更改相應(yīng)的實體類嗎?

答案當(dāng)然是不,借助于IDEA的數(shù)據(jù)庫插件Database,我們可以通過提供一個groovy腳本來批量生成數(shù)據(jù)表對應(yīng)的實體類.

這樣,不僅簡化了代碼編寫,同時還能統(tǒng)一實體類的生成邏輯.

關(guān)于IDEA中腳本的使用方式參見文檔:Generate Java entity classes for tables and views

IDEA中本身為提供了一個名為Generate POJOs.groovy的腳本,該腳本可以完成簡單的代碼生成工作,但是,在實際業(yè)務(wù)中,我們的實體類除了屬性定義之外,往往還有一些其他的數(shù)據(jù)要定義在里面,比如:數(shù)據(jù)庫描述相關(guān)的注解.

自定義腳本實現(xiàn)

這里,我提供了一個簡單的自定義groovy腳本,通過該腳本,你可以完成包括自定義注解在內(nèi)的代碼生成工作.

基本屬性定義

腳本的最開始,定義了幾個開關(guān)用于控制腳本的行為,建議全部開啟:

// ============= 常量區(qū)域 =================
useLogicDelete = true; /* 啟用邏輯刪除 */
useLombok = true;/*是否啟用lombok*/
useSerializable = true;/*是否啟用實體序列化*/

再定義兩個Map集合,其中typeMapping負(fù)責(zé)將數(shù)據(jù)庫類型轉(zhuǎn)換為java類型,javaAliasMap則負(fù)責(zé)通過java類定義的簡短名稱獲取其全限定名稱:

/* 類型轉(zhuǎn)換 ,負(fù)責(zé)將數(shù)據(jù)庫類型轉(zhuǎn)換為java類型,轉(zhuǎn)換邏輯取自 mybatis */
typeMapping = [
        (~/(?i)real|decimal|numeric/)        : "BigDecimal",
        (~/(?i)bigint/)                      : "Long",
        (~/(?i)tinyint/)                     : "Byte", /* 根據(jù)自己的需求,可以考慮轉(zhuǎn)換為Boolean*/
        (~/(?i)int/)                         : "Integer",
        (~/(?i)enum/)                        : "String", /* 枚舉統(tǒng)一轉(zhuǎn)換為字符串*/
        (~/(?i)float|double/)                : "Double", /* 根據(jù)自己的需求可以考慮其他類型*/
        (~/(?i)datetime|timestamp|date|time/): "Date",
        (~/(?i)/)                            : "String" /*其余的統(tǒng)一轉(zhuǎn)成字符串*/
]


/* java 別名映射 ,負(fù)責(zé)導(dǎo)包*/
javaAliasMap = [
        "BigDecimal"  : "java.math.BigDecimal",
        "Date"        : "java.util.Date",
        "Getter"      : "lombok.Getter",
        "Setter"      : "lombok.Setter",
        "ToString"    : "lombok.ToString",
        "Serializable": "java.io.Serializable",
        "Table": "cn.jpanda.common.page.annotations.Table",
        "TableID": "cn.jpanda.common.page.annotations.TableID",
        "Column": "cn.jpanda.common.page.annotations.Column",
        "Logic": "cn.jpanda.common.page.annotations.Logic",
]

接著定義了三個生成實體類需要使用的屬性,他們負(fù)責(zé)記錄待生成實體類的部分關(guān)鍵信息:

// 代碼生成路徑,在腳本中通過彈出文件框進行選擇,同時會轉(zhuǎn)換為包名稱
String packageName = ""
/* 待引入的java類*/
importClass = [];
/* 待使用的類注解 */
usesAnnotations = [];

屬性比較簡單,上面都有注釋,這些屬性都是在后面運行時被賦值的.

腳本執(zhí)行入口

接下來就是腳本的真正入口:

/* 腳本入口 */
/* 選擇文件目錄 ,并執(zhí)行生成代碼操作 */
FILES.chooseDirectoryAndSave("Choose directory", "Choose where to store generated files") { dir ->
    SELECTION.filter { it instanceof DasTable }.each { generate(it, dir) }
}

該方法會彈出一個文件選擇框,供用戶選擇一個用來存放生成代碼的文件夾.

當(dāng)用戶完成選擇文件夾后,用戶選擇的數(shù)據(jù)庫表數(shù)據(jù)將會依次傳入到generate()方法中,用來生成相應(yīng)的實體對象.

為數(shù)據(jù)庫表生成對應(yīng)的實體類

通過一個table屬性生成相應(yīng)實體的邏輯比較簡單,大概有七步:

def generate(table, dir) {
    // step1: 獲取包名
    packageName = getPackageName(dir)
    // step2: 獲取當(dāng)前表名對應(yīng)的類名稱
    def className = javaName(table.getName(), true)
    // step3: 加載lombok注解
    if (useLombok) {
        ["Getter", "Setter", "ToString"].each() {
            convertAliasesAndImportClasses(it)
            usesAnnotations << it;
        };
    }
    // step4: 加載序列化
    if (useSerializable) {
        convertAliasesAndImportClasses("Serializable")
    }
    // step5: 加載自定義類注解
    loadCustomAnnotationToClass(table, className, dir);

    // step6: 處理所有數(shù)據(jù)列定義
    def properties = processDataColumnDefinition(table);

    // step7: 生成代碼
    new File(dir as File, className + ".java").withPrintWriter("utf-8") {
        out ->
            generate(out, className, properties, table)
    }
}

1.根據(jù)用戶選擇的目錄生成包名

 // step1: 獲取包名
packageName = getPackageName(dir)

static def getPackageName(dir) {
return dir.toString().replaceAll("\\\\", ".").replaceAll("/", ".").replaceAll("^.*src(\\.main\\.java\\.)?", "") + ";"
}

方法的實現(xiàn)并不復(fù)雜,默認(rèn)通過src/main/java目錄的子目錄層級結(jié)構(gòu)來生成包名稱.

2.將表明轉(zhuǎn)換為java類型名

 // step2: 獲取當(dāng)前表名對應(yīng)的類名稱
def className = javaName(table.getName(), true)

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

轉(zhuǎn)換規(guī)則并不復(fù)雜:下劃線轉(zhuǎn)駝峰,首字母大寫.

3.根據(jù)用戶開關(guān)加載lombok注解

if (useLombok) {
    ["Getter", "Setter", "ToString"].each() {
        convertAliasesAndImportClasses(it)
        usesAnnotations << it;
    };
}

convertAliasesAndImportClasses()方法是一個負(fù)責(zé)完成導(dǎo)包配置的工具方法:

void convertAliasesAndImportClasses(className) {
    def entry = javaAliasMap.find { p, t -> p.equalsIgnoreCase(className) };
    if (entry == null) {
        return;
    }
    def fullName = entry.value
    if (isNotEmpty(fullName)) {
        doImportClass(fullName);
    }
}

這里只簡單啟用了最常見的三個lombok注解,可以根據(jù)自己的需求,調(diào)整所需的注解.

4.根據(jù)序列化開關(guān)選擇是否啟用序列化

// step4: 加載序列化
if (useSerializable) {
    convertAliasesAndImportClasses("Serializable")
}

5.[擴展點]加載自定義類注解

// step5: 加載自定義類注解
loadCustomAnnotationToClass(table, className, dir);

void loadCustomAnnotationToClass(table, className, dir) {
// 根據(jù)自己的需求實現(xiàn),加載自定義的注解,比如JPA注解

}

loadCustomAnnotationToClass()方法定義在腳本底部,可以根據(jù)自己的需要來實現(xiàn).

6.預(yù)處理所有數(shù)據(jù)列定義

// step6: 處理所有數(shù)據(jù)列定義
def properties = processDataColumnDefinition(table);

def processDataColumnDefinition(table) {
    // 加載當(dāng)前數(shù)據(jù)庫主鍵
    def primaryKey = ""
    def prKey = DasUtil.getPrimaryKey(table);
    if (prKey != null) {
        def keyRef = prKey.getColumnsRef();
        if (keyRef != null) {
            def it = keyRef.iterate();
            while (it.hasNext()) {
                // 默認(rèn)只處理單主鍵
                primaryKey = it.next();
            }
            primaryKey = javaName(primaryKey, false);
        }
    }

    // 依次處理每一行數(shù)據(jù)列
    DasUtil.getColumns(table).reduce([]) { properties, col ->
        // 獲取JDBC類型
        def spec = Case.LOWER.apply(col.getDataType().getSpecification())
        // 將JDBC類型映射為JAVA類型
        def typeStr = typeMapping.find { p, t -> p.matcher(spec).find() }.value
        // 判斷該類型是否需要導(dǎo)包
        convertAliasesAndImportClasses(typeStr);
        // 將列名稱轉(zhuǎn)換為字段名稱
        def javaName = javaName(col.getName(), false);
        // 當(dāng)前列是否為主鍵
        def isPrimaryKey = javaName.equals(primaryKey);
        // 是否為邏輯刪除標(biāo)記
        def isLogicDeleteFlag = isLogicDelete(javaName);

        def property = [
                name   : javaName,
                colName: col.getName(),
                type   : typeStr,
                comment: col.getComment(),
                isKey  : isPrimaryKey,
                isDel  : isLogicDeleteFlag,
                annos  : []
        ]
        loadCustomAnnotationsToProperty(property);
        properties << property;
    }
}

processDataColumnDefinition()方法看起來實現(xiàn)比較復(fù)雜,但是實際上只是負(fù)責(zé)將數(shù)據(jù)列定義解析為下列數(shù)據(jù)結(jié)構(gòu):

def property = [
        name   : javaName,  /* java屬性名*/
        colName: col.getName(), /*jdbc列名*/
        type   : typeStr, /*java類型*/
        comment: col.getComment(),/*注釋*/
        isKey  : isPrimaryKey, /*是否為數(shù)據(jù)表主鍵*/
        isDel  : isLogicDeleteFlag, /*是否是邏輯刪除標(biāo)志*/
        annos  : [] /*需要添加的屬性注解*/
]

property有一個annos屬性,他的值是通過loadCustomAnnotationsToProperty()獲取的,這是另一個擴展點,用于加載自定義屬性注解,比如,我的簡單實現(xiàn)是:

void loadCustomAnnotationsToProperty(property) {
    // 根據(jù)自己的需求實現(xiàn),加載自定義屬性注解,比如這里,我使用了自定義的注解
    if (property.isDel) {
        convertAliasesAndImportClasses("Logic");
        property.annos << "Logic";
    }
    if (property.isKey) {
        convertAliasesAndImportClasses("TableID");
        property.annos << "TableID";
    }
    convertAliasesAndImportClasses("Column");
    property.annos << "Column";
}

7.生成代碼

// step7: 生成代碼
new File(dir as File, className + ".java").withPrintWriter("utf-8") {
    out ->
        generate(out, className, properties, table)
}

這一步是使用上面的數(shù)據(jù)來生成真正的代碼,實現(xiàn)很長,但是基本上都是用來處理前面獲取到的數(shù)據(jù)的:

// 生成實體類代碼
def generate(out, className, properties, table) {
    // step 1: 輸出包名
    out.println "package $packageName"
    out.println ""
    out.println ""
    // step2: 導(dǎo)入類
    importClass.each() {
        out.println "import ${it};"
    }
    out.println ""

    // 補充:生成注釋
    generateClassComments(out, table)

    // step3: 生成類注解
    usesAnnotations.each() {
        out.println "@${it}"
    }
    // step4: 生成類名
    out.print "public class $className"
    if (useSerializable) {
        out.println(" implements Serializable {")
        out.println ""
        /* 生成序列化ID*/
        out.println genSerialID()
    } else {
        out.println "{"
    }
    out.println ""
    // step5: 處理每個屬性定義
    properties.each() {
        // step5.1: 輸出注釋
        if (isNotEmpty(it.comment)) {
            out.println "\t/**"
            out.println "\t * ${it.comment}"
            out.println "\t */"
        }
        //step5.2: 輸出注解
        it.annos.each() {
            out.println "\t@${it}"
        }
        /*step5.3: 輸入字段內(nèi)容*/
        out.println "\tprivate ${it.type} ${it.name};"
    }

    // step6: 生成getter/setter方法
    if (!useLombok) {
        // 在未啟用lombok的情況下生成getter/setter方法
        properties.each() {
            out.println ""
            out.println "  public ${it.type} get${it.name.capitalize()}() {"
            out.println "    return ${it.name};"
            out.println "  }"
            out.println ""
            out.println "  public void set${it.name.capitalize()}(${it.type} ${it.name}) {"
            out.println "    this.${it.name} = ${it.name};"
            out.println "  }"
            out.println ""
        }
    }

    // step7: 結(jié)尾
    out.println "}"
}

generate()方法中,值得留意的是:

// 補充:生成注釋
generateClassComments(out, table)

這是方法的第三個擴展點,用于加載自定義類注釋,我的簡單實現(xiàn)是:

void generateClassComments(out, table) {
    /* 生成類注釋 */
    ["/**",
     " * ",
     " * ${table.getComment()}",
     " * @author Jpanda [Jpanda@aliyun.com]",
     " * @version 1.0",
     " * @since " + new SimpleDateFormat("yyyy-MM-dd").format(new Date()),
     " */"
    ].each() {
        out.println "${it}"
    }
}

上面就是腳本的基本思路了,腳本比較簡單,上面也有詳細的注釋,基本可以滿足使用.

使用腳本

下面是一個簡單的代碼生成示例.

涉及到的表結(jié)構(gòu):

create table user
(
    id         int auto_increment primary key,
    iphone     varchar(50)  not null comment '手機號',
    password   varchar(50)  not null comment '密碼',
    nikename   varchar(100) null comment '名字',
    group_flag int(1)       null comment '組標(biāo)識 0 店長 1 組長 2管理員'
)
    comment '用戶';

首先,我們把自定腳本放入IDEA的腳本執(zhí)行目錄下:

腳本執(zhí)行目錄

然后通過Database插件調(diào)用腳本:

使用腳本

選擇目錄:

選擇目錄

生成代碼:

package cn.jpanda.common.pojos.test;


import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.io.Serializable;
import cn.jpanda.common.page.annotations.TableID;
import cn.jpanda.common.page.annotations.Column;

/**
 * 
 * 用戶
 * @author Jpanda [Jpanda@aliyun.com]
 * @version 1.0
 * @since 2020-04-22
 */
@Getter
@Setter
@ToString
public class User implements Serializable {

 private static final long serialVersionUID =  2598051958746997471L;

 @TableID
 @Column
 private Integer id;
 /**
  * 手機號
  */
 @Column
 private String iphone;
 /**
  * 密碼
  */
 @Column
 private String password;
 /**
  * 名字
  */
 @Column
 private String nikename;
 /**
  * 組標(biāo)識 0 店長 1 組長 2管理員
  */
 @Column
 private Integer groupFlag;
}

完整代碼

下面給出完整的腳本代碼,需要根據(jù)自己的需求,調(diào)節(jié)自定義注解相關(guān)的數(shù)據(jù):

import com.intellij.database.model.DasTable
import com.intellij.database.util.Case
import com.intellij.database.util.DasUtil

import java.text.SimpleDateFormat

/*
 * Available context bindings:
 *   SELECTION   Iterable<DasObject>
 *   PROJECT     project
 *   FILES       files helper
 */

// ============= 常量區(qū)域 =================
useLogicDelete = true; /* 啟用邏輯刪除 */
useLombok = true;/*是否啟用lombok*/
useSerializable = true;/*是否啟用實體序列化*/

/* 類型轉(zhuǎn)換 ,負(fù)責(zé)將數(shù)據(jù)庫類型轉(zhuǎn)換為java類型,轉(zhuǎn)換邏輯取自 mybatis */
typeMapping = [
        (~/(?i)real|decimal|numeric/)        : "BigDecimal",
        (~/(?i)bigint/)                      : "Long",
        (~/(?i)tinyint/)                     : "Byte", /* 根據(jù)自己的需求,可以考慮轉(zhuǎn)換為Boolean*/
        (~/(?i)int/)                         : "Integer",
        (~/(?i)enum/)                        : "String", /* 枚舉統(tǒng)一轉(zhuǎn)換為字符串*/
        (~/(?i)float|double/)                : "Double", /* 根據(jù)自己的需求可以考慮其他類型*/
        (~/(?i)datetime|timestamp|date|time/): "Date",
        (~/(?i)/)                            : "String" /*其余的統(tǒng)一轉(zhuǎn)成字符串*/
]


/* java 別名映射 ,負(fù)責(zé)導(dǎo)包*/
javaAliasMap = [
        "BigDecimal"  : "java.math.BigDecimal",
        "Date"        : "java.util.Date",
        "Getter"      : "lombok.Getter",
        "Setter"      : "lombok.Setter",
        "ToString"    : "lombok.ToString",
        "Serializable": "java.io.Serializable",
        "Table"       : "cn.jpanda.common.page.annotations.Table",
        "TableID"     : "cn.jpanda.common.page.annotations.TableID",
        "Column"      : "cn.jpanda.common.page.annotations.Column",
        "Logic"       : "cn.jpanda.common.page.annotations.Logic",
]


/* =========  運行時屬性定義 ============*/
// 代碼生成路徑,在腳本中通過彈出文件框進行選擇
String packageName = ""
/* 待引入的java類*/
importClass = [];
/* 待使用注解 */
usesAnnotations = [];


/* 腳本入口 */
/* 選擇文件目錄 ,并執(zhí)行生成代碼操作 */
FILES.chooseDirectoryAndSave("Choose directory", "Choose where to store generated files") { dir ->
    SELECTION.filter { it instanceof DasTable }.each { generate(it, dir) }
}


def generate(table, dir) {
    // step1: 獲取包名
    packageName = getPackageName(dir)
    // step2: 獲取當(dāng)前表名對應(yīng)的類名稱
    def className = javaName(table.getName(), true)
    // step3: 加載lombok注解
    if (useLombok) {
        ["Getter", "Setter", "ToString"].each() {
            convertAliasesAndImportClasses(it)
            usesAnnotations << it;
        };
    }
    // step4: 加載序列化
    if (useSerializable) {
        convertAliasesAndImportClasses("Serializable")
    }
    // step5: 加載自定義類注解
    loadCustomAnnotationToClass(table, className, dir);

    // step6: 處理所有數(shù)據(jù)列定義
    def properties = processDataColumnDefinition(table);

    // step7: 生成代碼
    new File(dir as File, className + ".java").withPrintWriter("utf-8") {
        out ->
            generate(out, className, properties, table)
    }
}


// 生成實體類代碼
def generate(out, className, properties, table) {
    // step 1: 輸出包名
    out.println "package $packageName"
    out.println ""
    out.println ""
    // step2: 導(dǎo)入類
    importClass.each() {
        out.println "import ${it};"
    }
    out.println ""

    // 補充:生成注釋
    generateClassComments(out, table)

    // step3: 生成類注解
    usesAnnotations.each() {
        out.println "@${it}"
    }
    // step4: 生成類名
    out.print "public class $className"
    if (useSerializable) {
        out.println(" implements Serializable {")
        out.println ""
        /* 生成序列化ID*/
        out.println genSerialID()
    } else {
        out.println "{"
    }
    out.println ""
    // step5: 處理每個屬性定義
    properties.each() {
        // step5.1: 輸出注釋
        if (isNotEmpty(it.comment)) {
            out.println "\t/**"
            out.println "\t * ${it.comment}"
            out.println "\t */"
        }
        //step5.2: 輸出注解
        it.annos.each() {
            out.println "\t@${it}"
        }
        /*step5.3: 輸入字段內(nèi)容*/
        out.println "\tprivate ${it.type} ${it.name};"
    }

    // step6: 生成getter/setter方法
    if (!useLombok) {
        // 在未啟用lombok的情況下生成getter/setter方法
        properties.each() {
            out.println ""
            out.println "  public ${it.type} get${it.name.capitalize()}() {"
            out.println "    return ${it.name};"
            out.println "  }"
            out.println ""
            out.println "  public void set${it.name.capitalize()}(${it.type} ${it.name}) {"
            out.println "    this.${it.name} = ${it.name};"
            out.println "  }"
            out.println ""
        }
    }

    // step7: 結(jié)尾
    out.println "}"
}

def processDataColumnDefinition(table) {
    // 加載當(dāng)前數(shù)據(jù)庫主鍵
    def primaryKey = ""
    def prKey = DasUtil.getPrimaryKey(table);
    if (prKey != null) {
        def keyRef = prKey.getColumnsRef();
        if (keyRef != null) {
            def it = keyRef.iterate();
            while (it.hasNext()) {
                // 默認(rèn)只處理單主鍵
                primaryKey = it.next();
            }
            primaryKey = javaName(primaryKey, false);
        }
    }

    // 依次處理每一行數(shù)據(jù)列
    DasUtil.getColumns(table).reduce([]) { properties, col ->
        // 獲取JDBC類型
        def spec = Case.LOWER.apply(col.getDataType().getSpecification())
        // 將JDBC類型映射為JAVA類型
        def typeStr = typeMapping.find { p, t -> p.matcher(spec).find() }.value
        // 判斷該類型是否需要導(dǎo)包
        convertAliasesAndImportClasses(typeStr);
        // 將列名稱轉(zhuǎn)換為字段名稱
        def javaName = javaName(col.getName(), false);
        // 當(dāng)前列是否為主鍵
        def isPrimaryKey = javaName.equals(primaryKey);
        // 是否為邏輯刪除標(biāo)記
        def isLogicDeleteFlag = isLogicDelete(javaName);

        def property = [
                name   : javaName,  /* java屬性名*/
                colName: col.getName(), /*jdbc列名*/
                type   : typeStr, /*java類型*/
                comment: col.getComment(),/*注釋*/
                isKey  : isPrimaryKey, /*是否為數(shù)據(jù)表主鍵*/
                isDel  : isLogicDeleteFlag, /*是否是邏輯刪除標(biāo)志*/
                annos  : [] /*需要添加的屬性注解*/
        ]
        loadCustomAnnotationsToProperty(property);
        properties << property;
    }
}

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

static def isNotEmpty(content) {
    return content != null && content.toString().trim().length() > 0
}

static String genSerialID() {
    return "\tprivate static final long serialVersionUID =  " + Math.abs(new Random().nextLong()) + "L;"
}
// 生成包名
static def getPackageName(dir) {
    return dir.toString().replaceAll("\\\\", ".").replaceAll("/", ".").replaceAll("^.*src(\\.main\\.java\\.)?", "") + ";"
}

/**
 * 判斷一個java屬性是否為邏輯刪除
 * [根據(jù)自己的需求重構(gòu)該測試]
 * @param property 屬性名稱
 * @return
 */
boolean isLogicDelete(property) {
    return useLogicDelete && property.equalsIgnoreCase("DeleteFlag") || property.equalsIgnoreCase("DelFlag")
}

/**
 * 導(dǎo)入lombok的類
 */
void importLombokPackage() {
    if (useLombok) {
        ["lombok.Getter", "lombok.Setter", "lombok.ToString"].each() {
            doImportClass(it);
        };
    }
}

/**
 * 導(dǎo)入一個包名稱
 * @param className
 */
void doImportClass(className) {
    if (importClass.count { it -> it.equalsIgnoreCase(className) } == 0) {
        importClass << className;
    }
}

void convertAliasesAndImportClasses(className) {
    def entry = javaAliasMap.find { p, t -> p.equalsIgnoreCase(className) };
    if (entry == null) {
        return;
    }
    def fullName = entry.value
    if (isNotEmpty(fullName)) {
        doImportClass(fullName);
    }
}

void loadCustomAnnotationToClass(table, className, dir) {
    // 根據(jù)自己的需求實現(xiàn),加載自定義的注解,比如JPA注解

}

void loadCustomAnnotationsToProperty(property) {
    // 根據(jù)自己的需求實現(xiàn),加載自定義屬性注解,比如這里,我使用了自定義的注解
    if (property.isDel) {
        convertAliasesAndImportClasses("Logic");
        property.annos << "Logic";
    }
    if (property.isKey) {
        convertAliasesAndImportClasses("TableID");
        property.annos << "TableID";
    }
    convertAliasesAndImportClasses("Column");
    property.annos << "Column";
}

void generateClassComments(out, table) {
    /* 生成類注釋 */
    ["/**",
     " * ",
     " * ${table.getComment()}",
     " * @author Jpanda [Jpanda@aliyun.com]",
     " * @version 1.0",
     " * @since " + new SimpleDateFormat("yyyy-MM-dd").format(new Date()),
     " */"
    ].each() {
        out.println "${it}"
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末劫灶,一起剝皮案震驚了整個濱河市冰蘑,隨后出現(xiàn)的幾起案子厌秒,更是在濱河造成了極大的恐慌,老刑警劉巖汉形,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纸镊,死亡現(xiàn)場離奇詭異,居然都是意外死亡获雕,警方通過查閱死者的電腦和手機薄腻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來届案,“玉大人庵楷,你說我怎么就攤上這事。” “怎么了尽纽?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵咐蚯,是天一觀的道長。 經(jīng)常有香客問我弄贿,道長春锋,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任差凹,我火速辦了婚禮期奔,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘危尿。我一直安慰自己呐萌,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布谊娇。 她就那樣靜靜地躺著肺孤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪济欢。 梳的紋絲不亂的頭發(fā)上赠堵,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天,我揣著相機與錄音法褥,去河邊找鬼茫叭。 笑死,一個胖子當(dāng)著我的面吹牛挖胃,可吹牛的內(nèi)容都是我干的杂靶。 我是一名探鬼主播,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼酱鸭,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了垛吗?” 一聲冷哼從身側(cè)響起凹髓,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎怯屉,沒想到半個月后蔚舀,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡锨络,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年赌躺,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片羡儿。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡礼患,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情缅叠,我是刑警寧澤悄泥,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站肤粱,受9級特大地震影響弹囚,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜领曼,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一鸥鹉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧庶骄,春花似錦毁渗、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至幻碱,卻和暖如春绎狭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背褥傍。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工儡嘶, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人恍风。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓蹦狂,卻偏偏與公主長得像,于是被迫代替她去往敵國和親朋贬。 傳聞我的和親對象是個殘疾皇子凯楔,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,044評論 2 355

推薦閱讀更多精彩內(nèi)容