idea自带groovy插件,可以通过groovy逆向生成java代码,优点是可以灵活配置,根据自己需求生成的模板,使用方法如下
第一步:IDEA配置数据库
配置方法这里不讲,配置结果如图
第二步:编写groovy脚本
脚本如下,生成内容可以根据自己的需求修改
import com.intellij.database.model.DasTable
import com.intellij.database.model.ObjectKind
import com.intellij.database.util.Case
import com.intellij.database.util.DasUtil
import com.intellij.psi.codeStyle.NameUtil
import java.io.*
import java.text.SimpleDateFormat
// 注释中作者
userName = "Li Chengjin"
// 表名如果以t_开头或者其他前缀,需要处理掉是改为true
isRemoveTableNamePrefix = false
// 默认包名
entityPackageName = "entity"
mapperPackageName = "mapper"
servicePackageName = "service"
serviceImplPackageName = "impl"
baseDirName =""
basePackageName = ""
baseClassName = ""
entityClassNamePO = ""
entityClassNameVO = ""
serviceClassName = ""
serviceImplClassName = ""
mapperClassName = ""
currentTime= new SimpleDateFormat("yyyy-MM-dd").format(new Date())
// 映射数据库字段
typeMapping = [
(~/(?i)int|tinyint|smallint|mediumint/) : "Integer",
(~/(?i)bool|bit/) : "Boolean",
(~/(?i)float|double|decimal|real/) : "Double",
(~/(?i)datetime|timestamp|date|time/) : "Date",
(~/(?i)blob|binary|bfile|clob|raw|image/): "InputStream",
(~/(?i)/) : "String"
]
// 选择框获取数据库表及java文件夹
FILES.chooseDirectoryAndSave("Choose directory", "Choose where to save the generate files !!!") {
dir ->
SELECTION
.filter { it instanceof DasTable && it.getKind() == ObjectKind.TABLE}
.each {
basePackageName = getPackageName(dir)
baseClassName = changeStrToCamelCase(it.getName(), true)
baseDirName = dir.toString()
// 生成实体类
generateEntityPO(it)
// 生成mapper
generateMapper()
// 生产mapper.xml
generateMapperXML()
// 生成service
generateService()
// 生成service实现类
generateServiceImpl()
}
}
// 生成Entity实体文件
def generateEntityPO(table) {
def fields = calcFields(table)
entityClassNamePO = "${baseClassName}PO"
entityClassNameVO = "${baseClassName}VO"
// 先创建文件夹
def entityDir = "${baseDirName}/${entityPackageName}"
def dirFile = new File(entityDir)
if (!dirFile.exists()) {
dirFile.mkdirs()
}
def filePO = new File(entityDir, "${entityClassNamePO}.java")
// 输出实体
new PrintWriter(new OutputStreamWriter(new FileOutputStream(filePO), "UTF-8"))
.withPrintWriter {
out -> generateEntityPOContent(out, fields, table)
}
def fileVO = new File(entityDir, "${entityClassNameVO}.java")
// 输出实体
new PrintWriter(new OutputStreamWriter(new FileOutputStream(fileVO), "UTF-8"))
.withPrintWriter {
out -> generateEntityVOContent(out, fields, table)
}
}
// 生成实体类内容
def generateEntityPOContent(out, fields, table) {
out.println "package ${basePackageName}.${entityPackageName};"
out.println ""
out.println "import com.baomidou.mybatisplus.annotation.IdType;"
out.println "import com.baomidou.mybatisplus.annotation.TableId;"
out.println "import com.baomidou.mybatisplus.annotation.TableField;"
out.println "import com.baomidou.mybatisplus.annotation.TableName;"
out.println "import java.io.Serializable;"
out.println "import lombok.Data;"
Set types = new HashSet()
fields.each() {
types.add(it.type)
}
if (types.contains("Date")) {
out.println "import java.util.Date;"
}
if (types.contains("InputStream")) {
out.println "import java.io.InputStream;"
}
out.println ""
out.println "/**\n" +
" * @Description \n" +
" * @author ${userName}\n" +
" * @Date ${currentTime}\n" +
" */"
out.println "@Data"
out.println "@TableName(value =\"${table.getName()}\")"
out.println "public class ${entityClassNamePO} implements Serializable {"
out.println genSerialID()
fields.each() {
out.println ""
// 输出注释
if (isNotEmpty(it.commoent)) {
out.println "\t/**"
out.println "\t * ${it.commoent.toString()}"
out.println "\t */"
}
// 输出注解
if ((it.annos + "").indexOf("[@Id]") >= 0) out.println "\t@TableId(type = IdType.AUTO)"
if (it.annos != "") out.println " ${it.annos.replace("[@Id]", "")}"
// 输出成员变量
out.println "\tprivate ${it.type} ${it.name};"
}
out.println ""
out.println "}"
}
// 生成实体类内容
def generateEntityVOContent(out, fields, table) {
out.println "package ${basePackageName}.${entityPackageName};"
out.println ""
out.println "import lombok.Data;"
Set types = new HashSet()
fields.each() {
types.add(it.type)
}
if (types.contains("Date")) {
out.println "import java.util.Date;"
}
if (types.contains("InputStream")) {
out.println "import java.io.InputStream;"
}
out.println ""
out.println "/**\n" +
" * @Description \n" +
" * @author ${userName}\n" +
" * @Date ${currentTime}\n" +
" */"
out.println "@Data"
out.println "public class ${entityClassNameVO} {"
fields.each() {
out.println ""
// 输出注释
if (isNotEmpty(it.commoent)) {
out.println "\t/**"
out.println "\t * ${it.commoent.toString()}"
out.println "\t */"
}
// 输出成员变量
out.println "\tprivate ${it.type} ${it.name};"
}
out.println ""
out.println "}"
}
// 生成Mapper文件
def generateMapper() {
mapperClassName = "${baseClassName}Mapper"
// 先创建文件夹
def mapperDir = "${baseDirName}/${mapperPackageName}"
def dirFile = new File(mapperDir)
if (!dirFile.exists()) {
dirFile.mkdirs()
}
def file = new File(mapperDir, "${mapperClassName}.java")
// 输出mapper
new PrintWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"))
.withPrintWriter {
out -> generateMapperContent(out)
}
}
// 生成Mapper内容
def generateMapperContent(out) {
out.println "package ${basePackageName}.${mapperPackageName};"
out.println ""
out.println "import org.apache.ibatis.annotations.Mapper;"
out.println "import com.baomidou.mybatisplus.core.mapper.BaseMapper;"
out.println "import ${basePackageName}.${entityPackageName}.${entityClassNamePO};"
out.println ""
out.println "/**\n" +
" * @Description \n" +
" * @author ${userName}\n" +
" * @Date ${currentTime}\n" +
" */"
out.println "@Mapper"
out.println "public interface ${mapperClassName} extends BaseMapper<${entityClassNamePO}> {\n" + "}"
}
// 生成mapper.xml
def generateMapperXML(){
def mapperDir = "${baseDirName}/${mapperPackageName}"
def dirFile = new File(mapperDir)
if (!dirFile.exists()) {
dirFile.mkdirs()
}
def file = new File(mapperDir, "${mapperClassName}.xml")
new PrintWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"))
.withPrintWriter {
out -> generateMapperXmlContent(out)
}
}
// 生成mapper.xml内容
def generateMapperXmlContent(out) {
out.println('<?xml version="1.0" encoding="UTF-8"?>');
out.println('<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">')
out.println("<mapper namespace=\"${basePackageName}.${mapperPackageName}.${mapperClassName}\">")
out.println('')
out.println('</mapper>')
}
// 生成 Service 文件
def generateService() {
serviceClassName = "${baseClassName}Service"
// 先创建文件夹
def serviceDir = "${baseDirName}/${servicePackageName}"
def dirFile = new File(serviceDir)
if (!dirFile.exists()) {
dirFile.mkdirs()
}
def file = new File(serviceDir, "${serviceClassName}.java")
PrintWriter printWriterMapper = new PrintWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"))
printWriterMapper.withPrintWriter { out -> generateServiceContent(out) }
}
// Service 文件具体生成逻辑
def generateServiceContent(out) {
out.println "package ${basePackageName}.${servicePackageName};"
out.println ""
out.println "import com.baomidou.mybatisplus.extension.service.IService;"
out.println "import ${basePackageName}.entity.${entityClassNamePO};"
out.println ""
out.println "/**\n" +
" * @Description \n" +
" * @author ${userName}\n" +
" * @Date ${currentTime}\n" +
" */"
out.println "public interface ${serviceClassName} extends IService<${entityClassNamePO}> {\n}"
}
// 生成 ServiceImpl 文件
def generateServiceImpl() {
serviceImplClassName = "${baseClassName}ServiceImpl"
// 先创建文件夹
def serviceImplDir = "${baseDirName}/${servicePackageName}/${serviceImplPackageName}"
def dirFile = new File(serviceImplDir)
if (!dirFile.exists()) {
dirFile.mkdirs()
}
def file = new File(serviceImplDir, "${serviceImplClassName}.java")
new PrintWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"))
.withPrintWriter {
out -> generateServiceImplContent(out)
}
}
// ServiceImpl 文件具体生成逻辑
def generateServiceImplContent(out) {
out.println "package ${basePackageName}.${servicePackageName}.${serviceImplPackageName};"
out.println ""
out.println "import lombok.extern.slf4j.Slf4j;"
out.println "import org.springframework.stereotype.Service;"
out.println "import org.springframework.transaction.annotation.Transactional;"
out.println "import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;"
out.println "import ${basePackageName}.${mapperPackageName}.${mapperClassName};"
out.println "import ${basePackageName}.${servicePackageName}.${serviceClassName};"
out.println "import ${basePackageName}.${entityPackageName}.${entityClassNamePO};"
out.println ""
out.println "/**\n" +
" * @Description \n" +
" * @Author ${userName}\n" +
" * @Date ${currentTime} \n" +
" */"
out.println "@Slf4j"
out.println "@Service"
out.println "@Transactional(rollbackFor = Exception.class)"
out.println "public class ${serviceImplClassName} extends ServiceImpl<${mapperClassName},${entityClassNamePO}> implements ${serviceClassName} {\n}"
}
// 获取包所在文件夹路径
def getPackageName(dir) {
return dir.toString().replaceAll("\\\\", ".").replaceAll("/", ".").replaceAll("^.*src(\\.main\\.java\\.)?", "")
}
// 读取表
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
def comm = [
colName : col.getName(),
name : changeStrToCamelCase(col.getName(), false),
type : typeStr,
commoent: col.getComment(),
annos : "\t@TableField(value = \"" + col.getName() + "\")"]
if ("id".equals(Case.LOWER.apply(col.getName())))
comm.annos += ["@Id"]
fields += [comm]
}
}
// 改变变量名风格,将变量或表名改为驼峰
def changeStrToCamelCase(String str, isCapitalize) {
def s = NameUtil.splitNameIntoWords(str)
.collect { Case.LOWER.apply(it).capitalize() }
.join("")
.replaceAll(/[^\p{javaJavaIdentifierPart}[_]]/, "_")
s = isRemoveTableNamePrefix ? s[1..s.size() - 1] : s
isCapitalize || s.length() == 1 ? s : Case.LOWER.apply(s[0]) + s[1..-1]
}
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;"
}
第三步:放置脚本
这一步主要是方便后续选择,也可以放在电脑固定的文件夹中,脚本放置位置如图
第四步:使用脚本
在需要逆向的表中右键点击,如图选择到刚才编写的脚本
点击后弹出选择框,这一步是选择生产文件的位置,选中文件后会在指定位置生成mapper,entity和service
通知提示生成成功
第五步:检查
代码逆向生成成功