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

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

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

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

效果如下:

相关推荐

Vue3非兼容变更——函数式组件(vue 兼容)

在Vue2.X中,函数式组件有两个主要应用场景:作为性能优化,因为它们的初始化速度比有状态组件快得多;返回多个根节点。然而在Vue3.X中,有状态组件的性能已经提高到可以忽略不计的程度。此外,有状态组...

利用vue.js进行组件化开发,一学就会(一)

组件原理/组成组件(Component)扩展HTML元素,封装可重用的代码,核心目标是为了可重用性高,减少重复性的开发。组件预先定义好行为的ViewModel类。代码按照template\styl...

Vue3 新趋势:10 个最强 X 操作!(vue.3)

Vue3为前端开发带来了诸多革新,它不仅提升了性能,还提供了...

总结 Vue3 组件管理 12 种高级写法,灵活使用才能提高效率

SFC单文件组件顾名思义,就是一个.vue文件只写一个组件...

前端流行框架Vue3教程:17. _组件数据传递

_组件数据传递我们之前讲解过了组件之间的数据传递,...

前端流行框架Vue3教程:14. 组件传递Props效验

组件传递Props效验Vue组件可以更细致地声明对传入的props的校验要求...

前端流行框架Vue3教程:25. 组件保持存活

25.组件保持存活当使用...

5 个被低估的 Vue3 实战技巧,让你的项目性能提升 300%?

前端圈最近都在卷性能优化和工程化,你还在用老一套的Vue3开发方法?作为摸爬滚打多年的老前端,今天就把私藏的几个Vue3实战技巧分享出来,帮你在开发效率、代码质量和项目性能上实现弯道超车!一、...

绝望!Vue3 组件频繁崩溃?7 个硬核技巧让性能暴涨 400%!

前端的兄弟姐妹们五一假期快乐,谁还没在Vue3项目上栽过跟头?满心欢喜写好的组件,一到实际场景就频频崩溃,页面加载慢得像蜗牛,操作卡顿到让人想砸电脑。用户疯狂吐槽,领导脸色难看,自己改代码改到怀疑...

前端流行框架Vue3教程:15. 组件事件

组件事件在组件的模板表达式中,可以直接使用...

Vue3,看这篇就够了(vue3 从入门到实战)

一、前言最近很多技术网站,讨论的最多的无非就是Vue3了,大多数都是CompositionAPI和基于Proxy的原理分析。但是今天想着跟大家聊聊,Vue3对于一个低代码平台的前端更深层次意味着什么...

前端流行框架Vue3教程:24.动态组件

24.动态组件有些场景会需要在两个组件间来回切换,比如Tab界面...

前端流行框架Vue3教程:12. 组件的注册方式

组件的注册方式一个Vue组件在使用前需要先被“注册”,这样Vue才能在渲染模板时找到其对应的实现。组件注册有两种方式:全局注册和局部注册...

焦虑!Vue3 组件频繁假死?6 个奇招让页面流畅度狂飙 500%!

前端圈的朋友们,谁还没在Vue3项目上踩过性能的坑?满心期待开发出的组件,一到高并发场景就频繁假死,用户反馈页面点不动,产品经理追着问进度,自己调试到心态炸裂!别以为这是个例,不少人在电商大促、数...

前端流行框架Vue3教程:26. 异步组件

根据上节课的代码,我们在切换到B组件的时候,发现并没有网络请求:异步组件:...

取消回复欢迎 发表评论: