29

真会玩!竟然可以这样用IDEA通过数据库生成lombok版的POJO...

 3 years ago
source link: http://mp.weixin.qq.com/s?__biz=MzU2NjIzNDk5NQ%3D%3D&%3Bmid=2247490535&%3Bidx=1&%3Bsn=e66c1d324fb554a40f3bd31294a95e51
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

点击上方 匠心零度 ,选择“ 设为星标

做积极的人,而不是积极废人

y2UNjqN.jpg!web

作者: sisibeloved

来源:

https://juejin.im/post/5ca5d01f5188257e1d45707a

# 前言

最近写需求时需要新建许多新表,设计完表结构还要一一写成对应的 POJO,很麻烦,就 Google 了一下。网上相关资料不多,借鉴了一篇博客,并在其基础上进行了完善。

# 前置步骤

  1. 使用 IDEA 自带的插件 Database 连接数据库

  2. 在数据库的表上右键 Scripted Extensions -> Go to Scripts Directory

  3. 在打开的目录下放入脚本文件

# 源码

脚本用的 Groovy 语言,语法类似 Java,并能调用 Java 类库,自己修改也很方便。唯一的麻烦是执行入口在 Intellij 内部,想 debug 很麻烦。

PO 的路径一般都是统一的,如果要在新的模块中使用需要改一下路径。另外类注释需要替换成自己的。

还有一点需要注意的是枚举类型,脚本中将 tinyint 统一映射成了 Boolean 类型,如果要映射成自定义枚举类型,需要在实体类中自行修改。

用于生成带 Lombok 注释的实体类的脚本

Generate Lombok POJOs.groovy:

import com.intellij.database.model.DasTable

import com.intellij.database.util.Case

import com.intellij.database.util.DasUtil


import java.time.LocalDate


/*

* Available context bindings:

* SELECTION Iterable<DasObject>

* PROJECT project

* FILES files helper

*/


// 此处指定包路径,路径需要自行维护;

packageName = "com.xxx.xxx.entity;"

// 此处指定对应的类型映射,可按需修改,目前tinyint如果要映射到自定义枚举类型,只能手动修改

typeMapping = [

(~/(?i)bigint/) : "Long",

(~/(?i)int/) : "Integer",

(~/(?i)tinyint/) : "Boolean",

(~/(?i)float|double|decimal|real/): "BigDecimal",

(~/(?i)time|datetime|timestamp/) : "LocalDateTime",

(~/(?i)date/) : "LocalDate",

(~/(?i)/) : "String"

]


// 上面用到类和它的导入路径的之间的映射

importMap = [

"BigDecimal" : "java.math.BigDecimal",

"LocalDate" : "java.time.LocalDate",

"LocalDateTime" : "java.time.LocalDateTime",

]


// 导入路径列表,下面引用的时候会去重,也可以直接声明成一个 HashSet

importList = []


// 弹出选择文件的对话框

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) + "PO"

def fields = calcFields(table)

new PrintWriter(new OutputStreamWriter(new FileOutputStream(new File(dir, className + ".java")), "utf-8")).withPrintWriter { out -> generate(out, className, fields, table) }

}


// 从这里开始,拼实体类的具体逻辑代码

def generate(out, className, fields, table) {

out.println "package $packageName"

out.println ""

out.println ""

// 引入所需的包

out.println "import lombok.Data;"

out.println "import javax.persistence.Id;"

out.println "import javax.persistence.Table;"

out.println "import javax.persistence.GeneratedValue;"

// 去重后导入列表

importList.unique().each() { pkg ->

out.println "import " + pkg + ";"

}

out.println ""

// 添加类注释

out.println "/**"

// 如果添加了表注释,会加到类注释上

if (isNotEmpty(table.getComment())) {

out.println " * " + table.getComment()

}

out.println " *"

out.println " * @author xxx"

out.println " * @date " + LocalDate.now()

out.println " */"

// 添加类注解

out.println "@Data"

out.println "@Table(name = \"${table.getName()}\")"

out.println "public class $className {"

out.println ""

boolean isId = true

// 遍历字段,按下面的规则生成

fields.each() {

// 输出注释

if (isNotEmpty(it.comment)) {

out.println "\t/**"

out.println "\t * ${it.comment}"

out.println "\t */"

}

// 这边默认第一个字段为主键,实际情况大多数如此,遇到特殊情况可能需要手动修改

if (isId) {

out.println "\t@Id"

out.println "\t@GeneratedValue(generator = \"JDBC\")"

isId = false

}

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

out.println ""

}

out.println ""

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

if (importMap.containsKey(typeStr)) {

importList.add(importMap.get(typeStr))

}

fields += [[

name : javaName(col.getName(), false),

type : typeStr,

comment: col.getComment()

]]

}

}


def isNotEmpty(content) {

return content != null && content.toString().trim().length() > 0

}


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]

}

用于生成带 Lombok 注释并继承基类的实体类的脚本

Generate Lombok POJOs extend BaseEntity.groovy:

import com.intellij.database.model.DasTable

import com.intellij.database.util.Case

import com.intellij.database.util.DasUtil


import java.time.LocalDate


/*

* Available context bindings:

* SELECTION Iterable<DasObject>

* PROJECT project

* FILES files helper

*/


// 此处指定包路径,路径需要自行维护;

packageName = "com.xxx.xxx.entity;"

// 此处指定对应的类型映射,可按需修改,目前tinyint如果要映射到自定义枚举类型,只能手动修改

typeMapping = [

(~/(?i)bigint/) : "Long",

(~/(?i)int/) : "Integer",

(~/(?i)tinyint/) : "Boolean",

(~/(?i)float|double|decimal|real/): "BigDecimal",

(~/(?i)time|datetime|timestamp/) : "LocalDateTime",

(~/(?i)date/) : "LocalDate",

(~/(?i)/) : "String"

]


// 上面用到类和它的导入路径的之间的映射

importMap = [

"BigDecimal" : "java.math.BigDecimal",

"LocalDate" : "java.time.LocalDate",

"LocalDateTime" : "java.time.LocalDateTime",

]


// 导入路径列表,下面引用的时候会去重,也可以直接声明成一个 HashSet

importList = []


// 基类中已经有的属性,就无需在新生成的类中声明了

userTimeList = [

"create_user_id",

"update_user_id",

"create_time",

"update_time"

]


// 弹出选择文件的对话框

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) + "PO"

def writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(new File(dir, className + ".java")), "utf-8"))

def fields = calcFields(table)

writer.withPrintWriter { out -> generate(out, className, fields, table) }

}


// 从这里开始,拼实体类的具体逻辑代码

def generate(out, className, fields, table) {

out.println "package $packageName"

out.println ""

out.println ""

// 引入所需的包

out.println "import com.xxx.xxx.entity.BaseEntity;"

out.println "import lombok.Data;"

out.println "import lombok.EqualsAndHashCode;"

out.println "import java.io.Serializable;"

out.println "import javax.persistence.Id;"

out.println "import javax.persistence.Table;"

out.println "import javax.persistence.GeneratedValue;"

// 去重后导入列表

importList.unique().each() { pkg ->

out.println "import " + pkg + ";"

}

out.println ""

// 添加类注释

out.println "/**"

// 如果添加了表注释,会加到类注释上

if (isNotEmpty(table.getComment())) {

out.println " * " + table.getComment()

}

out.println " *"

out.println " * @author xxx"

out.println " * @date " + LocalDate.now()

out.println " */"

// 添加类注解

out.println "@Data"

out.println "@EqualsAndHashCode(callSuper = false)"

out.println "@Table(name = \"${table.getName()}\")"

out.println "public class $className extends BaseEntity implements Serializable {"

out.println ""

boolean isId = true

// 遍历字段,按下面的规则生成

fields.each() {

// 输出注释

if (isNotEmpty(it.comment)) {

out.println "\t/**"

out.println "\t * ${it.comment}"

out.println "\t */"

}

// 这边默认第一个字段为主键,实际情况大多数如此,遇到特殊情况可能需要手动修改

if (isId) {

out.println "\t@Id"

out.println "\t@GeneratedValue(generator = \"JDBC\")"

isId = false

}

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

out.println ""

}

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

// 如果是BaseTimeUserIdPO中已有的字段,则不再添加

if (!userTimeList.contains(col.getName())) {

// 如果是需要导入的类型,则往list里面添加

if (importMap.containsKey(typeStr)) {

importList.add(importMap.get(typeStr))

}

fields += [[

name : javaName(col.getName(), false),

type : typeStr,

dbType : col.getDataType(),

comment: col.getComment()

]]

} else {

fields += []

}

}

}


def isNotEmpty(content) {

return content != null && content.toString().trim().length() > 0

}


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]

}

# 使用方法

在 Database 中选中需要生成实体类的表(可以多选),右键 Scripted Extensions 选择需要执行的脚本,在弹出的对话框中选择生成文件的目标目录,OK。

# 参考资料

[1] idea通过数据库生成java实体类(lombok版)

如果觉得写的不错,请记得转发或者在看,这是对我最大的认可和鼓励!

END

如果读完觉得有收获的话,欢迎点【好看】,关注【匠心零度】,查阅更多精彩历史!!!

nmqYriz.gif

让我“ 好看 ”  bYreamJ.gif


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK