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

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

ztj100 2025-02-08 13:56 8 浏览 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;"
}

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

效果如下:

相关推荐

利用navicat将postgresql转为mysql

导航"拿来主义"吃得亏自己动手,丰衣足食...

Navicat的详细教程「偷偷收藏」(navicatlite)

Navicat是一套快速、可靠并价格适宜的数据库管理工具,适用于三种平台:Windows、macOS及Linux。可以用来对本机或远程的MySQL、SQLServer、SQLite、...

Linux系统安装SQL Server数据库(linux安装数据库命令)

一、官方说明...

Navicat推出免费数据库管理软件Premium Lite

IT之家6月26日消息,Navicat推出一款免费的数据库管理开发工具——NavicatPremiumLite,针对入门级用户,支持基础的数据库管理和协同合作功能。▲Navicat...

Docker安装部署Oracle/Sql Server

一、Docker安装Oracle12cOracle简介...

Docker安装MS SQL Server并使用Navicat远程连接

...

Web性能的计算方式与优化方案(二)

通过前面《...

网络入侵检测系统之Suricata(十四)——匹配流程

其实规则的匹配流程和加载流程是强相关的,你如何组织规则那么就会采用该种数据结构去匹配,例如你用radixtree组织海量ip规则,那么匹配的时候也是采用bittest确定前缀节点,然后逐一左右子树...

使用deepseek写一个图片转换代码(deepnode处理图片)

写一个photoshop代码,要求:可以将文件夹里面的图片都处理成CMYK模式。软件版本:photoshop2022,然后生成的代码如下://Photoshop2022CMYK批量转换专业版脚...

AI助力AUTOCAD,生成LSP插件(ai里面cad插件怎么使用)

以下是用AI生成的,用AUTOLISP语言编写的cad插件,分享给大家:一、将单线偏移为双线;;;;;;;;;;;;;;;;;;;;;;单线变双线...

Core Audio音频基础概述(core 音乐)

1、CoreAudioCoreAudio提供了数字音频服务为iOS与OSX,它提供了一系列框架去处理音频....

BlazorUI 组件库——反馈与弹层 (1)

组件是前端的基础。组件库也是前端框架的核心中的重点。组件库中有一个重要的板块:反馈与弹层!反馈与弹层在组件形态上,与Button、Input类等嵌入界面的组件有所不同,通常以层的形式出现。本篇文章...

怎样创建一个Xcode插件(xcode如何新建一个main.c)

译者:@yohunl译者注:原文使用的是xcode6.3.2,我翻译的时候,使用的是xcode7.2.1,经过验证,本部分中说的依然是有效的.在文中你可以学习到一系列的技能,非常值得一看.这些技能不单...

让SSL/TLS协议流行起来:深度解读SSL/TLS实现1

一前言SSL/TLS协议是网络安全通信的重要基石,本系列将简单介绍SSL/TLS协议,主要关注SSL/TLS协议的安全性,特别是SSL规范的正确实现。本系列的文章大体分为3个部分:SSL/TLS协...

社交软件开发6-客户端开发-ios端开发验证登陆部分

欢迎订阅我的头条号:一点热上一节说到,Android客户端的开发,主要是编写了,如何使用Androidstudio如何创建一个Android项目,已经使用gradle来加载第三方库,并且使用了异步...

取消回复欢迎 发表评论: