百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分类 > 正文

IDEA不愧为神器,结合Groovy脚本,简直无敌

ztj100 2025-02-08 13:56 18 浏览 0 评论

导语

如今,有许许多多的插件或者编辑器都支持根据数据表自动生成数据实体类了, 比如IDEA, 各种MyBatis的代码生成工具, 等等. 本篇介绍一下如何使用IDEA的groovy脚本文件生成带JPA注解的实体类

一, 使用IDEA连接数据库

需注意:

正式版IDEA才有此功能, 社区版本有演示图片使用的IDEA版本为2018.3, 不同版本界面可能有细小差别

创建新的数据连接

  • 如果没有, 可以上方菜单栏: 视图-工具窗口-Database打开
  • 新建Oracle数据库也是相同操作

配置数据连接

  • 填写一个连接名,随便填什么都行
  • 不用选择,默认就行
  • 填写数据库连接的 IP地址,比如本地数据库可以填写:localhost或者127.0.0.1
  • 填写数据库开放的端口号,一般没设置的话默认都是3306
  • 填写你需要连接的数据库名
  • 填写数据库的用户名
  • 填写数据库密码
  • 这里会有一个驱动需要点击下载,图中是已经下载好了
  • 填写自己的数据库连接url,然后可以点击9所在按钮进行测试连接,本地连接失败检查是否开启了mysql服务

二, IDEA自带的两种创建实体类的方法

(1), 如果只是创建简单的, 只有属性, getter, setter的实体类, 而不需要JPA/Hibernate的实体类注解

  • 单击打开刚刚创建的数据连接
  • 打开schemas, 找到自己需要创建实体类的表(可以使用ctrl或shift多选)
  • 右键: Scripted Extensions - Generate POJOs.groovy
  • 选择生成路径就OK了

需注意

生成的包名可能有问题, 默认是package com.sample, 需要自己手动修改

(2), 使用了Hibernate/Jpa框架, 需要的是有注解的实体类, Idea也提供了相应的方法

推荐:100期面试题汇总

添加JPA模块

  • 打开项目结构
  • 打开模块, 点击+号添加模块
  • 选择JPA
  • 点击右下角确定后, 关闭项目结构

使用Persistence工具生成带注解的实体类-1

  • 如果上一步没问题的话, IDEA左下角侧边栏会出现Persistence工具栏
  • 打开Persistence工具栏, 右键项目: Generate Persistence Mapping - By Database Schema

使用Persistence工具生成带注解的实体类-2

  • 选择数据库连接
  • 选择生成类所在包
  • 选择要生成的表
  • 选择要生成的字段(选择表后字段默认除了外键全选)
  • 修改要生成的属性名
  • 修改要生成的属性类型
  • 勾上即为生成带注解的实体类

生成的类实例如下

三, 更进一步, 使用自己的Groovy生成带注解的实体类

上面介绍了两个使用IDEA生成实体类的方法, 各有优缺点

  • 生成不带注解的实体类简单高效, 但缺点就是如果使用的是Jpa/Hibernate框架就不适合
  • 生成带注解的实体类能生成注解实体类, 但缺点就是生成的实体类的注解可能不太符合我们的注解, 只能生成到当前项目包下, 面对一些复杂的数据库如Oracle会显示很多系统表而且表空间切换不太方便

我们知道Idea生成不带注解的实体类是通过Groovy脚本文件生成的, 我们也能找到这个文件, 那我们能不能修改这个文件, 让它生成带注解的实体类呢?

(1), 使用自己的Groovy生成带注解的实体类的好处

  • 在Database工具栏里, 操作简单方便
  • 可以自己对脚本进行一些编辑, 使生成的实体类达到自己的定制需求
  • 对Oracle这样的数据库生成实体类时, 避免了系统表的影响, 可以自己选择表空间进行操作
  • 可以生成在电脑上的任何位置, 不受限制

(2), 使用自己的Groovy生成带注解的实体类的不足

  • @author 作者名需要自己修改脚本
  • @Table(Schema="") 的表空间名不能读取, 需要自己修改脚本, 设定表空间名(mysql可以直接删除这个属性的定义)(IDEA的Persistence工具可以读取(Schema=""属性并生成, 但我们不知道它是怎么获取的)
  • @Id的主键生成方式不可知, 需要生成后自己确定(mysql用户可以直接修改脚本设定主键生成方式, 但Oracle用户需要生成实体类后再逐个确认)

(3), 使用自己的Groovy生成带注解的实体类可以继续完善的地方

1, 如果需要hashcode()和equals()方法, 也修改脚本, 使其自动生成

(4), 新建一个Groovy脚本文件

Database工具栏里, 右键右键: Scripted Extensions - Go to Scripts Directory

在目录下新建一个Generate MyPOJOs.groovy

添加里面的内容

  1. 修改idea为自己名字 的地方可以修改作者名字为自己的
  2. schema = \"后面添加自己的表空间名称(mysql可以不添加, 不用这个schema属性也行) 这里可以根据提示修改
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?java.text.SimpleDateFormat

/*
?*?Available?context?bindings:
?*???SELECTION???Iterable
?*???PROJECT?????project
?*???FILES???????files?helper
?*/
packageName?=?""
typeMapping?=?[
????????(~/(?i)tinyint|smallint|mediumint/)??????:?"Integer",
????????(~/(?i)int/)?????????????????????????????:?"Long",
????????(~/(?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"
]


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?className?=?javaName(table.getName(),?true)
????def?fields?=?calcFields(table)
????packageName?=?getPackageName(dir)
????PrintWriter?printWriter?=?new?PrintWriter(new?OutputStreamWriter(new?FileOutputStream(new?File(dir,?className?+?".java")),?"UTF-8"))
????printWriter.withPrintWriter?{?out?->?generate(out,?className,?fields,?table)?}

//????new?File(dir,?className?+?".java").withPrintWriter?{?out?->?generate(out,?className,?fields,table)?}
}

//?获取包所在文件夹路径
def?getPackageName(dir)?{
????return?dir.toString().replaceAll("\\\\",?".").replaceAll("/",?".").replaceAll("^.*src(\\.main\\.java\\.)?",?"")?+?";"
}

def?generate(out,?className,?fields,?table)?{
????out.println?"package?$packageName"
????out.println?""
????out.println?"import?javax.persistence.Column;"
????out.println?"import?javax.persistence.Entity;"
????out.println?"import?javax.persistence.Table;"
????out.println?"import?javax.persistence.Id;"
????out.println?"import?javax.persistence.GeneratedValue;"
????out.println?"import?java.io.Serializable;"
????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??idea\n"?+?//1.?修改idea为自己名字
????????????"?*?@Date?"?+?new?SimpleDateFormat("yyyy-MM-dd").format(new?Date())?+?"?\n"?+
????????????"?*/"
????out.println?""
????out.println?"@Entity"
????out.println?"@Table?(?name?=\""?+?table.getName()?+?"\"?,?schema?=?\"\")"?//2.?schema?=?\"后面添加自己的表空间名称(mysql可以不添加,?不用这个schema属性也行)
????out.println?"public?class?$className??implements?Serializable?{"
????out.println?""
????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@Id"

????????if?(it.annos?!=?"")?out.println?"???${it.annos.replace("[@Id]",?"")}"


????????//?输出成员变量
????????out.println?"\tprivate?${it.type}?${it.name};"
????}

????//?输出get/set方法
????fields.each()?{
????????out.println?""
????????out.println?"\tpublic?${it.type}?get${it.name.capitalize()}()?{"
????????out.println?"\t\treturn?this.${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}"
????}

????//?输出toString方法
????out.println?""
????out.println?"\t@Override"
????out.println?"\tpublic?String?toString()?{"
????out.println?"\t\treturn?\"TpApiConfig{\"?+"
????fields.each()?{
????????out.println?"\t\t\t\t\"${it.name}='\"?+?${it.name}?+?'\\''?+"
????}
????out.println?"\t\t\t\t'}';"
????out.println?"\t}"

????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
????????def?comm?=?[
????????????????colName?:?col.getName(),
????????????????name????:?javaName(col.getName(),?false),
????????????????type????:?typeStr,
????????????????commoent:?col.getComment(),
????????????????annos???:?"\t@Column(name?=?\""?+?col.getName()?+?"\"?)"]
????????if?("id".equals(Case.LOWER.apply(col.getName())))
????????????comm.annos?+=?["@Id"]
????????fields?+=?[comm]
????}
}

//?已经修改为使用javaName,?如果有需要可以在def?className?=?javaName(table.getName(),?true)中修改为javaClassName
//?处理类名(这里是因为我的表都是以t_命名的,所以需要处理去掉生成类名时的开头的T,
//?如果你不需要那么请查找用到了?javaClassName这个方法的地方修改为?javaName?即可)
def?javaClassName(str,?capitalize)?{
????def?s?=?com.intellij.psi.codeStyle.NameUtil.splitNameIntoWords(str)
????????????.collect?{?Case.LOWER.apply(it).capitalize()?}
????????????.join("")
????????????.replaceAll(/[^\p{javaJavaIdentifierPart}[_]]/,?"_")
????//?去除开头的T??http://developer.51cto.com/art/200906/129168.htm
????s?=?s[1..s.size()?-?1]
????capitalize?||?s.length()?==?1???s?:?Case.LOWER.apply(s[0])?+?s[1..-1]
}

def?javaName(str,?capitalize)?{
//????def?s?=?str.split(/(?<=[^\p{IsLetter}])/).collect?{?Case.LOWER.apply(it).capitalize()?}
//????????????.join("").replaceAll(/[^\p{javaJavaIdentifierPart}]/,?"_")
//????capitalize?||?s.length()?==?1??s?:?Case.LOWER.apply(s[0])?+?s[1..-1]
????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]
}

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

static?String?changeStyle(String?str,?boolean?toCamel)?{
????if?(!str?||?str.size()?<=?1)
????????return?str

????if?(toCamel)?{
????????String?r?=?str.toLowerCase().split('_').collect?{?cc?->?Case.LOWER.apply(cc).capitalize()?}.join('')
????????return?r[0].toLowerCase()?+?r[1..-1]
????}?else?{
????????str?=?str[0].toLowerCase()?+?str[1..-1]
????????return?str.collect?{?cc?->?((char)?cc).isUpperCase()???'_'?+?cc.toLowerCase()?:?cc?}.join('')
????}
}

static?String?genSerialID()?{
????return?"\tprivate?static?final?long?serialVersionUID?=??"?+?Math.abs(new?Random().nextLong())?+?"L;"
}

表上右键, 选择自己写的脚本生成实体类

效果如下:

相关推荐

其实TensorFlow真的很水无非就这30篇熬夜练

好的!以下是TensorFlow需要掌握的核心内容,用列表形式呈现,简洁清晰(含表情符号,<300字):1.基础概念与环境TensorFlow架构(计算图、会话->EagerE...

交叉验证和超参数调整:如何优化你的机器学习模型

准确预测Fitbit的睡眠得分在本文的前两部分中,我获取了Fitbit的睡眠数据并对其进行预处理,将这些数据分为训练集、验证集和测试集,除此之外,我还训练了三种不同的机器学习模型并比较了它们的性能。在...

机器学习交叉验证全指南:原理、类型与实战技巧

机器学习模型常常需要大量数据,但它们如何与实时新数据协同工作也同样关键。交叉验证是一种通过将数据集分成若干部分、在部分数据上训练模型、在其余数据上测试模型的方法,用来检验模型的表现。这有助于发现过拟合...

深度学习中的类别激活热图可视化

作者:ValentinaAlto编译:ronghuaiyang导读使用Keras实现图像分类中的激活热图的可视化,帮助更有针对性...

超强,必会的机器学习评估指标

大侠幸会,在下全网同名[算法金]0基础转AI上岸,多个算法赛Top[日更万日,让更多人享受智能乐趣]构建机器学习模型的关键步骤是检查其性能,这是通过使用验证指标来完成的。选择正确的验证指...

机器学习入门教程-第六课:监督学习与非监督学习

1.回顾与引入上节课我们谈到了机器学习的一些实战技巧,比如如何处理数据、选择模型以及调整参数。今天,我们将更深入地探讨机器学习的两大类:监督学习和非监督学习。2.监督学习监督学习就像是有老师的教学...

Python教程(三十八):机器学习基础

...

Python 模型部署不用愁!容器化实战,5 分钟搞定环境配置

你是不是也遇到过这种糟心事:花了好几天训练出的Python模型,在自己电脑上跑得顺顺当当,一放到服务器就各种报错。要么是Python版本不对,要么是依赖库冲突,折腾半天还是用不了。别再喊“我...

超全面讲透一个算法模型,高斯核!!

...

神经网络与传统统计方法的简单对比

传统的统计方法如...

AI 基础知识从0.1到0.2——用“房价预测”入门机器学习全流程

...

自回归滞后模型进行多变量时间序列预测

下图显示了关于不同类型葡萄酒销量的月度多元时间序列。每种葡萄酒类型都是时间序列中的一个变量。假设要预测其中一个变量。比如,sparklingwine。如何建立一个模型来进行预测呢?一种常见的方...

苹果AI策略:慢哲学——科技行业的“长期主义”试金石

苹果AI策略的深度原创分析,结合技术伦理、商业逻辑与行业博弈,揭示其“慢哲学”背后的战略智慧:一、反常之举:AI狂潮中的“逆行者”当科技巨头深陷AI军备竞赛,苹果的克制显得格格不入:功能延期:App...

时间序列预测全攻略,6大模型代码实操

如果你对数据分析感兴趣,希望学习更多的方法论,希望听听经验分享,欢迎移步宝藏公众号...

AI 基础知识从 0.4 到 0.5—— 计算机视觉之光 CNN

...

取消回复欢迎 发表评论: