13 min read
TOC
[TOC]
逆向生成脚本在哪

说明:
图中2,选择表的时候支持多选,Very Good!
3就是执行脚步,会弹窗提示你保存到哪
4是定位到脚本路径,自定义的脚本就放这个目录下

测试Groovy脚步

建一个groovy console就可以测试脚本了,比如,我要测试字符串方法
str = "T_D_12"
str.startsWith("T_D_")
str.substring(4)
点击左上角运行按钮

输出结果

GeneratePojosWithLombok.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)number/) : "Long",
(~/(?i)int/) : "Integer",
(~/(?i)tinyint/) : "Boolean",
(~/(?i)float|double|decimal|real/): "BigDecimal",
(~/(?i)time|datetime|timestamp/) : "DateTime",
(~/(?i)date/) : "Date",
(~/(?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)
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;"
out.println "import tk.mybatis.mapper.annotation.KeySql;"
out.println "import cc.ewell.holisticnursing.product.enr.utils.CustomIdentityGenerator;"
// 去重后导入列表
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@KeySql(genId = CustomIdentityGenerator.class)"
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) {
if(str.startsWith("T_D_") || str.startsWith("T_C_")){
str = str.substring(4);//特殊表名前缀截取
}
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]
}
GenerateDaoXml.groovy
package src
import com.intellij.database.model.DasTable
import com.intellij.database.util.Case
import com.intellij.database.util.DasUtil
/*
* Available context bindings:
* SELECTION Iterable<DasObject>
* PROJECT project
* FILES files helper
*/
// entity(dto)、mapper(dao) 与数据库表的对应关系在这里手动指明,idea Database 窗口里只能选下列配置了的 mapper
// tableName(key) : [mapper(dao),entity(dto)]
typeMapping = [
(~/(?i)int/) : "INTEGER",
(~/(?i)float|double|decimal|real/): "DOUBLE",
(~/(?i)datetime|timestamp/) : "TIMESTAMP",
(~/(?i)date/) : "TIMESTAMP",
(~/(?i)time/) : "TIMESTAMP",
(~/(?i)/) : "VARCHAR"
]
basePackage = "com.chitic.bank.mapping" // 包名需手动填写
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 baseName = mapperName(table.getName(), true)
def fields = calcFields(table)
new File(dir, baseName + "Mapper.xml").withPrintWriter { out -> generate(table, out, baseName, fields) }
}
def generate(table, out, baseName, fields) {
def baseResultMap = 'BaseResultMap'
def base_Column_List = 'Base_Column_List'
def date = new Date().format("yyyy/MM/dd")
def tableName = table.getName()
def dao = basePackage + ".dao.${baseName}Mapper"
def to = basePackage + ".to.${baseName}TO"
out.println mappingsStart(dao)
out.println resultMap(baseResultMap, to, fields)
out.println sql(fields, base_Column_List)
out.println selectById(tableName, fields, baseResultMap, base_Column_List)
out.println deleteById(tableName, fields)
out.println delete(tableName, fields, to)
out.println insert(tableName, fields, to)
out.println update(tableName, fields, to)
out.println selectList(tableName, fields, to, base_Column_List, baseResultMap)
out.println mappingsEnd()
}
static def resultMap(baseResultMap, to, fields) {
def inner = ''
fields.each() {
inner += '\t\t<result column="' + it.sqlFieldName + '" jdbcType="' + it.type + '" property="' + it.name + '"/>\n'
}
return '''\t<resultMap id="''' + baseResultMap + '''" type="''' + to + '''">
<id column="id" jdbcType="INTEGER" property="id"/>
''' + inner + '''\t</resultMap>
'''
}
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 : mapperName(col.getName(), false),
sqlFieldName: col.getName(),
type : typeStr,
annos : ""]]
}
}
def mapperName(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]
}
// ------------------------------------------------------------------------ mappings
static def mappingsStart(mapper) {
return '''<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="''' + mapper + '''">
'''
}
// ------------------------------------------------------------------------ mappings
static def mappingsEnd() {
return '''</mapper>'''
}
// ------------------------------------------------------------------------ selectById
static def selectById(tableName, fields, baseResultMap, base_Column_List) {
return '''
<select id="selectById" parameterType="java.lang.Integer" resultMap="''' + baseResultMap + '''">
select
<include refid="''' + base_Column_List + '''"/>
from ''' + tableName + '''
where id = #{id}
</select>'''
}
// ------------------------------------------------------------------------ insert
static def insert(tableName, fields, parameterType) {
return '''
<insert id="insert" parameterType="''' + parameterType + '''">
insert into ''' + tableName + '''
<trim prefix="(" suffix=")" suffixOverrides=",">
''' + testNotNullStr(fields) + '''
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
''' + testNotNullStrSet(fields) + '''
</trim>
</insert>
'''
}
// ------------------------------------------------------------------------ update
static def update(tableName, fields, parameterType) {
return '''
<update id="update" parameterType="''' + parameterType + '''">
update ''' + tableName + '''
<set>
''' + testNotNullStrWhere(fields) + '''
</set>
where id = #{id}
</update>'''
}
// ------------------------------------------------------------------------ deleteById
static def deleteById(tableName, fields) {
return '''
<delete id="deleteById" parameterType="java.lang.Integer">
delete
from ''' + tableName + '''
where id = #{id}
</delete>'''
}
// ------------------------------------------------------------------------ delete
static def delete(tableName, fields, parameterType) {
return '''
<delete id="delete" parameterType="''' + parameterType + '''">
delete from ''' + tableName + '''
where 1 = 1
''' + testNotNullStrWhere(fields) + '''
</delete>'''
}
// ------------------------------------------------------------------------ selectList
static def selectList(tableName, fields, parameterType, base_Column_List, baseResultMap) {
return '''
<select id="selectList" parameterType="''' + parameterType + '''" resultMap="''' + baseResultMap + '''">
select
<include refid="''' + base_Column_List + '''"/>
from ''' + tableName + '''
where 1 = 1
''' + testNotNullStrWhere(fields) + '''
order by id desc
</select>'''
}
// ------------------------------------------------------------------------ sql
static def sql(fields, base_Column_List) {
def str = '''\t<sql id="''' + base_Column_List + '''">
@inner@
</sql> '''
def inner = ''
fields.each() {
inner += ('\t\t' + it.sqlFieldName + ',\n')
}
return str.replace("@inner@", inner.substring(0, inner.length() - 2))
}
static def testNotNullStrWhere(fields) {
def inner = ''
fields.each {
inner += '''
<if test="''' + it.name + ''' != null">
and ''' + it.sqlFieldName + ''' = #{''' + it.name + '''}
</if>\n'''
}
return inner
}
static def testNotNullStrSet(fields) {
def inner = ''
fields.each {
inner += '''
<if test="''' + it.name + ''' != null">
#{''' + it.name + '''},
</if>\n'''
}
return inner
}
static def testNotNullStr(fields) {
def inner1 = ''
fields.each {
inner1 += '''
<if test = "''' + it.name + ''' != null" >
\t''' + it.sqlFieldName + ''',
</if>\n'''
}
return inner1
}
GenerateDao.groovy
package src
import com.intellij.database.model.DasTable
import com.intellij.database.util.Case
import com.intellij.database.util.DasUtil
/*
* Available context bindings:
* SELECTION Iterable<DasObject>
* PROJECT project
* FILES files helper
*/
packageName = "**;" // 需手动配置 生成的 dao 所在包位置
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 baseName = javaName(table.getName(), true)
new File(dir, baseName + "Mapper.java").withPrintWriter { out -> generateInterface(out, baseName) }
}
def generateInterface(out, baseName) {
def date = new Date().format("yyyy/MM/dd")
out.println "package $packageName"
out.println "import cn.xx.entity.${baseName}Entity;" // 需手动配置
out.println "import org.springframework.stereotype.Repository;"
out.println ""
out.println "/**"
out.println " * Created on $date."
out.println " *"
out.println " * @author GX" // 可自定义
out.println " */"
out.println "@Repository"
out.println "public interface ${baseName}Dao extends BaseDao<${baseName}Entity> {" // 可自定义
out.println ""
out.println "}"
}
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]
}
生成JpaRepository.groovy
import com.intellij.database.model.DasTable
import com.intellij.database.model.ObjectKind
import com.intellij.database.util.Case
packageName = "com.gx.dao;"
packageEntityName = "com.gx.entity"
FILES.chooseDirectoryAndSave("Choose directory", "Choose where to store generated files") { dir ->
SELECTION.filter { it instanceof DasTable && it.getKind() == ObjectKind.TABLE }.each { generate(it, dir) }
}
def generate(table, dir) {
def entityName = javaName(table.getName(), true)
def className = entityName + "Repository"
new File(dir, className + ".java").withPrintWriter { out -> generate(out, table, className, entityName) }
}
def generate(out, table, className, entityName) {
out.println "package $packageName"
out.println ""
out.println "import org.springframework.stereotype.Repository;"
out.println "import org.springframework.data.jpa.repository.JpaRepository;"
out.println "import org.springframework.data.jpa.repository.JpaSpecificationExecutor;"
out.println ""
out.println "import $packageEntityName.$entityName;"
out.println ""
out.println "@Repository"
out.println "public interface $className extends JpaRepository<$entityName, Long>, JpaSpecificationExecutor<$entityName> {"
out.println ""
out.println "}"
}
def javaName(str, capitalize) {
def s = str.split(/(?<=[^\p{IsLetter}])/).collect { Case.LOWER.apply(it).capitalize() }
.join("").replaceAll(/[^\p{javaJavaIdentifierPart}]/, "_").replaceAll(/_/, "")
capitalize || s.length() == 1 ? s : Case.LOWER.apply(s[0]) + s[1..-1]
}
参考:

Kim
Time waits for no one.