【项目开发】使用ruoyi开源软件自动生成代码
若依的代码生成模块,是以数据库中的表为基石,进行创建的。
新建数据库表
(dig_workshop和dig_company):
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for dig_workshop
-- ----------------------------
DROP TABLE IF EXISTS `dig_workshop`;
CREATE TABLE `dig_workshop` (
`workshop_id` bigint NOT NULL AUTO_INCREMENT COMMENT '工作区/车间 ID',
`workshop_name` varchar(100) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '工作区/车间名称',
`workshop_desc` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '描述',
`company_id` bigint DEFAULT NULL COMMENT '隶属公司',
`background_img` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '背景图',
`status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0' COMMENT '帐号状态(0正常 1停用)',
`del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
`create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '创建者',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '更新者',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`workshop_id`)
) ENGINE=InnoDB AUTO_INCREMENT=102 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='工作区/车间主表';
-- ----------------------------
-- Records of dig_workshop
-- ----------------------------
INSERT INTO `dig_workshop` VALUES ('1', '未分配车间', '未分配默认值', '1', '', '0', '0', 'admin', '2021-11-10 11:06:14', '', null);
INSERT INTO `dig_workshop` VALUES ('100', '测控 - 北1楼', '联康测控北边1楼 车间', '4', '', '0', '0', 'admin', '2021-11-10 11:06:57', '', null);
INSERT INTO `dig_workshop` VALUES ('101', '测控 - 南1楼', '联康测控南边1楼 车间', '4', '', '0', '0', 'admin', '2021-11-10 11:07:31', '', null);
-- ----------------------------
-- Table structure for dig_company
-- ----------------------------
DROP TABLE IF EXISTS `dig_company`;
CREATE TABLE `dig_company` (
`company_id` bigint NOT NULL AUTO_INCREMENT COMMENT '公司ID',
`company_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '公司名称',
`company_shortname` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '公司简称',
`belong` tinyint(1) NOT NULL COMMENT '是否是本公司(1是,2不是)',
`create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '创建者',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0' COMMENT '帐号状态(0正常 1停用)',
`del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
`update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '更新者',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`company_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='公司表';
-- ----------------------------
-- Records of dig_company
-- ----------------------------
INSERT INTO `dig_company` VALUES ('1', '江苏联康信息股份有限公司', '联康信息', '1', 'admin', '2021-11-10 10:18:51', '0', '0', '', null);
INSERT INTO `dig_company` VALUES ('2', '深圳联康测控有限公司', '深圳测控', '1', 'admin', '2021-11-10 10:19:29', '0', '0', '', null);
INSERT INTO `dig_company` VALUES ('3', '上海亿克泰电子科技有限公司', '亿克泰', '1', 'admin', '2021-11-10 10:19:51', '0', '0', '', null);
INSERT INTO `dig_company` VALUES ('4', '江苏联康测控有限公司', '江苏测控', '1', 'admin', '2021-11-10 10:20:14', '0', '0', '', null);
启动生成代码模块
导入表结构
在数据库中创建的表,需要先导入。
设置代码生成方式
点击编辑按钮,会出现基本信息,字段信息,生成信息,三个小的模块。
基本信息
字段信息
其中,字段描述,是建表语句中每个字段的Comment
,同时它对应@excel注解中的描述信息,如:
/**工作区/车间名称 */
@Excel(name = "工作区/车间名称")
private String workshopName;
像我这样写的字段过长,再添加修改页面会挤到一起,非常不美观,所以数据库建表的Comment尽量简短一点。
或者在字段信息的生成列表中,进行手动修改。
物理类型是数据库中的字段的类型,Java类型是要生成的代码中的实体类的数据类型。
**java属性,**是把列名去掉下划线,然后转换大小写后,写入到实体类中的属性名。
插入列里的勾选项,是点击新增后,弹出的页面中,显示的列信息。
编辑列里的勾选项,是点击修改后,弹出的页面中,显示的列信息。
列表列里的勾选项,是index页面初始化后,展示的列信息。
查询列里的勾选项,是在index页面上方,显示的查询条件。
查询方式 就是 = != > < like等查询方式
必填,如果勾选的话,它会在vue文件的表单校验中,增加一个判断(文本框前面带个红*
)
其中 背景图, background_img字段不是文本框,而是一个上传图片的控件,这个可以直接选。
status字段是一个单选框,它和 字典表中的
生成信息
生成模板,分为单表Crud,树表crud,主子表crud。
生成的包路径,是生成的代码存放的路径。
模块名就不用说了。
业务名,是这个模块下业务类的名称,对应domain中的dto,而controller和service等也会根据其自动生成。
生成功能名,会出现在java类的description中,也会出现在@log注解中title里。
/**
* 导出车间管理列表
*/
@PreAuthorize(hasPermi = "digital:workshop:export")
@Log(title = "车间管理", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, DigWorkshop digWorkshop) throws IOException
{
List<DigWorkshop> list = digWorkshopService.selectDigWorkshopList(digWorkshop);
ExcelUtil<DigWorkshop> util = new ExcelUtil<DigWorkshop>(DigWorkshop.class);
util.exportExcel(response, list, "车间管理数据");
}
生成方式选择 zip 即可
我前面再数据库中生成了两张表,是因为dig_workshop和dig_company之间有关联关系,通过外键company_id进行关联。
再查询dig_workshop这张表的时候,需要通过company_id关联dig_company查询出对应的company名称,一并返回到前台。
如果模板采用主子表的Crud,那么必须要关联表事先导入。
生成代码
代码生成后,是一个zip格式的文件夹,解压后放到对应的模块下即可。
它同时也生成了菜单的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('车间管理', '2047', '1', 'workshop', 'digital/workshop/index', 1, 0, 'C', '0', '0', 'digital:workshop: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', 'digital:workshop: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', 'digital:workshop: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', 'digital:workshop: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', 'digital:workshop: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', 'digital:workshop:export', '#', 'admin', sysdate(), '', null, '');
直接扔到数据库里运行即可。
运行完之后,车间管理的菜单就出来了,但是它是没有图标的,还需要手动添加一下。
配置文件
到这里,基本上这个模块的简单功能开发,已经接近尾声。
但是,现在代码跑起来,是无法成功运行的,因为yml文件还没有配置。
bootstrap.yml
# Tomcat
server:
port: 9203
# Spring
spring:
application:
# 应用名称
name: ruoyi-digital
profiles:
# 环境配置
active: dev
cloud:
nacos:
discovery:
# 服务注册地址
server-addr: localhost:8848
# 开发环境与生产环境隔离(该配置是dev环境)
namespace: ecb178a8d-429147-91b49-60c2ee-77c2e876e95
config:
# 配置中心地址
server-addr: localhost:8848
# 配置文件格式
file-extension: yml
# 共享配置
shared-configs:
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
# 开发环境与生产环境隔离(该配置是dev环境)
namespace: ecb178a8d-429147-91b49-60c2ee-77c2e876e95
我采用的nacos作为配置中心,它读取的默认格式为:
${prefix}:默认是spring.application.name的值,也就是 ruoyi-digital
${spring.profiles.active}我配的是dev,所以它的值是 dev
。我做的这个项目,配置文件是分离的,开发一套,生产一套,是根据命名空间进行划分的。
namespace: ecb178a8d-429147-91b49-60c2ee-77c2e876e95 就是 dev环境
${file-extension},我配的是 yml
因此我写的这个功能模块的配置文件格式为:ruoyi-digital-dev.yml
我的配置中心和注册服务都是在dev环境中,通过namespace进行隔离。
ruoyi-digital-dev.yml
# spring配置
spring:
redis:
host: localhost
port: 6379
password:
datasource:
druid:
stat-view-servlet:
enabled: true
loginUsername: admin
loginPassword: 123456
dynamic:
druid:
initial-size: 5
min-idle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
filters: stat,slf4j
connectionProperties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000
datasource:
# 主库数据源
master:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/ry-cloud?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: root
# 从库数据源
# slave:
# username:
# password:
# url:
# driver-class-name:
# seata: true # 开启seata代理,开启后默认每个数据源都代理,如果某个不需要代理可单独关闭
# seata配置
seata:
# 默认关闭,如需启用spring.datasource.dynami.seata需要同时开启
enabled: false
# Seata 应用编号,默认为 ${spring.application.name}
application-id: ${spring.application.name}
# Seata 事务组编号,用于 TC 集群名
tx-service-group: ${spring.application.name}-group
# 关闭自动代理
enable-auto-data-source-proxy: false
# 服务配置项
service:
# 虚拟组和分组的映射
vgroup-mapping:
ruoyi-system-group: default
config:
type: nacos
nacos:
serverAddr: 127.0.0.1:8848
group: SEATA_GROUP
namespace:
registry:
type: nacos
nacos:
application: seata-server
server-addr: 127.0.0.1:8848
namespace:
# mybatis配置
mybatis:
# 搜索指定包别名
typeAliasesPackage: com.ruoyi.digital
# 配置mapper的扫描,找到所有的mapper.xml映射文件
mapperLocations: classpath:mapper/**/*.xml
# swagger配置
swagger:
title: 系统模块接口文档
license: Powered By ruoyi
licenseUrl: https://ruoyi.vip
这里面redis和数据库都是连本地的环境,方便测试。
mybatis配置里,搜索的包名要和生成代码中的包名对应
typeAliasesPackage: com.ruoyi.digital :扫描该路径下的所有mapper文件
mapperLocations: classpath:mapper/**/*.xml :扫描类路径下,目录及其子目录中所有以xml结尾的文件
配置文件写好了,项目就可以启动了,但是此时依然无法访问。
因为网关还没有配置。
配置网关
当项目启动时,就已经在nacos中注册了服务名称。
之所以使用gateway网关,就是不想暴露IP地址和端口,仅通过服务名惊醒调用,让网关根据匹配规则,进行请求的转发
ruoyi-gateway-dev.yml
spring:
redis:
host: localhost
port: 6379
password:
cloud:
gateway:
discovery:
locator:
lowerCaseServiceId: true
enabled: true
routes:
# 数字化模块
- id: ruoyi-digital
uri: lb://ruoyi-digital
predicates:
- Path=/digital/**
filters:
- StripPrefix=1
StripPrefix=1 :是截取一位,然后进行匹配。比如当有个请求访问 /digital/workshop/list
路径的时候,它和网关中的ruoyi-digital
规则匹配上,它就会截取请求的前一位,然后再转发到ruoyi-digital
模块中去。
换言之,访问/digital/workshop/list
,就相当于访问 lb://ruoyi-digital/workshop/list
这样配,真的好奇怪,为什么呢?
我觉得第一个原因,是若依的开源作者,想要抹除模块之间的界限。
第二个原因,就是生成的代码中也是这样写的,不这样配不行啊,证据如下:
/**
* 车间管理Controller
* @date 2021-11-10
*/
@RestController
@RequestMapping("/workshop")
public class DigWorkshopController extends BaseController
{// 业务代码略}
请看它的 @RequestMapping
注解。
待完善
网关配置完成后,整个功能模块就跑通了,这只是一个简单的脚手架,有很多业务逻辑和公司业务冲突的地方,还需要更加细致的二次开发。
举个栗子:
文件上的信息展示,明显需要修改。
再比如,底边栏的数据列表,不应该全是input文本框,应该有下拉框和按钮的组合,还有字段的展示,也有待完善。
这只是举得一个小功能里面得一些小瑕疵,像这样得下次,自动生成得代码里还有很多,
尽管如此,ruoyi自动生成代码得功能依然非常强大,避免了程序重复造轮子得窘境。
最后说一句:
拥抱开源