若依管理系统RuoYiVue三:代码生成器原理和实战

作者: 狂盗一枝梅

本篇文章将会介绍ruoyi-vue代码生成器的使用方法、原理介绍以及独立版代码生成器的封装

历史文章

若依管理系统RuoYi-Vue(一):项目启动和菜单创建
若依管理系统RuoYi-Vue(二):权限系统设计详解

本篇文章将会讲解ruoyi-vue系统下代码生成器的使用、原理分析以及将这部分代码抽离出来形成独立版的代码生成器。

一、代码生成器的使用

1.新建maven模块

原则上,们的业务代码和若依系统本身的系统代码是要做隔离的,一方面是易于之后随着若依系统升级而升级,另一方面则是纯粹的合理性考虑。

这里新建一个ruoyi-business模块作为业务代码模块,新建完ruoyi-business模块之后添加ruoyi-framework依赖,pom文件如下所示

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>ruoyi</artifactId>
        <groupId>com.ruoyi</groupId>
        <version>3.4.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.kdyzm</groupId>
    <artifactId>ruoyi-business</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <dependencies>
        <!-- 核心模块-->
        <dependency>
            <groupId>com.ruoyi</groupId>
            <artifactId>ruoyi-framework</artifactId>
        </dependency>
    </dependencies>
</project>

之后在ruoyi-admin添加ruoyi-business模块的依赖

<dependency>
    <groupId>com.kdyzm</groupId>
    <artifactId>ruoyi-business</artifactId>
    <version>1.0.0-SNAPSHOT</version>
</dependency>

2.准备代码生成器配置 ruoyi-vue系统中代码生成器相代码都在ruoyi-generator模块中,代码生成的配置在resources/generator.yml文件中,由于要在新的模块ruoyi-business中做开发,要有个新包名,包名取作com.kdyzm.business,所以generator.yml配置文件内容如下:

 代码生成
gen: 
   作者
  author: kdyzm
   默认生成包路径 system 需改成自己的模块名称 如 system monitor tool
  packageName: com.kdyzm.business
   自动去除表前缀,默认是false
  autoRemovePre: false
   表前缀(生成类名不会包含表前缀,多个用逗号分隔)
  tablePrefix: sys_

另外,这里要使用自定义包名com.kdyzm.business,所以若依系统中mybatis也要做相应的修改

  • 修改mybatis别名配置,增加对com.kdyzm包名的识别
    MyBatis配置
    mybatis:
       搜索指定包别名
      typeAliasesPackage: com.ruoyi.**.domain,com.kdyzm.**.domain
    
  • 修改mybatis的mapper扫描包路径 修改com.ruoyi.framework.config.ApplicationConfig类的MapperScan注解,增加对com.kdyzm包的扫描
    @MapperScan()
    public class ApplicationConfig{
      ...
    }
    

最后,在ruoyi-admin新增一个Config类,扫描com.kdyzm包,以将ruoyi-business模块中的所有组件纳入spring管理。

package com.ruoyi.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
 * @author kdyzm
 */
@Configuration
@ComponentScan(basePackages = "com.kdyzm")
public class Config {
}

3.准备表

这里新建一张商品表作为示例,注意,这里的字段和表都要加上注释

CREATE TABLE `goods` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `GOODS_NAME` varchar(255) DEFAULT NULL COMMENT '商品名字',
  `put_way_flag` tinyint(1) DEFAULT NULL COMMENT '商品是否上架,0:下架,1:上架',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `create_by` varchar(64) DEFAULT NULL COMMENT '创建人',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  `update_by` varchar(64) DEFAULT NULL COMMENT '更新人',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品表'

4.生成代码

进入系统工具-代码生成页面,点击导入按钮,找到goods表并导入,如下图所示

然后点击生成代码按钮

之后,就可以得到一个ruoyi.zip压缩文件,压缩文件中包含生成的前后端代码以及sql语句文件,生成的代码目录结构如下所示

├── goodsMenu.sql
├── main
│   ├── java
│   │   └── com
│   │       └── kdyzm
│   │           └── business
│   │               ├── controller
│   │               │   └── GoodsController.java
│   │               ├── domain
│   │               │   └── Goods.java
│   │               ├── mapper
│   │               │   └── GoodsMapper.java
│   │               └── service
│   │                   ├── IGoodsService.java
│   │                   └── impl
│   │                       └── GoodsServiceImpl.java
│   └── resources
│       └── mapper
│           └── business
│               └── GoodsMapper.xml
└── vue
    ├── api
    │   └── business
    │       └── goods.js
    └── views
        └── business
            └── goods
                └── index.vue

二、将生成的代码应用到项目

1.后端代码

将生成代码中的main目录直接拷贝到ruoyi-business模块下的src目录,可以看到生成的代码是典型的三层架构,从controller到mapper都已经帮们生成好了。

2.前端代码

前端代码对应着生成目录中的vue目录,这里将vue/api目录中的内容拷贝到ruoyi-ui/src/api目录中,将vue/views中的内容拷贝到ruoyi-ui/src/views目录,操作上,直接将生成的api和views目录拷贝到src目录即可。

3.sql代码

生成的sql代码是创建菜单和按钮权限使用的,直接在ruoyi数据库下执行 goodsMenu.sql 文件中的内容即可。

-- 菜单 SQL
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('商品', '3', '1', 'goods', 'business/goods/index', 1, 0, 'C', '0', '0', 'business:goods:list', '', 'admin', sysdate(), '', null, '商品菜单');
-- 按钮父菜单ID
SELECT @parentId := LAST_INSERT_ID();
-- 按钮 SQL
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('商品查询', @parentId, '1',  '', '', 1, 0, 'F', '0', '0', 'business:goods:query',        '', 'admin', sysdate(), '', null, '');
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('商品新增', @parentId, '2',  '', '', 1, 0, 'F', '0', '0', 'business:goods:add',          '', 'admin', sysdate(), '', null, '');
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('商品修改', @parentId, '3',  '', '', 1, 0, 'F', '0', '0', 'business:goods:edit',         '', 'admin', sysdate(), '', null, '');
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('商品删除', @parentId, '4',  '', '', 1, 0, 'F', '0', '0', 'business:goods:remove',       '', 'admin', sysdate(), '', null, '');
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('商品导出', @parentId, '5',  '', '', 1, 0, 'F', '0', '0', 'business:goods:export',       '', 'admin', sysdate(), '', null, '');

三、测试

重新运行前后端代码,打开系统工具菜单(为何在这里?这是若依vue的bug,已经提到gitee,bug链接: I3915P )的商品菜单

可以看到,前后端代码只是复制粘贴,后端接口、前端菜单、权限等等一切都已经被代码生成器帮们做完了,可以说代码生成器极大的简化了们的开发。

四、代码生成器高级使用

在三的测试过程中,们发现,商品是否上架这个字段对应的前端表单是个文本输入框,但是实际上这里应该是个下拉列表框或者单选按钮才对,因为它只有两个值:0或者1,ruoyi-vue代码生成器实际上是支持这种操作的。之前生成代码的时候导入表之后直接点击了下载按钮生成了代码,实际上跳过了一个重要的步骤,那就是编辑代码生成选项。

点击编辑按钮之后,跳转修改生成配置页面。

在这个页面中,可以修改字段在前端的显示类型以及字典类型,比如,要想"商品是否上架"在前端展示为单选框,就可以修改显示类型为"单选框”,字典类型设置为"业务是否(需要新增数据字典,0表示下架,1表示上架)“。

提交之后重新生成的代码样式:

可以看到,商品是否字段变成了下拉列表和单选框的样式。

另外,若依代码生成器支持三种数据格式模板的代码生成:单表、树表、主子表,这里默认使用的是单表模板,也是最常使用的模板。

五、代码生成器原理

1.Velocity Velocity是一个基于Java的模板引擎,其提供了一个Context容器,在java代码里面们可以往容器中存值,然后在vm文件中使用特定的语法获取,这是velocity基本的用法,其与jsp、freemarker并称为三大视图展现技术。作为一个模块引擎,除了作为前后端分离的MVC展现层,Velocity还有一些其他用途,比如源代码生成。

在若依Vue系统中,正是使用了Velocity技术实现的源代码生成。大体上,源代码生成只需三步走:

  1. 创建模板文件
  2. 准备上下文(变量值)
  3. 替换模板文件中的变量

三步走完之后源代码就生成了,说起来是很简单的,但是实际上做起来会比较麻烦,特别是第一步创建模板文件是最复杂的,以下为index.vue模板文件部分源代码:

foreach($column in $columns)
if($column.query)
set($dictType=$column.dictType)
set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
set($parentheseIndex=$column.columnComment.indexOf("("))
if($parentheseIndex != -1)
set($comment=$column.columnComment.substring(0, $parentheseIndex))
else
set($comment=$column.columnComment)
end
if($column.htmlType == "input")
...

可以看到,该vue模板文件中充斥着大量Velocity的if-else语法,嵌套在一起更是显得无比复杂。

总之,整体上来看,java代码的模板比较简单,vue和mybatis mapper的模板文件比较复杂。 2.information_schema 数据库 mysql数据库中有一个information_schema数据库,它是mysql的系统数据库之一,它里面存储着两个表TABLES以及COLUMNS,这两个表分别存储着所有的表信息以及所有表中的列信息,代码生成器正是以两张表的信息为核心实现的。 3.ruoyi-vue代码生成器源码分析 ruoyi-vue代码生成器相关代码均位于ruoyi-generator模块中,根据之前的实际操作体验上来看,最简单的情况,前端页面只需要两步即可完成代码生成

  • 导入表结构
  • 生成代码

实际上这两步对应着后端的两个接口:com.ruoyi.generator.controller.GenControllerimportTableSavecom.ruoyi.generator.controller.GenControllerbatchGenCode ,生成源码的步骤就要从这两步下手。

首先看com.ruoyi.generator.controller.GenControllerimportTableSave 接口,它做了以下这些事情

  1. 从information_schema数据库的tables表中查询目标表的表明、标注释、创建时间和更新时间,但是忽略掉定时任务的表和已经生成过的表。
  2. 初始化表数据并将数据插入ruoyi数据库的gen_table表
  3. 从information_schema数据库的columns表中查询目标表的列信息,包含字段名、字段注释、字段类型、是否允许为null等详细信息
  4. 初始化列信息并将数据插入ruoyi数据库的gen_table_column表

接下来看下 com.ruoyi.generator.controller.GenControllerbatchGenCode 接口,它做了以下这些事情

  1. 从ruoyi数据库的gen_table、gen_table_column表查询出生成代码需要的表和列信息。
  2. 初始化Velocity
  3. 准备Velocity上下文信息(变量值信息)
  4. 读取模板、渲染模板,然后将渲染后的模板内容添加进如压缩流,之后前端就可以下载zip压缩文件了。

完毕。

六、扩展篇:封装独立版ruoyi-vue代码生成器

1.为什么要做这个

作为一个后端开发,最经常做的事情不是搞啥系统架构,而是最简单的CRUD。。。若是能有一个代码一键生成工具自动根据已经创建的表信息生成CRUD后端代码,那岂不是能节省老鼻子功夫了——若依系统已经实现了这个代码生成器的工具,但是它依赖于前端页面,必须有权限访问"系统工具-代码生成"菜单才行,而这在企业中像这种普通研发往往是是没有权限访问的。但是有权限访问表,查看表结构。作为一个有追求的开发,既不肯开口问别人要权限,还想要实现代码生成器,该怎么做?

自己搞一个呗。

在这里封装的代码生成器不考虑前端页面调整功能,其实现的功能更加注重于后端代码,其作用和"系统工具-代码生成"页面中最简单的生成代码的两步(导入表和下载代码,无编辑)结果等效。 2.抽离ruoyi-vue代码生成器逻辑 ruoyi-vue中的ruoyi-generator模块有着完整的代码生成逻辑,但是它依托于ruoyi-admin的spring-boot框架才能运行,现在要将ruoyi-generator模块的功能独立于spring-boot,让其作为一个普通的spring的程序,只有一个普通的main方法,实现和原来等效的功能。

这里的做法是直接修改ruoyi-generator模块,删除spring-boot的相关功能,但是保留spring、mybatis、druid等基础组件的依赖,然后将这些组件手动重新纳入spring容器中进行管理,最后通过main方法调用到相关模块。

具体就不展开讲了,有兴趣的可以看看的源代码:https://gitee.com/kdyzm/ruoyi-vue-gen 3.独立版代码生成器使用方法 3.1 配置application.properties配置文件

该配置文件的内容如下:

mysql.username=$
mysql.password=$
mysql.connectionUrl=$
mysql.driverClass=$
gen.author=kdyzm
gen.packageName=com.kdyzm.business
gen.autoRemovePre=false
gen.tableName=news
gen.tablePrefix=sys_

上半部分是数据库配置,连接的是ruoyi-vue数据库,正常配置即可;下半部分是生成配置,除了gen.tableName,其它配置和原ruoyi-vue代码生成器的配置相同。

要注意,代码生成结果仅使用用ruoyi-vue项目,如需自定义模板,需要修改源代码。 3.2 打包和运行

在项目根目录运行命令mvn clean package,打包完成之后切换到target目录,使用命令java -jar ruoyi-vue-gen-1.0-SNAPSHOT.jar运行jar包得到ruoyi.zip压缩文件

七、项目源代码

独立版代码生成器源代码:https://gitee.com/kdyzm/ruoyi-vue-gen

好了,ruoyi-vue代码生成器篇就到此结束了,欢迎关注的博客 https://blog.kdyzm.cn ~

原文创作:狂盗一枝梅

原文链接:https://www.cnblogs.com/kuangdaoyizhimei/p/14452736.html

文章列表

更多推荐

更多
  • AWS自动化机器学习-十一、MLSDLC 的持续集成、部署和训练 技术要求,编纂持续集成阶段,管理持续部署阶段,管理持续训练,延伸,构建集成工件,构建测试工件,构建生产工件,自动化持续集成流程,回顾构建阶段,回顾测试阶段,审查部署和维护阶段,回顾应用用户体验,创建新的鲍鱼调查数据,回顾持续训练流程,清
    Apache CN

  • AWS自动化机器学习-六、使用 AWS 步骤函数自动化机器学习过程 技术要求,介绍 AWS 步骤功能,使用 Step 函数 Data Science SDK for CI/CD,建立 CI/CD 渠道资源,创建状态机,解决状态机的复杂性,更新开发环境,创建管道工件库,构建管道应用构件,部署 CI/CD
    Apache CN

  • AWS自动化机器学习-第三部分:优化以源代码为中心的自动化机器学习方法 本节将向您介绍整体 CI/CD 流程的局限性,以及如何将 ML 从业者的角色进一步整合到管道构建流程中。本节还将介绍这种角色集成如何简化自动化过程,并通过向您介绍 AWS Step 函数向您展示一种优化的方法。本节包括以下章节:
    Apache CN

  • AWS自动化机器学习-一、AWS 上的自动化机器学习入门 技术要求,洗钱流程概述,洗钱过程的复杂性,端到端 ML 流程示例,AWS 如何使 ML 开发和部署过程更容易自动化,介绍 ACME 渔业物流,ML 的情况,从数据中获得洞察力,建立正确的模型,训练模型,评估训练好的模型,探索可能的后续步
    Apache CN

  • AWS自动化机器学习-二、使用 SageMaker 自动驾驶器自动化机器学习模型开发 技术要求,介绍 AWS AI 和 ML 前景,SageMaker 自动驾驶器概述,利用 SageMaker 自动驾驶器克服自动化挑战,使用 SageMaker SDK 自动化 ML 实验,SageMaker Studio 入门,准备实验
    Apache CN

  • AWS自动化机器学习-四、机器学习的持续集成和持续交(CI/CD) 四、机器学习的持续集成和持续交CI/CD技术要求,介绍 CI/CD 方法,通过 CI/CD 实现 ML 自动化,在 AWS 上创建 CI/CD 管道,介绍 CI/CD 的 CI 部分,介绍 CI/CD 的 CD 部分,结束循环,采取以部
    Apache CN

  • AWS自动化机器学习-九、使用 Amazon Managed Workflows 为 Apache AirFlow 构建 ML 工作流 技术要求,开发以数据为中心的工作流程,创建合成鲍鱼调查数据,执行以数据为中心的工作流程,构建和单元测试数据 ETL 工件,构建气流 DAG,清理, 在前面的年龄计算器示例中,我们了解了如何通过 ML 从业者和开发人员团队之间的跨职能
    Apache CN

  • AWS自动化机器学习-七、使用 AWS 步骤函数构建 ML 工作流 技术要求,构建状态机工作流,执行集成测试,监控管道进度,设置服务权限,创建 ML 工作流程, 在本章中,我们将从第六章中的 [处继续,使用 AWS 步骤函数自动化机器学习过程。您将从那一章中回忆起,我们正在努力实现的主要目标是简化
    Apache CN

  • AWS自动化机器学习-八、使用 Apache Airflow 实现机器学习过程的自动化 技术要求,介绍阿帕奇气流,介绍亚马逊 MWAA,利用气流处理鲍鱼数据集,配置 MWAA 系统的先决条件,配置 MWAA 环境, 当建立一个 ML 模型时,有一个所有 ML 从业者都知道的基本原则;也就是说,最大似然模型只有在数据被训练时
    Apache CN

  • AWS自动化机器学习-五、自动化 ML 模型的持续部署 技术要求,部署 CI/CD 管道,构建 ML 模型工件,执行自动化 ML 模型部署,整理管道结构,创建 CDK 应用,部署管道应用,查看建模文件,审查申请文件,查看模型服务文件,查看容器构建文件,提交 ML 工件,清理, 在 [第 4
    Apache CN

  • 近期文章

    更多
    文章目录

      推荐作者

      更多