若依管理系统RuoYi-Vue (三):代码⽣成器原理和实战
历史⽂章
本篇⽂章将会讲解ruoyi-vue 系统下代码⽣成器的使⽤、原理分析以及将这部分代码抽离出来形成独⽴版的代码⽣成器。
⼀、代码⽣成器的使⽤
1.新建maven 模块
原则上,我们的业务代码和若依系统本⾝的系统代码是要做隔离的,⼀⽅⾯是易于之后随着若依系统升级⽽升级,另⼀⽅⾯则是纯粹的合理性考虑。
这⾥新建⼀个ruoyi-business 模块作为业务代码模块,新建完ruoyi-business 模块之后添加ruoyi-framework 依赖,pom ⽂件如下所⽰
<?xml version="1.0" encoding="UTF-8"?><project xmlns="/POM/4.0.0"
xmlns:xsi="/2001/XMLSchema-instance"
xsi:schemaLocation="/POM/4.0.0 /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 模块中,代码⽣成的配置在l ⽂件中,由于要在新的模块ruoyi-business 中做开发,要有个新包名,包名取作com.kdyzm.business ,所以l 配置⽂件内容如下:
# 代码⽣成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.fig.ApplicationConfig 类的MapperScan 注解,增加对com.kdyzm 包的扫描
>
@MapperScan({"com.ruoyi.**.mapper","com.kdyzm.**.mapper"})免费模板生成器
public class ApplicationConfig{    ...
}
最后,在ruoyi-admin 新增⼀个Config 类,扫描com.kdyzm 包,以将ruoyi-business 模块中的所有组件纳⼊spring 管理。package fig;import t.annotation.ComponentScan;import t.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
│              └── l
└── 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 链接:
)的商品菜单
可以看到,前后端代码只是复制粘贴,后端接⼝、前端菜单、权限等等⼀切都已经被代码⽣成器帮我们做完了,可以说代码⽣成器极⼤的简化了我们的开发。
四、代码⽣成器⾼级使⽤
在三的测试过程中,我们发现,商品是否上架这个字段对应的前端表单是个⽂本输⼊框,但是实际上这⾥应该是个下拉列表框或者单选按钮才对,因为它只有两个值: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=$lumnComment.indexOf("("))
#if($parentheseIndex != -1)#set($comment=$lumnComment.substring(0, $parentheseIndex))#else
#set($comment=$lumnComment)#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 模块中,根据之前的实际操作体验上来看,最简单的情况,前端页⾯只需要两步即可完成代码⽣成导⼊表结构
⽣成代码实际上这两步对应着后端的两个接⼝:ller.GenController#importTableSave  和 ller.GenController#batchGenCode  ,⽣成源码的步骤就要从这两步下⼿。
⾸先看ller.GenController#importTableSave  接⼝,它做了以下这些事情
1. 从information_schema 数据库的tables 表中查询⽬标表的表明、标注释、创建时间和更新时间,但是忽略掉定时任务的表和已经⽣成过的表。
2. 初始化表数据并将数据插⼊ruoyi 数据库的gen_table 表
3. 从information_schema 数据库的columns 表中查询⽬标表的列信息,包含字段名、字段注释、字段类型、是否允许为null 等详细信息
4. 初始化列信息并将数据插⼊ruoyi 数据库的gen_table_column 表接下来看下 ller.GenController#batchGenCode  接⼝,它做了以下这些事情
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 ⽅法调⽤到相关模块。
3.独⽴版代码⽣成器使⽤⽅法
3.1 配置application.properties 配置⽂件该配置⽂件的内容如下:mysql.username=${dbUserName}
mysql.password=${tionUrl=${dbUrl}
mysql.driverClass=${dbDriverClassName}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 压缩⽂件
七、项⽬源代码>

发表评论