作者:小傅哥

博客:https://bugstack.cn

源码:https://github.com/fuzhengwei/CodeGuide/wiki

沉淀、分享、成长,让自己和他人都能有所收获!

一、前言

都能用,都能凑活用!

一个东西好几套,为了晋升都来搞。拿了成绩就要跑,后面兄弟再重造!

几年前,大家并不是这样,那时候还有很多东西可以创新,乱世出英雄总能在一个方向深耕并作出一款款好用的产品功能、框架服务、技术组件等。但后来好像这样的情况开始减少了,取而代之的是重复、复刻、照搬,换个新的皮肤、换个新的样式、换个新的名字,就是取巧的新东西了。

有时候公司或者组织也像家,但家里的东西一般是破了补补、坏了修修,实在不行就换个,但没有谁的家里卫生间一个马桶、厨房一个马桶、客厅一个马桶、卧室一个马桶的,虽然你的新马桶可以自动喷水。

所以,在建设一个好的产品功能时,尽可能要学学那些已经非常的优秀的产品,IDEA、GitHub、Mysql等等,在IDEA提供了满足用户扩展功能的插件开发,而不是你说一个东西我没有,你就自己造。共建会让这个东西变得更加优秀!

二、需求目的

在上一章节中我们通过扩展创建工程向导,添加我们需要创建DDD工程脚手架的步骤,最终提供一个DDD开发框架。那么在这个DDD工程开发框架中,还缺少一部分基于数据库表信息自动生成对应PO、DAO、Mapper文件的功能。

  • 那么本章节我们就来在工程中扩展这部分内容,实际操作的效果就是我们可以在工程上通过鼠标右键的方式,唤出添加ORM代码块的窗体,通过选择库表的方式,使用 freemarker 自动生成代码。
  • 在生成的代码块中需要完成对所需要包的引入,同时会使用到 lombok 注解的方式替代PO对象中的get、set方法,以减少代码量逻辑的创建。

三、案例开发

1. 工程结构

  1. guide-idea-plugin-orm
  2. ├── .gradle
  3. └── src
  4. ├── main
  5. └── java
  6. └── cn.bugstack.guide.idea.plugin
  7. ├── action
  8. └── CodeGenerateAction.java
  9. ├── domain
  10. ├── model.vo
  11. ├── CodeGenContextVO.java
  12. └── ORMConfigVO.java
  13. └── service
  14. ├── impl
  15. └── ProjectGeneratorImpl.java
  16. ├── AbstractProjectGenerator.java
  17. ├── GeneratorConfig.java
  18. └── IProjectGenerator.java
  19. ├── infrastructure
  20. ├── data
  21. ├── DataSetting.java
  22. └── DataState.java
  23. ├── po
  24. ├── Base.java
  25. ├── Column.java
  26. ├── Dao.java
  27. ├── Field.java
  28. ├── Model.java
  29. └── Table.java
  30. └── utils
  31. ├── DBHelper.java
  32. └── JavaType.java
  33. ├── module
  34. └── FileChooserComponent.java
  35. └── ui
  36. ├── ORMSettingsUI.java
  37. └── ORMSettingsUI.form
  38. ├── resources
  39. ├── META-INF
  40. └── plugin.xml
  41. └── template
  42. ├── dao.ftl
  43. ├── mapper.ftl
  44. └── model.ftl
  45. ├── build.gradle
  46. └── gradle.properties

源码获取:#公众号:bugstack虫洞栈 回复:idea 即可下载全部 IDEA 插件开发源码# 第 5 章:在开发工程中鼠标右键,生成ORM代码

在此 IDEA 插件工程中,主要分为5块区域:

  • action:用于提供菜单栏,这个菜单的位置在 plugin.xml 中配置,我们把它配置到工程鼠标右键出现的列表上。这样可以更加方便的让我们选取工程,以及在这个工程下添加生成的代码片段
  • domain:领域服务层,其实你直接写一个Service包也是可以的,只不过最近作者小傅哥更喜欢使用DDD的思想和结构来创建代码实现功能逻辑。
  • infrastructure:基础层,提供数据在工程下的存放,每一个工程右键都有自己的配置存储默认信息,方便下次打开的时候可以读取到这部分内容。同时这一层还提供了用于处理数据库操作的类,因为我们需要从数据库中读取出表的信息、字段、注释,用于创建PO、DAO、Mapper使用。
  • module:模块层,这里提供了一个用于选择文件路径的组件,可以让我们在工程上鼠标右键的出来的窗体中,点击模块选择对应的要生成代码的位置路径。
  • ui:提供配置面板,也就是我们在代码工程上鼠标右键弹出来的面板,这个面板配置后用于生成ORM代码。

2. 拖拽Swing面板

ORMSettingsUI:咱们先把用于创建代码配置的面板创建出来,有了画面,就好进入了。

  • 面板包括生成 PO、DAO、XML 的代码路径,以及配置数据库和选择表的内容。
  • 操作过程就是在你配置好了这些基本信息后,就可以选择查询表名,并选择好你要给哪几个表生成对应的ORM代码了。

3. 配置鼠标右键弹窗

首先我们需要创建一个 Action 实现类,通过 New -> Plugin DevKit -> Action

cn.bugstack.guide.idea.plugin.action.CodeGenerateAction

  1. /**
  2. * @author: 小傅哥,微信:fustack
  3. * @github: https://github.com/fuzhengwei
  4. * @Copyright: 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
  5. */
  6. public class CodeGenerateAction extends AnAction {
  7. private IProjectGenerator projectGenerator = new ProjectGeneratorImpl();
  8. @Override
  9. public void actionPerformed(AnActionEvent e) {
  10. Project project = e.getRequiredData(CommonDataKeys.PROJECT);
  11. ShowSettingsUtil.getInstance().editConfigurable(project, new ORMSettingsUI(project, projectGenerator));
  12. }
  13. }
  • 这是一个右键菜单的入口,通过这个入口才能去打开我们自己的UI窗体,这个UI窗体就是我们上面拖拽出来的配置面板,ORMSettingsUI
  • 接下来我们还需要把这个 Action 配置到 plugin.xml 文件中,才能被右键菜单创建出来。开发代码的时候也是这样一个流程,你总要从一个点开始,有了抓手才好抓下去

plugin.xml 配置

  1. <actions>
  2. <!-- Add your actions here -->
  3. <action id="CodeGenerateAction" class="cn.bugstack.guide.idea.plugin.action.CodeGenerateAction"
  4. text="ORMCodeGenerate - 小傅哥" description="Code Generate ORM" icon="/icons/logo.png">
  5. <add-to-group group-id="ProjectViewPopupMenu" anchor="last"/>
  6. </action>
  7. </actions>
  8. ea-plugin>
  • 把我们的 Action 实现类配置到 xml 中,同时你还要配置它应该出现的位置,比如你需要把这个菜单添加到工程创建中 ProjectViewPopupMenu 以及位置信息 anchor="last"
  • 另外为了让插件看上去更加高大上还美观适合吹牛,那么还需要配置 icon,这个位置配置一个16*16的图片,图片可以从 iconfont 进行下载。

4. 给窗体添加功能

这一步其实干的就是注入灵魂的事情,让窗体活起来。给输入框添加内容、给按钮添加事件、给确认按钮增加上生成创建ORM代码块的上下文。文章的描述尽可能会偏向于核心代码的讲解,详情可以参考源码

接下来这部分内容会在 ORMSettingsUI 类中反复摩擦,直到补全所有功能。

4.1 选择框事件

  1. // 选择PO生成目录
  2. this.poButton.addActionListener(e -> {
  3. FileChooserComponent component = FileChooserComponent.getInstance(project);
  4. VirtualFile baseDir = project.getBaseDir();
  5. VirtualFile virtualFile = component.showFolderSelectionDialog("选择PO生成目录", baseDir, baseDir);
  6. if (null != virtualFile) {
  7. ORMSettingsUI.this.poPath.setText(virtualFile.getPath());
  8. }
  9. });
  • 还记得我们提到的拖拽Swing面板吗,那么这个添加事件的步骤就是给你的 PO 目录添加一个事件,允许我们可以自己选择出要把对应PO的代码生成到哪个目录结构下。
  • 关于dao、xml都是类似操作,这里就不在演示了。

4.2 数据表事件

  1. this.selectButton.addActionListener(e -> {
  2. try {
  3. DBHelper dbHelper = new DBHelper(this.host.getText(), Integer.parseInt(this.port.getText()), this.user.getText(), this.password.getText(), this.database.getText());
  4. List<String> tableList = dbHelper.getAllTableName(this.database.getText());
  5. String[] title = {"", "表名"};
  6. Object[][] data = new Object[tableList.size()][2];
  7. for (int i = 0; i < tableList.size(); i++) {
  8. data[i][1] = tableList.get(i);
  9. }
  10. table1.setModel(new DefaultTableModel(data, title));
  11. TableColumn tc = table1.getColumnModel().getColumn(0);
  12. tc.setCellEditor(new DefaultCellEditor(new JCheckBox()));
  13. tc.setCellEditor(table1.getDefaultEditor(Boolean.class));
  14. tc.setCellRenderer(table1.getDefaultRenderer(Boolean.class));
  15. tc.setMaxWidth(100);
  16. } catch (Exception exception) {
  17. Messages.showWarningDialog(project, "数据库连接错误,请检查配置.", "Warning");
  18. }
  19. });
  • 这一步操作核心流程就在于把你需要生成ORM的代码的表给拉出来,只要把表选择上,才能根据表生成PO、DAO、Mapper,其实你用的其他一些自动生成代码框架也是这么干的。
  • 另外你的建表最好规范,比如有表注释、有字段注释、字段的设计遵守下划线和小写字母,这样会更加容易创建出好看的代码。

4.3 组装生成代码上下文

当我们点击配置窗体的 OK 按钮时候,要干啥,对喽,我们要创建出代码片段了,那么这个时候需要在重写的 apply 中完成此项操作。

  1. public void apply() {
  2. // 链接DB
  3. DBHelper dbHelper = new DBHelper(config.getHost(), Integer.parseInt(config.getPort()), config.getUser(), config.getPassword(), config.getDatabase());
  4. // 组装代码生产上下文
  5. CodeGenContextVO codeGenContext = new CodeGenContextVO();
  6. codeGenContext.setModelPackage(config.getPoPath() + "/po/");
  7. codeGenContext.setDaoPackage(config.getDaoPath() + "/dao/");
  8. codeGenContext.setMapperDir(config.getXmlPath() + "/mapper/");
  9. List<Table> tables = new ArrayList<>();
  10. Set<String> tableNames = config.getTableNames();
  11. for (String tableName : tableNames) {
  12. tables.add(dbHelper.getTable(tableName));
  13. }
  14. codeGenContext.setTables(tables);
  15. // 生成代码
  16. projectGenerator.generation(project, codeGenContext);
  17. }
  • 在 apply 中的核心代码主要就是使用 DBHelper 数据操作工具获取到对应的库下链接信息,同时把选择的号的表创建出用于生成代码类的参数,比如;类的名称、字段名称、注释名称等。
  • 最后就是调用生成代码的服务了,projectGenerator.generation(project, codeGenContext); 这一部分就是在我们领域服务 domain 中实现的。

5. 代码生成领域服务

  • 用于创建PO、DAO、Mapper的代码块的代码主要是这里实现的,核心在于提供了一个抽象类以及对应的实现类,因为处理代码生成需要使用到 freemarker 所以就在抽象类里包装了下,这样可以免去实现类中还需要关心这部分逻辑。

ProjectGeneratorImpl 生成代码

  1. @Override
  2. protected void generateORM(Project project, CodeGenContextVO codeGenContext) {
  3. List<Table> tables = codeGenContext.getTables();
  4. for (Table table : tables) {
  5. List<Column> columns = table.getColumns();
  6. List<Field> fields = new ArrayList<>();
  7. for (Column column : columns) {
  8. Field field = new Field(column.getComment(), JavaType.convertType(column.getType()), column.getName());
  9. field.setId(column.isId());
  10. fields.add(field);
  11. }
  12. // 生成PO
  13. Model model = new Model(table.getComment(), codeGenContext.getModelPackage() + CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, table.getName()), table.getName(), fields);
  14. writeFile(project, codeGenContext.getModelPackage(), model.getSimpleName() + ".java", "domain/orm/model.ftl", model);
  15. // 生成DAO
  16. Dao dao = new Dao(table.getComment(), codeGenContext.getDaoPackage() + "I" + CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, table.getName()) + "Dao", model);
  17. writeFile(project, codeGenContext.getDaoPackage(), dao.getSimpleName() + ".java", "domain/orm/dao.ftl", dao);
  18. // 生成Mapper
  19. writeFile(project, codeGenContext.getMapperDir(), dao.getModel().getSimpleName() + "Mapper.xml", "domain/orm/mapper.ftl", dao);
  20. }
  21. }
  • 创建代码的过程就比较简单了,通过循环提取出来的表信息,映射成对应的类和属性以及注释,再使用 resources 下的 ftl 文件创建出对应的类和xml配置文件就可以了。
  • 如果你还需要生成起来代码片段或者创建调用一些常用的组件,也是可以通过这样的方式进行实现的。

四、测试验证

  • 点击 Plugin 启动 IDEA 插件,之后在工程右键如下:

1. 鼠标右键,选择菜单

2. 配置页面,配置信息

3. 自动创建,生成代码

  • 好了,选择代码块就这么嗖的创建了出来,是不是非常方便,而且可以满足你在任何时候的把新的库表代码补充进来,减少了手敲CRUD操作。

五、总结

  • 本章节小傅哥带着你又在 IDEA DDD 插件生成工程的结构下,又完善了一步生成ORM代码,当然你也可以在创建工程向导中添加生成ORM代码的步骤。而在工程下创建ORM的方式可以当做是对脚手架工程的补充,满足不同场景下的需求。
  • 此外在 IDEA 插件开发的系列内容中我们是不断的尝试使用新的方式完善不同的功能点,如果你需要开发一个完整的插件那么可以结合这些功能一起来开发你的需求。
  • 插件开发中还是有很多的内容需要了解和学习的,同时也要注意一些代码实现细节,例如我们本章节中的数据保存是在一个什么维度,是IDEA开发工具维度,还是在IDEA中的工程维度,这些是有区别。比如你的不同工程,是不需要保存同一份配置的

六、系列推荐

整个小东西,在IDEA中自动生成PO、DAO、Mapper的更多相关文章

  1. MyBatis 使用Generator自动生成Model , Dao, mapper

    最近   我新建了一 个maven 项目,使用的是spring + springmvc + mybatis框架. 听说Mybatis可以自动生成model和mapper以及dao层,我就从网上查了查资 ...

  2. 懒人小工具1:winform自动生成Model,Insert,Select,Delete以及导出Excel的方法

       懒人小工具2:T4自动生成Model,Insert,Select,Delete以及导出Excel的方法    github地址:https://github.com/Jimmey-Jiang/J ...

  3. 在 Linux 中自动生成 Cordova/Phonegap for Android 的 APK 安装程序

    在 Linux 中自动生成 Cordova/Phonegap for Android 的 APK 安装程序 本贴首发于: http://xuekaiyuan.com/forum.php?mod=vie ...

  4. IntelliJ IDEA 中自动生成 serialVersionUID 的方法

    as, idea plugin中搜如下关键字,并安装该插件: GenerateSerialVersionUID 如上图所示,创建一个类并实现Serializable接口,然后按alt+Enter键,即 ...

  5. 在PowerDesigner中自动生成sqlserver字段备注

    在PowerDesigner中自动生成sqlserver字段备注 PowerDesigner是数据库设计人员常用的设计工具,但其自生默认生成的代码并不会生成sqlserver数据库的字段备注说明.在生 ...

  6. 二十四、详述 IntelliJ IDEA 中自动生成 serialVersionUID 的方法

    当我们用 IntelliJ IDEA 编写类并实现 Serializable(序列化)接口的时候,可能会遇到这样一个问题,那就是: 无法自动生成serialVersionUID. 而serialVer ...

  7. eclipse中自动生成注释

    eclipse中自动生成注释 包前缀设置的地方 注释模板设置的地方 Eclipse自动生成方法注释 快捷键 自动生成方法的注释格式,例如 /*** @param str* @return* @thro ...

  8. Eclipse中自动生成get/set时携带注释给get/set

    Eclipse中自动生成get/set时携带注释给get/set   编码的时候通常要用到 JavaBean ,而在我们经常把注释写在字段上面,但生成的Get/Set方法不会生成,通过修改Eclips ...

  9. 从JSON中自动生成对应的对象模型

    编程的乐趣和挑战之一,就是将体力活自动化,使效率成十倍百倍的增长. 需求 做一个项目,需要返回一个很大的 JSON 串,有很多很多很多字段,有好几层嵌套.前端同学给了一个 JSON 串,需要从这个 J ...

  10. 使用MyBatis Generator自动生成实体、mapper和dao层

    原文链接 通过MyBatis Generator可以自动生成实体.mapper和dao层,记录一下怎么用的. 主要步骤: 关于mybatis从数据库反向生成实体.DAO.mapper: 参考文章:ht ...

随机推荐

  1. 一、@Configuration、@Conponent 、@ComponentScan 注解等

    一句话概括 区别: @Configuration 中所有带 @Bean 注解的方法都会被动态代理,因此调用该方法返回的都是同一个实例.2. 可以直接调用方法,不需要 @Autowired 注入后使用. ...

  2. 基于阿里云Serverless函数计算开发的疫情数据统计推送机器人

    一.Serverless函数计算 什么是Serverless? 在<Serverless Architectures>中对 Serverless 是这样子定义的: Serverless w ...

  3. S3C2440移植uboot之新建单板_时钟_SDRAM_串口

    上一节S3C2440移植uboot之启动过程概述我们我们分析了uboot启动流程,这节将开始新建一块单板支持S3C2440. 目录 1.新建单板 1.1 将2410的单板文件夹拷贝成2440: 1.2 ...

  4. Go ASM 学习笔记之 ppt 版

    在 小白学标准库之反射 reflect 篇中介绍了接口和反射.然而,对于接口的类型转换,底层实现还是一知半解.在参考 Go 语言设计与实现 这本书接口章节时,又看不大懂.一个拦路虎摆在面前:汇编.不懂 ...

  5. iview 表单有值却校验失败

    转载请注明出处: iview 表单校验数值的时候,表单有值,却在提交的时候,提示表单校验失败: 解决方案: 1. IviewUI的文档里查到了rules规则里面有个校验类型的属性字段type rule ...

  6. SV 数据类型-3

    联合数组 在内存中分配的空间可以是不连续的 联合数组方法 数组的方法 数组使用推荐 结构体 枚举类型 字符串变量类型String 操作符

  7. Linux系统下安装JDK8和Maven3.8.5

    一.下载JDK8Linux版本 官网下载太慢了,小编这里为大家下载好了: 链接:百度网盘地址 提取码:ov24 二.下载Maven maven3.8.5下载链接 三.使用xftp上传到linux上 四 ...

  8. 【收集】C & C++

    序 链接 备注 1 C语言0长度数组(可变数组/柔性数组)详解_CHENG Jian的博客-CSDN博客_0数组   2 C 语言参考 | Microsoft Learn   3 C++ 语言参考 | ...

  9. [转帖]加速拥抱支持开源生态 | OceanBase 开源版3.1.1正式发布

    https://www.oceanbase.com/news/accelerated-embrace-and-support-of-open-source-ecosystem-oceanbase-op ...

  10. [转帖]Oracle、SQL Server、MySQL数据类型对比

    Oracle.SQL Server.MySQL数据类型对比 - 知乎 (zhihu.com) 1,标准SQL数据类型 BINARY 每个字符占一个字节 任何类型的数据都可存储在这种类型的字段中.不需数 ...