背景
在 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 目录下找到。
连上数据库后就可以选中要生成的表,鼠标右键即可看到。
代码说明
先拿 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.groovy
和 Generate Mappings.groovy
都是对 generate(table, dir) 和 generate(out, className, fields)
进行修改就可以。
需要注意的是三个 groovy 文件中有些属性需要手动进行修改,如 Generate Mappings.groovy
中的 basePackage,生成 dao 时类的后缀,实体类的位置,或者要继承的基础类等,需要按需进行适当修改。
示例代码上传 GitHub,你可以在这里找到:
https://github.com/DuanJiaNing/demos/tree/master/groovy-demo/resources/src