芋道源码微服务架构开发指南

1. 萌新必读

1.1 简介

yudao-cloud ,RuoYi-Vue 全新 Cloud 版本,优化重构所有功能。
基于 Spring Cloud Alibaba + MyBatis Plus + Vue & Element 实现的后台管理系统 + UniApp 微信小程序,支持 RBAC 动态权限、数据权限、SaaS 多租户、Activiti + Flowable 工作流、三方登录、支付、短信、商城等功能

1.1.1. 严肃声明

该博客仅仅用于个人学习芋道源码,博客不能用来做商业用途

「我喜欢写代码,乐此不疲」
「我喜欢学技术,以此为乐」

我 🐶 在深圳艰苦奋斗,早中晚在 【小厂】认真搬砖,夜里为新技术与写博客。

如果这个博客让你有所收获,记得 【关注】我哦,这对我是非常不错的鼓励与支持。

1.1.2. 项目关系


三个项目的功能对比,可见社区共同整理的 国产开源项目 对比表格,我这里只学习微服务的。

1.1.3. 后端项目

| ruoyi-vue-pro | 基于 Spring Boot 多模块架构 |
| yudao-cloud | 基于 Spring Boot 多模块架构 |
| Spring-Boot-Labs| 系统学习 Spring Boot & Cloud 专栏|

1.1.4. 前端项目

| yudao-ui-admin-vue3 |基于 Vue3 + element-plus 实现的管理后台 |
| yudao-ui-admin-vben | 基于 Vue3 + vben(ant-design-vue) 实现的管理后台 |
| yudao-mall-uniapp| 基于 uni-app 实现的商城小程序|
| yudao-ui-admin-vue2 | 基于 Vue2 + element-ui 实现的管理后台 |
| yudao-ui-admin-uniapp | 基于 Vue2 + element-ui 实现的管理后台|
| yudao-ui-go-view| 基于 Vue3 + naive-ui 实现的大屏报表|

1.1.5. 在线体验

下面的地址后期会改成我个人部署的网站
演示地址【Vue3 + element-plus】:http://dashboard-vue3.yudao.iocoder.cn(opens new window)
演示地址【Vue3 + vben(ant-design-vue)】:http://dashboard-vben.yudao.iocoder.cn(opens new window)
演示地址【Vue2 + element-ui】:http://dashboard.yudao.iocoder.cn(opens new window)
如果你要搭建本地环境,可参考如下文档:
快速启动(后端项目)

1.2 交流

1.3 视频教程

1.3.1. 大纲

视频资源可以联系芋道官方,或者联系我上点魔法咯。

每个点都是大章节,包含 10-20 小节的视频。

  • 每个视频,控制在 10 分钟左右,问题驱动,全程无废话,保证高质量的学习。
  • 视频的内容,会带你理解整个系统的设计思想,每一个组件和模块的代码实现。
  • 知其然,知其所以然!让你走出只会 CRUD 的困局~

1.3.2. 技术架构图

1.3.3. 写进简历与自我感悟

自己学习的过程中,往往会碰到如下的问题:

  • 一个人瞎摸索,走弯路,效率低
  • 一脸懵逼,不知道如何学习
  • 遇到问题,无人解答,信心备受打击
  • 遇到一些难题,自己无法透彻理解
  • 知识面狭窄,不知道的太多
    通过这套视频,可以实现 “系统全面,效率高” 的效果。
    学完之后,可以将项目写到简历里噢。如下图所示:

由于我已经工作有两年多了我就直接看文档和源码了,兄弟们刚入行的话还是推荐去看视频哈,
之前我刚入行的时候也在B站大学看了几个月的视频

1.4. 功能列表

1.4.1. 功能技术概括

芋道,以开发者为中心,打造中国第一流的快速开发平台,全部开源,个人与企业可 100% 免费使用。

  • Java 后端:master 分支为 JDK 8 + Spring Boot 2.7,master-jdk17 分支为 JDK 17/21 + Spring Boot 3.2
  • 管理后台的电脑端:Vue3 提供 element-plus (opens new window)、vben(ant-design-vue) (opens new window)两个版本,Vue2 提供 element-ui (opens new window)版本
  • 管理后台的移动端:采用 uni-app (opens new window)方案,一份代码多终端适配,同时支持 APP、小程序、H5!
  • 后端采用 Spring Cloud Alibaba 微服务架构,注册中心 + 配置中心 Nacos,消息队列 RocketMQ,定时任务 XXL-Job,服务保障 Sentinel,服务网关 Gateway,分布式事务 Seata
  • 数据库可使用 MySQL、Oracle、PostgreSQL、SQL Server、MariaDB、国产达梦 DM、TiDB 等,基于 MyBatis Plus、Redis + Redisson 操作
  • 消息队列可使用 Event、Redis、RabbitMQ、Kafka、RocketMQ 等
  • 权限认证使用 Spring Security & Token & Redis,支持多终端、多种用户的认证系统,支持 SSO 单点登录
  • 支持加载动态权限菜单,按钮级别权限控制,本地缓存提升性能
  • 支持 SaaS 多租户系统,可自定义每个租户的权限,提供透明化的多租户底层封装
  • 工作流使用 Flowable,支持动态表单、在线设计流程、会签 / 或签、多种任务分配方式
  • 高效率开发,使用代码生成器可以一键生成 Java、Vue 前后端代码、SQL 脚本、接口文档,支持单表、树表、主子表
  • 实时通信,采用 Spring WebSocket 实现,内置 Token 身份校验,支持 WebSocket 集群
  • 集成微信小程序、微信公众号、企业微信、钉钉等三方登陆,集成支付宝、微信等支付与退款
  • 集成阿里云、腾讯云等短信渠道,集成 MinIO、阿里云、腾讯云、七牛云等云存储服务
  • 集成报表设计器、大屏设计器,通过拖拽即可生成酷炫的报表与大屏

1.4.2. 内置功能

系统内置多种多种业务功能,可以用于快速你的业务系统:

  • 通用模块(必选):系统功能、基础设施
  • 通用模块(可选):工作流程、支付系统、数据报表、会员中心
  • 业务系统(按需):ERP 系统、CRM 系统、商城系统、微信公众号

1.4.3. 系统功能

1.4.4. 基础设施

1.4.5. 工作流程

1.4.6. 支付系统

1.4.7. 数据报表

1.4.8. 微信公众号

1.4.9. 商城系统

演示地址:https://cloud.iocoder.cn/mall-preview/

1.4.10. 会员中心

1.4.11. ERP 系统

演示地址:https://cloud.iocoder.cn/erp-preview/

1.4.13. CRM 系统

演示地址:https://cloud.iocoder.cn/crm-preview/

1.4.14. AI 大模型

演示地址:https://cloud.iocoder.cn/ai-preview/

1.5 快速启动(后端项目)

目标:使用 IDEA 工具,将后端项目 yudao-cloud (opens new window)运行起来 🛫
整个过程非常简单,预计 15 分钟就可以完成,取决于大家的网速。

1.5.1. 克隆代码

使用 IDEA 克隆 https://github.com/YunaiV/yudao-cloud 仓库的最新代码,并给该仓库一个 Star。
注意:不建议使用 Eclipse,因为它没有支持 Lombok 和 Mapstruct 插件。

克隆完成后,耐心等待 Maven 下载完相关的依赖。一定要注意:
① 默认情况下,使用 master 分支,它对应 JDK 8 + Spring Boot 2.7 版本。
② 如果你想体验 JDK 17/21 + Spring Boot 3.2 版本,需要切换到 master-jdk17 分支。

友情提示:项目的每个模块的作用,可见 《开发指南 —— 项目结构》 文档。

使用的 Spring Cloud 版本较新,所以需要下载一段时间。兄弟们这个开源项目还是不错的可以给个 Star 支持下艿艿。

1.5.2. Apifox接口工具

点击 Apifox 首页,下载对应的 Apifox 桌面版。如下图所示:

**多样化使用不同的工具和开发环境是一种明智的选择,这不仅能够提升个人技能,还能使你更快适应各个公司的开发风格。**
接口文档?
阅读 《开发指南 —— 接口文档》 呀~~

1.5.3. 基础设施(必选)

下面的MySQL、Redis、Nacos基础设施【必须】安装,否则项目无法启动。

1.5.4. 初始化 MySQL

补充说明?
由于工作较忙,暂时未拆分到多个数据库,可以按照前缀自行处理:
system_ 前缀,属于 yudao-module-system 服务
infra_ 前缀,属于 yudao-module-infra 服务

我基于芋道SQL进行业务的数据库拆分与主从设置,并且按照业务进行拆分了

项目使用 MySQL 存储数据,所以需要启动一个 MySQL 服务。
① 创建一个名字为 ruoyi-vue-pro 数据库,【只要】 执行对应数据库类型的 sql (opens new window)目录下的 ruoyi-vue-pro.sql SQL 文件,进行初始化。

② 默认配置下,MySQL 需要启动在 3306 端口,并且账号是 root,密码是 123456。如果不一致,需要修改 application-local.yaml 配置文件。

疑问:如果我不是 MySQL,想用其它数据库,怎么办???
1、【如果是 PostgreSQL、Oracle、SQL Server 数据库】,修改 yudao-spring-boot-starter-mybatis 模块的 pom.xml 文件,将对应的 JDBC Driver 的 optional 移除(注意,需要使用 IDEA 刷新下 Maven 的依赖)。如下图所示:

2、【如果是 DM 达梦、大金、OpenGauss 等国产信创数据库】建议先使用 MySQL 跑通,然后再阅读 《国产信创数据库(DM 达梦、大金、OpenGauss)》 文档。

1.5.5. 初始化 Redis

项目使用 Redis 缓存数据,所以需要启动一个 Redis 服务。

不会安装的新手,可以选择阅读下文,好文推荐
Windows 安装 Redis 指南:https://redis.com.cn/redis-installation.html
Mac 安装 Redis 指南:https://juejin.cn/post/7068846712067981326

默认配置下,Redis 启动在 6379 端口,不设置账号密码。如果不一致,需要修改 application-local.yaml 配置文件。

1.5.6. 初始化 Nacos

可以从官网进行下载

暂时的其它技术使用指南使用芋道的,后面有时间会换成我自己的

项目使用 Nacos 作为注册中心和配置中心,参考 《芋道 Nacos 极简入门》 文章,进行安装,只需要看该文的 「2. 单机部署(最简模式)」 即可。

安装完成之后,需要创建 dev 命名空间,如下图所示:

注意!新建命名空间时,它的“命名空间ID”、“命名空间名”都要是 dev 噢!!!

Nacos 拓展学习资料:

《芋道 Spring Cloud Alibaba 配置中心 Nacos 入门》 对应 labx-05-spring-cloud-alibaba-nacos-config
《芋道 Spring Cloud Alibaba 注册中心 Nacos 入门》 对应 labx-01-spring-cloud-alibaba-nacos-discovery

1.-5.7. 基础设施(可选)

本小节的基础设施【可选】安装,不影响项目的启动,可在项目启动后再安装。

如果你想使用 Docker 一键搭建 RocketMQ、XXL-Job 等相关环境,可阅读 https://t.zsxq.com/g9nsF 帖子。后面会换成我的

1.-5.8. RocketMQ

项目使用 RocketMQ 作为消息中心和事件总线,参考 《芋道 RocketMQ 极简入门》 文章,进行安装,只需要看该文的 「2. 单机部署」 即可。

RocketMQ 拓展学习资料:

《芋道 Spring Cloud Alibaba 消息队列 RocketMQ 入门》 对应 labx-06-spring-cloud-stream-rocketmq
《芋道 Spring Cloud Alibaba 事件总线 Bus RocketMQ 入门》 对应 https://github.com/yudaocode/SpringBoot-Labs/tree/master/labx-06-spring-cloud-stream-rocketmq
《性能测试 —— RocketMQ 基准测试》

1.-5.9. XXL-Job

① 项目使用 XXL-Job 作为定时任务,参考 《芋道 XXL-Job 极简入门》 文章,进行安装,只需要看该文的 「4. 搭建调度中心」 即可。

② 默认配置下,本地 local 环境的定时任务是关闭的,避免控制台一直报错报错。如果要开启,请参考 《微服务手册 —— 定时任务》 文档。

1.-5.10. Seata

TODO 接入中,提供实战案例 ing

Seata 拓展学习资料:

《芋道 Spring Cloud Alibaba 分布式事务 Seata 入门 》 对应 对应 labx-17

1.-5.11. Sentinel

TODO 接入中,提供实战案例 ing

Sentinel 拓展学习资料:

《芋道 Spring Cloud Alibaba 服务容错 Sentinel 入门 》 对应 labx-04-spring-cloud-alibaba-sentinel

1.-5.12. Elasticsearch

TODO 接入中,提供实战案例 ing

Elasticsearch 拓展学习资料:

《芋道 Spring Boot Elasticsearch 入门》
《芋道 ELK(Elasticsearch + Logstash + Kibana) 极简入门》

1.-5.13. 启动后端项目

1.-5.14. 编译项目

第一步,使用 IDEA 自带的 Maven 插件,进行项目的编译。如下图所示:

【可选】也可以使用 Maven 命令编译:

  • 使用 IDEA 打开 Terminal 终端,在 根目录 下直接执行 mvn clean install package '-Dmaven.test.skip=true' 命令。
  • 如果执行报 Unknown lifecycle phase “.test.skip=true” 错误,使用 mvn clean install package -Dmaven.test.skip=true 即可。

ps:只有首次需要执行 Maven 命令,解决基础 pom.xml 不存在,导致报 BaseDbUnitTest 类不存在的问题。
整个过程,预计需要 1 分钟左右。成功后,控制台日志如下:

1.-5.15. 启动 gateway 服务

执行 GatewayServerApplication 类,进行启动。

启动还是报类不存在?
可能是 IDEA 的 bug,点击 [File -> Invalidate Caches] 菜单,清空下缓存,重启后在试试看。

启动完成后,使用浏览器访问 http://127.0.0.1:48080 (opens new window)地址,返回如下 JSON 字符串,说明成功。

友情提示:注意,默认配置下,网关启动在 48080 端口。
{"code":404,"data":null,"msg":null}

如果报 “Command line is too long” 错误,参考 《Intellij IDEA 运行时报 Command line is too long 解决方法 》 文章解决,或者直接点击 YudaoServerApplication 蓝字部分!

1.-5.16. 启动 system 服务

执行 SystemServerApplication 类,进行启动。

启动完成后,使用浏览器访问 http://127.0.0.1:48081/admin-api/system/http://127.0.0.1:48080/admin-api/system/ 地址,都返回如下 JSON 字符串,说明成功。

友情提示:注意,默认配置下,yudao-module-system 服务启动在 48081 端口。

{"code":401,"data":null,"msg":"账号未登录"}

1.-5.17. 启动 infra 服务

执行 InfraServerApplication 类,进行启动。

启动完成后,使用浏览器访问 http://127.0.0.1:48082/admin-api/infra/ (opens new window)和 http://127.0.0.1:48080/admin-api/infra/ (opens new window)地址,都返回如下 JSON 字符串,说明成功。

友情提示:注意,默认配置下,yudao-module-infra 服务启动在 48082 端口。

{"code":401,"data":null,"msg":"账号未登录"}

1.-5.18. 启动 bpm 服务

参见 《工作流手册》 文档。

1.-5.19. 启动 report 服务

参见 《大屏手册 》 文档。

1.-5.20. 启动 pay 服务

参见 《支付手册》 文档。

1.-5.21. 启动 mp 服务

参见 《公众号手册》 文档。

1.-5.22. 启动 mall 服务

参见 《商城手册》 文档。

1.-5.23. 启动 erp 服务

参见 《ERP 手册》 文档。

1.-5.24. 启动 crm 服务

参见 《CRM 手册》 文档。

1.-5.25. 启动 ai 服务

参见 《AI 大模型手册》 文档。

1.5.26. 启动前端项目 【简易】

友情提示:这是可选步骤,想要完整启动前端,可以直接看「1.5.26. 启动前端项目【完整】」小节噢!
yudao-demo 项目中,提前编译好了前端项目的静态资源,无需安装 Node 等前端环境,可以直接体验和使用。操作步骤如下:
① 克隆 https://gitee.com/yudaocode/yudao-demo 项目,运行对应的启动类:

  • Vue3 + element-plus (opens new window):ElementPlusApplication
  • Vue3 + vben (opens new window):VbenApplication
  • Vue2 + element-ui (opens new window):ElementUIApplication
    ② 访问 http://127.0.0.1:2048/ (opens new window)地址,即可看到对应的管理后台。

补充说明:

前端项目是不定期编译,可能不是最新版本。

如果需要最新版本,请继续往下看。

1.5.26. 启动前端项目 【完整】

参考 《快速启动(前端项目)》 文档

1.6 快速启动(前端项目)

友情提示:可能胖友本地没有安装 Node.js 的环境,导致报错。可以参考如下文档安装:

Windows 安装 Node.js 指南:http://www.iocoder.cn/NodeJS/windows-install(opens new window)
Mac 安装 Node.js 指南:http://www.iocoder.cn/NodeJS/mac-install

1.6.1. 管理后台 这里我就跑Vue3 + element-plus版本和uniapp和商城的uniapp版本,你们有时间可以都跑下

1.6.1.1 Vue3 + element-plus 版本

yudao-ui-admin-vue3 是前端 Vue3 管理后台项目。

克隆 https://github.com/yudaocode/yudao-ui-admin-vue3.git 项目 。

在根目录执行如下命令,进行启动:

# 安装 pnpm,提升依赖的安装速度
npm config set registry https://registry.npmmirror.com
npm install -g pnpm
# 安装依赖
pnpm install

# 启动服务
npm run dev

启动完成后,浏览器会自动打开 http://localhost:80 地址,可以看到前端界面。

友情提示:Vue3 使用 Vite 构建,所以它存在如下的情况,都是正常的:

  1. 项目启动很快,浏览器打开需要等待 1 分钟左右,请保持耐心。
  2. 点击菜单,感觉会有一点卡顿,因为 Vite 采用懒加载机制。不用担心,最终部署到生产环境,就不存在这个问题了。
    详细说明,可见 《为什么有人说 Vite 快,有人却说 Vite 慢?》 文章。

疑问:我是前端工程师,不想启动后端项目,怎么办?
可以将上述的 npm run dev 命令,替代成 npm run dev-server 命令。
远程 演示环境的后端服务,只允许 GET 请求,不允许 POST、PUT、DELETE 等请求。

1.6.1.2 Vue3 + vben(ant-design-vue) 版本

yudao-ui-admin-vue3 是前端 Vue3 + vben(ant-design-vue) 管理后台项目。

克隆 https://github.com/yudaocode/yudao-ui-admin-vben.git (opens new window)项目,并 Star 关注下该项目。

在根目录执行如下命令,进行启动:

# 安装 pnpm,提升依赖的安装速度
npm config set registry https://registry.npmmirror.com
npm install -g pnpm
# 安装依赖
pnpm install
# 启动服务
npm run dev

启动完成后,浏览器会自动打开 http://localhost:80 地址,可以看到前端界面。

疑问:我是前端工程师,不想启动后端项目,怎么办?
可以将上述的 npm run dev 命令,替代成 npm run front 命令。
远程 演示环境的后端服务,只允许 GET 请求,不允许 POST、PUT、DELETE 等请求。

1.6.1.3 Vue2 + element-ui 版本

yudao-ui-admin-vue2 是前端 Vue2 管理后台项目。

**① **克隆 https://github.com/yudaocode/yudao-ui-admin-vue2.git (opens new window)项目,并 Star 关注下该项目。

**② **在根目录执行如下命令,进行启动:

# 安装 Yarn,提升依赖的安装速度
npm install --global yarn
# 安装依赖
yarn install
# 启动服务
npm run local

疑问:我是前端工程师,不想启动后端项目,怎么办?
可以将上述的 npm run local 命令,替代成 npm run front 命令。
远程 演示环境的后端服务,只允许 GET 请求,不允许 POST、PUT、DELETE 等请求。

1.6.1.4 Vue2 + uni-app 版本

yudao-ui-admin-uniapp 是前端 uni-app 管理后台项目。

克隆 https://github.com/yudaocode/yudao-ui-admin-uniapp.git 项目,并 Star 关注下该项目。

下载 HBuilder (opens new window)工具,并进行安装。

点击 HBuilder 的 [文件 -> 导入 -> 从本地项目导入...] 菜单,选择项目的 yudao-ui-admin-uniapp 目录。

执行如下命令,安装 npm 依赖:

# 安装 npm 依赖
npm i

点击 HBuilder 的 [运行 -> 运行到内置浏览器] 菜单,使用 H5 的方式运行。成功后,界面如下图所示:

友情提示:登录时,滑块验证码,在内存浏览器可能存在兼容性的问题,此时使用 Chrome 浏览器,并使用“开发者工具”,设置为 iPhone 12 Pro 模式!

疑问:我是前端工程师,不想启动后端项目,怎么办?
修改 config.js 配置文件的 baseUrl 后端服务的地址为 'http://api-dashboard.yudao.iocoder.cn。如下图所示:

远程 演示环境的后端服务,只允许 GET 请求,不允许 POST、PUT、DELETE 等请求。

1.6.2 uni-app 商城移动端

yudao-mall-uniapp 是前端 uni-app 商城移动端项目。

前置任务:

需要参考 《商城手册 —— 功能开启》 文档,将商城的后端启动。

克隆 https://github.com/yudaocode/yudao-mall-uniapp (opens new window)项目,并 Star 关注下该项目。

下载 HBuilder (opens new window)工具,并进行安装。

点击 HBuilder 的 [文件 -> 导入 -> 从本地项目导入...] 菜单,选择克隆的 yudao-mall-uniapp 目录

执行如下命令,安装 npm 依赖:

# 安装 npm 依赖
npm i

点击 HBuilder 的 [运行 -> 运行到浏览器 -> Chrome] 菜单,使用 H5 的方式运行。成功后,界面如下图所示:

疑问:我是前端工程师,不想启动后端项目,怎么办?
搜索 http://127.0.0.1:48080 关键字,修改后端服务的地址为 'http://api-dashboard.yudao.iocoder.cn/。如下图所示:

1.7 接口文档

项目使用 Swagger 实现 RESTful API 的接口文档,提供两种解决方案:
*【推荐】 Apifox :强大的 API 工具,支持 API 文档、API 调试、API Mock、API 自动化测试

  • Knife4j:简易的 API 工具,仅支持 API 文档、API 调试

为什么选择 Swagger 呢?
Swagger 通过 Java 注解实现 API 接口文档的编写。相比使用 Java 注释的方式,注解提供更加规范的接口定义方式,开发体验更好。
如果你没有学习 Swagger,可以阅读 《芋道 Spring Boot API 接口文档 Swagger 入门 》文章。

每个服务都会启动 Swagger 的接口文档,方便开发者进行 API 调试。下述的内容,使用 system-server 系统服务举例子,它的端口是 48081。

注> 意!注意!注意!文章部分图中,看到的是 48080 端口,实际你都填写 48081。

1.7.1 Apifox 使用

本小节,我们来将项目中的 API 接口,一键导入到 Apifox 中,并使用它发起一次 API 的调用。

1.7.1.1 下载工具

点击 Apifox 首页,下载对应的 Apifox 桌面版。如下图所示:

为什么要下载 Apifox 桌面版?
我个人觉得小项目快速开发使用 Postman,复杂项目长久开发维护 使用 Apifox 进行替代。国产软件,yyds 永远滴神!
国内很多互联网公司,包括百度、阿里、腾讯、字节跳动等等在内,都在使用 Apifox 作为 API 工具。

1.7.1.2 项目的API 导出

1.7.1.3 API 导入

① 先点击「示例项目」,再点击「+」按钮,选择「导入」选项。

② 先选择「URL 导入」按钮,填写 Swagger 数据 URL 为 http://127.0.0.1:48081/v3/api-docs 。如果失败,则可以尝试 http://127.0.0.1:48080/v3/api-docs/all 解决。

③ 先点击「提交」按钮,再点击「确认导入」按钮,完成 API 接口的导入。

④ 导入完成后,点击「接口管理」按钮,可以查看到 API 列表。

1.7.1.4 API 调试

① 先点击右上角「请选择环境」,再点击「管理环境」选项,填写测试环境的地址为 http://127.0.0.1:48081,并进行保存。

② 点击「管理后台 —— 认证」的「使用账号密码登录」接口,查看该 API 接口的定义。

③ 点击「运行」按钮,填写 Headers 的 tenant-id 为 1,再点击 Body 的「自动生成」按钮,最后点击「发送」按钮。

1.7.2 常见问题

问题 ①:分页 GET 请求时,如果有 createTime 这种时间类型的数组参数,会报错。如下图所示:

答:把 createTime 左右两边的 [] 去掉,即可解决。

1.7.2.1 Knife4j 使用

友情提问:Knife4j 在 master 分支(即 JDK8 版本呢),存在 POST 请求不能生成 JSON 的问题?!
反馈来源:

  • https://t.zsxq.com/Urhsr(opens new window)
  • https://github.com/YunaiV/ruoyi-vue-pro/issues/639(opens new window)
    这个是 Knife4j 自带的 bug,目前只在 master-jdk17 分支(即 JDK17/21)版本可解决。
    比较无奈,没有完美解:
  • ① 如果你把 springdoc.default-flat-param-object 设置为 true 时(目前是这个配置),就会出现这个问题。
  • ② 如果你把 springdoc.default-flat-param-object 设置为 false 时,就不会出现这个问题,但是 GET 请求的参数格式又会不正确。
    = = 所幸,未来大家慢慢都会迁移到 JDK17/21 的版本,这个问题就会自然解决了

1.7.2.2 如何使用?

浏览器访问 http://127.0.0.1:48081/doc.html (opens new window)地址,使用 Knife4j 查看 API 接口文档。

① 点击任意一个接口,进行接口的调用测试。这里,使用「管理后台 - 用户个中心」的“获得登录用户信息”举例子。

② 点击左侧「调试」按钮,并将请求头部的 header-id 和 Authorization 勾选上。

其中,header-id 为租户编号,Authorization 的 "Bearer test" 后面为用户编号(模拟哪个用户操作)。

③ 点击「发送」按钮,即可发起一次 API 的调用。

也可以在项目中点击系统目录进行访问

如何使用 Gateway 网关,聚合各个服务的接口文档?
参见 《微服务手册 —— 服务网关》 文档

1.7.2.3 如何开启登录?

生产环境下,建议 Knife4j 接口界面开启“安全认证”的功能,避免出现安全事故。
只需要在 knife4j.basic 配置项中,额外添加 Basic Auth 认证即可,如下所示:

knife4j:
  basic:
    enable: true
    username: admin # Basic 认证用户名
    password: admin # Basic 认证密码

1.7.3 Swagger 技术组件

① 在 yudao-spring-boot-starter-web (opens new window)技术组件的 swagger (opens new window)包,实现了对 Swagger 的封装。

② 如果想要禁用 Swagger 功能,可通过 springdoc.api-docs.enable 配置项为 false。一般情况下,建议 prod 生产环境进行禁用,避免发生安全问题。

友情提示:除了通过 enable 进行关闭外,更建议的是通过 knife4j 提供的 knife4j.production = true 来实现

1.8 技术选型

1.8.1 技术架构图

1.8.2 后端

1.8.2.1 系统环境

框架 说明 版本 学习指南
JDK Java 开发工具包 JDK 17 或者 JDK8 书单
Maven Java 管理与构建工具 >= 3.5.4 书单
Nginx 高性能 Web 服务器 - 文档

1.8.2.2 主框架

框架 说明 版本 学习指南
Spring Cloud Alibaba(opens new window) 微服务框架 2023.0.1 文档
Spring MVC(opens new window) MVC 框架 6.1.10 文档
Spring Security(opens new window) Spring 安全框架 6.3.1 文档
Hibernate Validator(opens new window) 参数校验组件 8.0.1 文档

1.8.2.3 存储层

框架 说明 版本 学习指南
MySQL 数据库服务器 >= 5.7 文档
Druid JDBC 连接池、监控组件 1.2.23 文档
MyBatis Plus MyBatis 增强工具包 3.5.7 文档
Dynamic Datasource 动态数据源 4.3.1 文档
Redis key-value 数据库 >= 5.0 文档
Redisson Redis 客户端 3.32.0 文档

1.8.2.4 中间件

框架 说明 版本 学习指南
Nacos 配置中心 & 注册中心 2.3.2 文档
RocketMQ 消息队列 5.2.0 文档
Sentinel 服务保障 1.8.6 文档
XXL Job 定时任务 2.4.0 文档
Spring Cloud Gateway 服务网关 4.1.0 文档
Seata 分布式事务 1.6.1 文档
Flowable 工作流引擎 7.0.0 文档

1.8.2.5 系统监控

框架 说明 版本 学习指南
Spring Boot Admin Spring Boot 监控平台 3.6.1 文档
SkyWalking 分布式应用追踪系统 9.0.0 文档

1.8.2.6 单元测试

框架 说明 版本 学习指南
JUnit Java 单元测试框架 5.10.1 文档
Mockito Java Mock 框架 5.7.0 文档

1.8.2.7 其它工具

框架 说明 版本 学习指南
Springdoc Swagger 文档 2.3.0 文档
Jackson JSON 工具库 2.17.1 文档
MapStruct Java Bean 转换 1.5.5.Final 文档
Lombok 消除冗长的 Java 代码 1.18.34 文档

1.8.3 前端

1.8.3.1 管理后台(Vue3 + ElementPlus)

框架 说明 版本
Vue vue 框架 3.2.45
Vite 开发与构建工具 4.0.1
Element Plus Element Plus 2.2.26
TypeScript JavaScript 的超集 4.9.4
pinia Vue 存储库 替代 vuex5 2.0.28
vueuse 常用工具集 9.6.0
vxe-table vue 最强表单 4.3.7
vue-i18n 国际化 9.2.2
vue-router vue 路由 4.1.6
UnoCSS 下一代工具优先的 CSS 框架 0.58.9
iconify 在线图标库 3.0.0
wangeditor 富文本编辑器 5.1.23

1.8.3.2 管理后台(Vue3 + Vben + Ant-Design-Vue)

框架 说明 版本
Vue vue 框架 3.2.45
Vite 开发与构建工具 4.0.1
Element Plus ant-design-vue 3.2.17
TypeScript JavaScript 的超集 4.9.4
pinia Vue 存储库 替代 vuex5 2.0.28
vueuse 常用工具集 9.6.0
vue-i18n 国际化 9.2.2
vue-router vue 路由 4.1.6
UnoCSS 下一代工具优先的 CSS 框架 0.58.9
iconify 在线图标库 3.0.0

1.8.3.3 管理后台(Vue2)

框架 说明 版本 学习指南
Node JavaScript 运行时环境 >= 12 -
Vue JavaScript 框架 2.7.14 书单
Vue Element Admin 后台前端解决方案 2.5.10 -

1.8.3.4 管理后台(uni-app)

框架 说明 版本
uni-app 跨平台框架 2.0.0
uni-ui 基于 uni-app 的 UI 框架 1.4.20

1.8.3.4 用户 App

框架 说明 版本 学习指南
Vue JavaScript 框架 2.6.12 书单
UniApp 小程序、H5、App 的统一框架 - -

<span id="xiangmujiegou"; style="color: blue; font-weight: bold;">1.9 项目结构

0. 后端结构

后端采用模块化的架构,按照功能拆分成多个 Maven Module,提升开发与研发的效率,带来更好的可维护性。

一共有四类 Maven Module:

Maven Module 作用
yudao-dependencies Maven 依赖版本管理
yudao-framework Java 框架拓展
yudao-module-xxx XXX 功能的 Module 模块
yudao-server 管理后台 + 用户 App 的服务端

下面,我们来逐个看看。

1. yudao-dependencies

该模块是一个 Maven Bom,只有一个 pom.xml 文件,定义项目中所有 Maven 依赖的版本号,解决依赖冲突问题。

详细的解释,可见 《微服务中使用 Maven BOM 来管理你的版本依赖 》 文章。

从定位上来说,它和 Spring Boot 的 spring-boot-starter-parent 和 Spring Cloud 的 spring-cloud-dependencies 是一致的。

实际上,yudao-cloud 本质上还是个单体项目,直接在根目录 pom.xml (opens new window)管理依赖版本会更加方便,也符合绝大多数程序员的认知。但是要额外考虑一个场景,如果每个 yudao-module-xxx 模块都维护在一个独立的 Git 仓库,那么 yudao-dependencies 就可以在多个 yudao-module-xxx 模块下复用。

2. yudao-framework

该模块是 yudao-cloud 项目的框架封装,其下的每个 Maven Module 都是一个组件,分成两种类型:

① 技术组件:技术相关的组件封装,例如说 MyBatis、Redis 等等。

Maven Module 作用
yudao-common 定义基础 pojo 类、枚举、工具类等
yudao-spring-boot-starter-web Web 封装,提供全局异常、访问日志等
yudao-spring-boot-starter-websocket WebSocket 封装,提供 Token 认证、WebSocket 集群广播、Message 监听
yudao-spring-boot-starter-security 认证授权,基于 Spring Security 实现
yudao-spring-boot-starter-mybatis 数据库操作,基于 MyBatis Plus 实现
yudao-spring-boot-starter-redis 缓存操作,基于 Spring Data Redis + Redisson 实现
yudao-spring-boot-starter-mq 消息队列,基于 Redis 实现,支持集群消费和广播消费
yudao-spring-boot-starter-job 定时任务,基于 Quartz 实现,支持集群模式
yudao-spring-boot-starter-protection 服务保障,提供幂等、分布式锁、限流、熔断等功能
yudao-spring-boot-starter-excel Excel 导入导出,基于 EasyExcel 实现
yudao-spring-boot-starter-monitor 服务监控,提供链路追踪、日志服务、指标收集等功能
yudao-spring-boot-starter-test 单元测试,基于 Junit + Mockito 实现
yudao-spring-boot-starter-file 【已合并】 文件客户端,支持将文件存储到 S3(MinIO、阿里云、腾讯云、七牛云)、本地、FTP、SFTP、数据库等
yudao-spring-boot-starter-captcha 【已合并】 验证码 Captcha,提供滑块验证码
yudao-spring-boot-starter-flowable 【已合并】 工作流,基于 Flowable 实现

友情提示:

  • yudao-spring-boot-starter-file 组件:自 2.0.1 版本,合并到 yudao-module-infra-biz 模块的 framework/file 包下,一方面减少 starter 提升编译速度,一方面只有 infra 模块使用到
  • yudao-spring-boot-starter-captcha 组件:自 2.0.1 版本,合并到 yudao-module-system-biz 模块的 framework/captcha 包下,一方面减少 starter 提升编译速度,一方面只有 system 模块使用到
  • yudao-spring-boot-starter-flowable 组件:自 2.0.1 版本,合并到 yudao-module-bpm-biz 模块的 framework/flowable 包下,一方面减少 starter 提升编译速度,一方面只有 bpm 模块使用到

② 业务组件:业务相关的组件封装,例如说数据字典、操作日志等等。如果是业务组件,名字会包含 biz 关键字。

Maven Module 作用
yudao-spring-boot-starter-biz-tenant SaaS 多租户
yudao-spring-boot-starter-biz-data-permission 数据权限
yudao-spring-boot-starter-biz-operatelog 操作日志
yudao-spring-boot-starter-biz-pay 支付客户端,对接微信支付、支付宝等支付平台
yudao-spring-boot-starter-biz-ip 地区 & IP 库

友情提示:

  • yudao-spring-boot-starter-biz-operatelog 组件:自 2.1.0 版本,合并到 yudao-spring-boot-starter-security 组件的 operatelog 包下,主要减少 starter 提升编译速度

每个组件,包含两部分:

  1. core 包:组件的核心封装,拓展相关的功能。
  2. config 包:组件的 Spring Boot 自动配置。

3. yudao-module-xxx

该模块是 XXX 功能的 Module 模块,目前内置了 8 个模块。

项目 说明 是否必须
yudao-module-system 系统功能
yudao-module-infra 基础设施
yudao-module-member 会员中心 x
yudao-module-bpm 工作流程 x
yudao-module-pay 支付系统 x
yudao-module-report 大屏报表 x
yudao-module-mall 商城系统 x
yudao-module-erp ERP 系统 x
yudao-module-crm CRM 系统 x
yudao-module-ai AI 大模型 x
yudao-module-mp 微信公众号 x

每个模块包含两个 Maven Module,分别是:

Maven Module 作用
yudao-module-xxx-api 提供给其它模块的 API 定义
yudao-module-xxx-biz 模块功能的具体实现

例如说,yudao-module-infra 想要访问 yudao-module-system 的用户、部门等数据,需要引入 yudao-module-system-api 子模块。示例如下:

yudao-module-xxx-api 子模块的项目结构如下:

所在包 作用 示例
api Api 接口 提供给其它模块的 API 接口 AdminUserApi
api DTO 类 Api 接口的入参 ReqDTO、出参 RespDTO LoginLogCreateReqDTO, DeptRespDTO
enums Enum 类 字段的枚举 LoginLogTypeEnum
enums DictTypeConstants 类 数据字典的枚举 DictTypeConstants
enums ErrorCodeConstants 类 错误码的枚举 ErrorCodeConstants

yudao-module-xxx-biz 子模块的项目结构如下:

所在包 作用 示例
api ApiImpl 类 提供给其它模块的 API 实现类 AdminUserApiImpl
controler.admin Controller 类 提供给管理后台的 RESTful API,默认以 admin-api/ 作为前缀。 AuthController
controler.admin VO 类 Admin Controller 接口的入参 ReqVO、出参 RespVO AuthLoginReqVO, AuthLoginRespVO
controler.app Controller 类 提供给用户 App 的 RESTful API,默认以 app-api/ 作为前缀。 AppAuthController
controler.app VO 类 App Controller 接口的入参 ReqVO、出参 RespVO AppAuthLoginReqVO, AppAuthLoginRespVO
controler .http 文件 IDEA Http Client 插件,模拟请求 RESTful 接口 AuthController.http
service Service 接口 业务逻辑的接口定义 AdminUserService
service ServiceImpl 类 业务逻辑的实现类 AdminUserServiceImpl
dal - Data Access Layer,数据访问层
dal.dataobject DO 类 Data Object,映射数据库表、或者 Redis 对象 AdminUserDO
dal.mysql Mapper 接口 数据库的操作 AdminUserMapper
dal.redis RedisDAO 类 Redis 的操作 LoginUserRedisDAO
convert Convert 接口 DTO / VO / DO 等对象之间的转换器 UserConvert
job Job 类 定时任务 DemoJob
mq - Message Queue,消息队列
mq.message Message 类 发送和消费的消息 SmsSendMessage
mq.producer Producer 类 消息的生产者 SmsProducer
mq.consumer Consumer 类 消息的消费者 SmsSendConsumer
framework - 模块自身的框架封装 framework

疑问:为什么 Controller 分成 Admin 和 App 两种?
提供给 Admin 和 App 的 RESTful API 接口是不同的,拆分后更加清晰。

疑问:为什么 VO 分成 Admin 和 App 两种?
相同功能的 RESTful API 接口,对于 Admin 和 App 传入的参数、返回的结果都可能是不同的。例如说,Admin 查询某个用户的基本信息时,可以返回全部字段;而 App 查询时,不会返回 mobile 手机等敏感字段。

疑问:为什么 DO 不作为 Controller 的出入参?
1.明确每个 RESTful API 接口的出入参。例如说,创建部门时,只需要传入 name、parentId 字段,使用 DO 接参就会导致 type、createTime、creator 等字段可以被传入,导致前端同学一脸懵逼。
2. 每个 RESTful API 有自己独立的 VO,可以更好的设置 Swagger 注解、Validator 校验规则,而让 DO 保持整洁,专注映射好数据库表。

疑问:为什么操作 Redis 需要通过 RedisDAO?
Service 直接使用 RedisTemplate 操作 Redis,导致大量 Redis 的操作细节和业务逻辑杂糅在一起,导致代码不够整洁。通过 RedisDAO 类,将每个 Redis Key 像一个数据表一样对待,清晰易维护。

总结来说,每个模块采用三层架构 + 非严格分层,如下图所示:

疑问:如果 message 需要跨模块共享,类似 api 的效果,可以怎么做?
可以在 yudao-module-xxx-api 子模块下,新建一个 message 包,可参考 MemberUserCreateMessage 类。

4. yudao-server

该模块是后端 Server 的主项目,通过引入需要 yudao-module-xxx 业务模块,从而实现提供 RESTful API 给 yudao-ui-admin-vue3、yudao-mall-uniapp 等前端项目。

本质上来说,它就是个空壳(容器)!如下图所示:

0. 前端结构

项目 说明
yudao-ui-admin-vue3 [打开新窗口] 基于 Vue3 + element-plus 实现的管理后台
yudao-ui-admin-vben [打开新窗口] 基于 Vue3 + vben(ant-design-vue) 实现的管理后台
yudao-ui-admin-vue2 [打开新窗口] 基于 Vue2 + element-ui 实现的管理后台
yudao-ui-go-view [打开新窗口] 基于 Vue3 + naive-ui 实现的大屏报表
yudao-ui-admin-uniapp [打开新窗口] 基于 uni-app + uni-ui 实现的管理后台的小程序
yudao-mall-uniapp [打开新窗口] 基于 uni-app + uview 实现的用户 App

1. yudao-ui-admin-vue3

.
├── .github # github workflows 相关
├── .husky # husky 配置
├── .vscode # vscode 配置
├── mock # 自定义 mock 数据及配置
├── public # 静态资源
├── src # 项目代码
│   ├── api # api接口管理
│   ├── assets # 静态资源
│   ├── components # 公用组件
│   ├── hooks # 常用hooks
│   ├── layout # 布局组件
│   ├── locales # 语言文件
│   ├── plugins # 外部插件
│   ├── router # 路由配置
│   ├── store # 状态管理
│   ├── styles # 全局样式
│   ├── utils # 全局工具类
│   ├── views # 路由页面
│   ├── App.vue # 入口vue文件
│   ├── main.ts # 主入口文件
│   └── permission.ts # 路由拦截
├── types # 全局类型
├── .env.base # 本地开发环境 环境变量配置
├── .env.dev # 打包到开发环境 环境变量配置
├── .env.gitee # 针对 gitee 的环境变量 可忽略
├── .env.pro # 打包到生产环境 环境变量配置
├── .env.test # 打包到测试环境 环境变量配置
├── .eslintignore # eslint 跳过检测配置
├── .eslintrc.js # eslint 配置
├── .gitignore # git 跳过配置
├── .prettierignore # prettier 跳过检测配置
├── .stylelintignore # stylelint 跳过检测配置
├── .versionrc 自动生成版本号及更新记录配置
├── CHANGELOG.md # 更新记录
├── commitlint.config.js # git commit 提交规范配置
├── index.html # 入口页面
├── package.json
├── .postcssrc.js # postcss 配置
├── prettier.config.js # prettier 配置
├── README.md # 英文 README
├── README.zh-CN.md # 中文 README
├── stylelint.config.js # stylelint 配置
├── tsconfig.json # typescript 配置
├── vite.config.ts # vite 配置
└── windi.config.ts # windicss 配置

2. yudao-ui-admin-vben

.
├── build # 打包脚本相关
│   ├── config # 配置文件
│   ├── generate # 生成器
│   ├── script # 脚本
│   └── vite # vite配置
├── mock # mock文件夹
├── public # 公共静态资源目录
├── src # 主目录
│   ├── api # 接口文件
│   ├── assets # 资源文件
│   │   ├── icons # icon sprite 图标文件夹
│   │   ├── images # 项目存放图片的文件夹
│   │   └── svg # 项目存放svg图片的文件夹
│   ├── components # 公共组件
│   ├── design # 样式文件
│   ├── directives # 指令
│   ├── enums # 枚举/常量
│   ├── hooks # hook
│   │   ├── component # 组件相关hook
│   │   ├── core # 基础hook
│   │   ├── event # 事件相关hook
│   │   ├── setting # 配置相关hook
│   │   └── web # web相关hook
│   ├── layouts # 布局文件
│   │   ├── default # 默认布局
│   │   ├── iframe # iframe布局
│   │   └── page # 页面布局
│   ├── locales # 多语言
│   ├── logics # 逻辑
│   ├── main.ts # 主入口
│   ├── router # 路由配置
│   ├── settings # 项目配置
│   │   ├── componentSetting.ts # 组件配置
│   │   ├── designSetting.ts # 样式配置
│   │   ├── encryptionSetting.ts # 加密配置
│   │   ├── localeSetting.ts # 多语言配置
│   │   ├── projectSetting.ts # 项目配置
│   │   └── siteSetting.ts # 站点配置
│   ├── store # 数据仓库
│   ├── utils # 工具类
│   └── views # 页面
├── test # 测试
│   └── server # 测试用到的服务
│       ├── api # 测试服务器
│       ├── upload # 测试上传服务器
│       └── websocket # 测试ws服务器
├── types # 类型文件
├── vite.config.ts # vite配置文件
└── windi.config.ts # windcss配置文件

3. yudao-admin-ui


├── bin                        // 执行脚本
├── build                      // 构建相关  
├── public                     // 公共文件
│   ├── favicon.ico            // favicon 图标
│   └── index.html             // html 模板
│   └── robots.txt             // 反爬虫
├── src                        // 源代码
│   ├── api                    // 所有请求【重要】
│   ├── assets                 // 主题、字体等静态资源
│   ├── components             // 全局公用组件
│   ├── directive              // 全局指令
│   ├── icons                  // 图标
│   ├── layout                 // 布局
│   ├── plugins                // 插件
│   ├── router                 // 路由
│   ├── store                  // 全局 store 管理
│   ├── utils                  // 全局公用方法
│   ├── views                  // 视图【重要】
│   ├── App.vue                // 入口页面
│   ├── main.js                // 入口 JS,加载组件、初始化等
│   ├── permission.js          // 权限管理
│   └── settings.js            // 系统配置
├── .editorconfig              // 编码格式
├── .env.development           // 开发环境配置
├── .env.production            // 生产环境配置
├── .env.staging               // 测试环境配置
├── .eslintignore              // 忽略语法检查
├── .eslintrc.js               // eslint 配置项
├── .gitignore                 // git 忽略项
├── babel.config.js            // babel.config.js
├── package.json               // package.json
└── vue.config.js              // vue.config.js

4. yudao-admin-ui-uniapp

TODO 待补充

5. yudao-mall-uniapp

├── pages // 页面
│ ├── index // 入口页面
│ ├── user // 用户相关
│ ├── public // 公共页面
│ ├── activity // 活动页面
│ ├── app // 积分、签到页面
│ ├── chat // 客服页面
│ ├── commission // 分销页面
│ ├── coupon // 优惠券页面
│ ├── goods // 商品页面
│ ├── order // 订单页面
│ ├── pay // 支付页面
├── sheep // 底层依赖/工具库
│ ├── api // 服务端接口
│ ├── components // 自定义功能组件
│ ├── config // 配置文件
│ ├── helper // 助手函数
│ ├── hooks // vue-hooks
│ ├── libs // 自定义依赖
│ ├── platform // 第三方平台登录、分享、支付
│ ├── request // 请求类库
│ ├── router // 自定义路由跳转
│ ├── scss // 主样式库
│ ├── store // pinia状态管理模块
│ ├── ui // 自定义UI组件
│ ├── url // cdn图片地址格式化
│ ├── validate // 通用验证器
│ ├── index.js // Shopro入口文件
├── uni_modules // dcloud第三方插件

  1. yudao-ui-go-view
    TODO 待补充

1.10 代码热加载

JRebel 插件
JRebel 插件是目前最好用的热加载插件,它支持 IDEA Ultimate 旗舰版、Community 社区版。

直接去看文档吧
https://einverne.gitbook.io/intellij-idea-tutorial/jrebel-setup

1.11 一键改包

项目提供了 ProjectReactor 程序,支持一键改包,包括 Maven 的 groupId、artifactId、Java 的根 package、前端的 title、数据库的 SQL 配置、应用的 application.yaml 配置文件等等。效果如下图所示:

友情提示:修改包名后,未来合并最新的代码可能会有一定的成本。

主要有两点原因:
① 改包后,无法继续通过 git pull 拉取最新代码
② 市面上没有合适的工具,合并改包后的代码
这个存在于所有开源项目,不属于本项目的问题,希望可以理解!

操作步骤
① 第一步,使用 IDEA (opens new window)克隆 https://github.com/YunaiV/yudao-cloud (opens new window)仓库的最新代码,并给该仓库一个 Star (opens new window)。
② 第二步,打开 ProjectReactor 类,填写 groupIdNew、artifactIdNew、packageNameNew、titleNew 属性。如下图所示:

另外,如下两个属性也必须修改:

  • projectBaseDir 属性:修改为你 yudao-cloud 所在目录的绝对地址
  • projectBaseDirNew 属性:修改为你想要的新项目的绝对地址。注意,不要有 yudao 关键字。
    ③ 第三步,执行 ProjectReactor 的 #main(String[] args) 方法,它会基于当前项目,复制一个新项目到 projectBaseDirNew 目录,并进行相关的改名逻辑。
11:19:11.180 [main] INFO cn.iocoder.yudao.ProjectReactor - [main][原项目路劲改地址 (/Users/yunai/Java/yudao-cloud-2023)]
11:19:11.184 [main] INFO cn.iocoder.yudao.ProjectReactor - [main][检测新项目目录 (/Users/yunai/Java/xx-new)是否存在]
11:19:11.298 [main] INFO cn.iocoder.yudao.ProjectReactor - [main][完成新项目目录检测,新项目路径地址 (/Users/yunai/Java/xx-new)]
11:19:11.298 [main] INFO cn.iocoder.yudao.ProjectReactor - [main][开始获得需要重写的文件,预计需要 10-20 秒]
11:19:12.169 [main] INFO cn.iocoder.yudao.ProjectReactor - [main][需要重写的文件数量:1573,预计需要 15-30 秒]
11:19:14.607 [main] INFO cn.iocoder.yudao.ProjectReactor - [main][重写完成]共耗时:3

④ 第四步,使用 IDEA 打开 projectBaseDirNew 目录,参考 《开发指南 —— 快速启动》 文档,进行项目的启动。注意,一定要重新执行 SQL 的导入!!!

1.12 迁移模块(适合新项目)

1.后端代码迁移

后端代码迁移,指的是将【完整版】的代码,复制张贴到【精简版】。

项目 说明
yudao-module-member 会员中心的 Module 模块
yudao-module-pay 支付系统的 Module 模块
yudao-module-mall 商城系统的 Module 模块
yudao-module-erp ERP 系统的 Module 模块
yudao-module-crm CRM 系统的 Module 模块
yudao-module-mp 微信公众号的 Module 模块
yudao-module-report 大屏报表 Module 模块

1.1迁移步骤

① 第一步,选择一个你想要迁移的 Maven 模块的代码,复制粘贴过去。例如说:

② 第二步(可选),如果迁移的模块有 test 单元测试,需要删除对应的 test 目录,和 yudao-spring-boot-starter-test 依赖,如下图所示:

疑问:为什么要删除 test 目录和依赖呢?
因为【精简版】考虑到大家可能不需要单元测试,所以一并清理了。

下面,可以按照你的场景,进行一下操作。

注意!不需要每个场景都操作,只需要你需要的!!!

1.2 场景:我要做 BPM 工作流

将 yudao-module-bpm 模块,从【完整版】复制到【精简版】。然后参考 《工作流手册》 文档,测试迁移的正确性。

1.3 场景:我要做 CRM 系统

① 将 yudao-module-bpm 模块,从【完整版】复制到【精简版】。然后参考 《工作流手册》 文档,测试迁移的正确性。

② 将 yudao-module-crm 模块,从【完整版】复制到【精简版】。然后参考 《CRM 系统手册》 文档,测试迁移的正确性。

1.4 场景:我要做 ERP 系统

将 yudao-module-erp 模块,从【完整版】复制到【精简版】。然后参考 《ERP 系统手册》 文档,测试迁移的正确性。

1.5 场景:我要做 MALL 商城

① 将 yudao-module-member 模块,从【完整版】复制到【精简版】。然后参考 《会员中心手册》 文档,测试迁移的正确性。

② 将 yudao-module-pay 模块,从【完整版】复制到【精简版】。然后参考 《支付系统手册》 文档,测试迁移的正确性。

③ 将 yudao-module-mall 模块,从【完整版】复制到【精简版】。然后参考 《商城系统手册》 文档,测试迁移的正确性。

友情提示:因为 MALL 商城需要的模块比较多,我们其实也可以基于【完整版】,删除不需要的 Module 模块。
只需要删除 yudao-module-erp、yudao-module-report、yudao-module-mp、yudao-module-bpm、yudao-module-crm 模块,也是蛮方便的!

1.6 场景:我要做 REPORT 大屏报表

将 yudao-module-report 模块,从【完整版】复制到【精简版】。然后参考 《大屏手册》 文档,测试迁移的正确性。

1.7 其它场景补充

① 【会员】如果你要给你 C 端(会员)做一个 App 或者 H5,需要使用到「会员」功能,可以将 yudao-module-member 模块,从【完整版】复制到【精简版】。然后参考 《会员中心手册》 文档,测试迁移的正确性。

② 【支付】如果你的系统需要使用到支付宝、微信等支付功能,可以将 yudao-module-pay 模块,从【完整版】复制到【精简版】。然后参考 《支付系统手册》 文档,测试迁移的正确性。

③ 【公众号】如果你的系统需要使用到微信公众号功能,可以将 yudao-module-mp 模块,从【完整版】复制到【精简版】。然后参考 《公众号手册》 文档,测试迁移的正确性

2.前端代码清理

前端仓库,不区分【完整版】【精简版】,因为它本身就比较简单。只需要删除 api 和 views 下面对应的模块即可。如下图所示

前端 api 和 views 下面的模块,对应后端的 yudao-module-xxx 模块。所以后端没有迁移的模块,前端也需要删除。

如果碰到 remaining.ts 路由报错,可见 https://t.zsxq.com/69GWJ (opens new window)帖子!

3. 数据库清理

数据库的迁移,只设计到两份“配置”表:

  • 菜单相关:system_menu
  • 字典相关:system_dict_data、system_dict_type

3.1 清理菜单

系统的菜单划分,也是按照模块来的。所以只需要删除没迁移的模块的菜单即可。如下图所示:

# 删除顶级菜单:name 需要换成想要删除模块的菜单名
DELETE FROM system_menu WHERE name = '支付管理';

# 删除子菜单:多次执行,直到 Affected rows: 0 影响条数为 0
DELETE FROM system_menu WHERE parent_id NOT IN (SELECT id FROM (SELECT id FROM system_menu) AS TEMP) AND parent_id > 0

# 删除关联表
DELETE FROM system_role_menu WHERE menu_id NOT IN (SELECT id FROM system_menu)

3.2 字典清理

字典的清理,可以通过 SQL 完成。

# 删除 `yudao-module-member` 不要的字典数据
DELETE FROM system_dict_type WHERE type LIKE 'member_%';
DELETE FROM system_dict_data WHERE dict_type LIKE 'member_%';

# 删除 `yudao-module-pay` 不要的字典数据
DELETE FROM system_dict_type WHERE type LIKE 'pay_%';
DELETE FROM system_dict_data WHERE dict_type LIKE 'pay_%';

# 删除 `yudao-module-mall` 不要的字典数据
DELETE FROM system_dict_type WHERE type LIKE 'product_%';
DELETE FROM system_dict_data WHERE dict_type LIKE 'product_%';
DELETE FROM system_dict_type WHERE type LIKE 'trade_%';
DELETE FROM system_dict_data WHERE dict_type LIKE 'trade_%';
DELETE FROM system_dict_type WHERE type LIKE 'promotion_%';
DELETE FROM system_dict_data WHERE dict_type LIKE 'promotion_%';
DELETE FROM system_dict_type WHERE type LIKE 'brokerage_enabled_condition_%';
DELETE FROM system_dict_data WHERE dict_type LIKE 'brokerage_enabled_condition_%';

# 删除 `yudao-module-erp` 不要的字典数据
DELETE FROM system_dict_type WHERE type LIKE 'erp_%';
DELETE FROM system_dict_data WHERE dict_type LIKE 'erp_%';

# 删除 `yudao-module-crm` 不要的字典数据
DELETE FROM system_dict_type WHERE type LIKE 'crm_%';
DELETE FROM system_dict_data WHERE dict_type LIKE 'crm_%';

# 删除 `yudao-module-mp` 不要的字典数据
DELETE FROM system_dict_type WHERE type LIKE 'mp_%';
DELETE FROM system_dict_data WHERE dict_type LIKE 'mp_%';

# 删除 `yudao-module-report` 不要的字典数据
DELETE FROM system_dict_type WHERE type LIKE 'report_%';
DELETE FROM system_dict_data WHERE dict_type LIKE 'report_%';


1.13 删除功能(以租户为例)

项目内置功能较多,会存在一些你可能用不到的功能。一般的情况下,建议通过设置该功能对应的菜单为【禁用】,实现功能的“删除”。如下图所示:

后续,如果你又需要使用到该功能,只需要设置该功能对应的菜单为【开启】即可。

🙂 当然,如果你希望彻底删除功能,那么就需要采用删除代码的方式。整个过程如下:

① 【菜单】第一步,使用管理后台的菜单管理,删除对应的菜单、按钮。
② 【数据库表】第二步,删除对应的数据库表。
③ 【后端代码】第三步,删除对应的 Controller、Service、数据库实体等后端代码;然后启动后端项目,若存在代码报错,则继续删除相关联的代码,之后如此反复,直到成功。
④ 【前端代码】第四步,删除对应的 View 和 API 等前端代码;然后启动前端项目,若存在代码报错,则继续删除相关联的代码,之后如此反复,直到成功。

下面,我们来举一些例子。

删除「多租户」功能

  • 对应功能的文档: 多租户
  • 对应的关键字是 tenant

第一步,删除菜单

删除“租户管理“下的所有菜单,从最里层的按钮开始。如下图所示:

第二步,删除数据库表

删除 system_tenant 和 system_tenant_package 表。如下图所示:

第三步,删除后端代码

① 删除 yudao-module-system-api 模块的 api/tenant (opens new window)包。
② 删除 yudao-module-system-api 模块的 ErrorCodeConstants (opens new window)类中,和租户、租户套餐相关的错误码。如下图所示:

如果想删除的更干净,可以把 system_error_code 表中,对应编号的错误码也都删除一下。
③ 删除 yudao-module-system-biz 模块的如下包:

④ 删除 yudao-spring-boot-starter-biz-tenant 模块。

然后,使用 IDEA 搜索 yudao-spring-boot-starter-biz-tenant 关键字,删除 Maven 中所有对它的定义与引用。如下图所示:

之后,使用 IDEA 刷新下 Maven 依赖。如下图所示:

⑤ 运行 YudaoServerApplication 启动类,会报 cn.iocoder.yudao.framework.tenant.core.db 不存在的错误,需要将继承 TenantBaseDO 的数据库实体,都改成继承 BaseDO 基类。

⑥ 运行 YudaoServerApplication 启动类,会报 cn.iocoder.yudao.framework.tenant.core.aop 不存在的错误,需要去除对 @TenantIgnore 注解的使用。如下图所示:

⑦ 运行 YudaoServerApplication 启动类,会报 cn.iocoder.yudao.module.system.service.tenant 不存在的错误,需要去除对 TenantService 的使用。如下图所示:

⑧ 运行 YudaoServerApplication 启动类,会报 cn.iocoder.yudao.framework.tenant.core.context 不存在的错误,需要去除对 TenantContextHolder 的使用。如下图所示:

⑨ 运行 YudaoServerApplication 启动类,终于成功了!!!

ps:可以将 application.yaml 配置文件中,对应的 yudao.tenant 配置项给进一步删除。

第四步,删除前端代码

以 yudao-admin-ui 为示例~

① 删除 View 和 API 的前端代码:

  • views/system/tenant(opens new window)
  • views/system/tenantPackage(opens new window)
  • api/system/tenant.js(opens new window)
  • api/system/tenantPackage.js

② 在 yudao-admin-ui 目录下,执行 npm run local 成功。访问登录页,结果访问白屏。需要清理 login.vue 页,涉及 tenant 关键字的代码。例如说:

刷新,成功访问登录界面。

③ 在 yudao-admin-ui 目录下,搜索 tenant 或 Tenant 关键字,可进一步清理多租户的代码。例如说:

第五步,测试验收
至此,我们已经完成了多租户的代码删除,还是蛮艰辛的~

后续,你可以简单测试一下,看看是不是删除代码,导致一些小问题。

1.14 表结构变更(版本升级)


https://cloud.iocoder.cn/sql-update/#_1-结构同步

1.15 国产信创数据库(DM 达梦、大金、OpenGauss)


https://cloud.iocoder.cn/xinchuang-db/#_1-dm-达梦数据库

1.16 内网穿透


https://cloud.iocoder.cn/natapp/#_1-第一步-购买隧道

1.16 面试题、简历模版、简历优化


https://cloud.iocoder.cn/interview/#_1-面试题

2. 后端手册

2.1 新建服务

2.1. 新建 scrm模块

① 选择 File -> New -> Module 菜单,如下图所示:

② 选择 Maven 类型,选择父模块为 yudao,输入名字为 yudao-module-scrm,并点击 Create 按钮,如下图所示:

③ 打开 yudao-module-scrm模块,删除 src 文件,如下图所示:

④ 打开 yudao-module-scrm 模块的 pom.xml 文件,修改内容如下:

提示

部分,只是注释,不需要写到 XML 中。
<?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>yudao</artifactId>
        <groupId>cn.iocoder.cloud</groupId>
        <version>${revision}</version> <!-- 1. 修改 version 为 ${revision} -->
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>yudao-module-scrm</artifactId>
    <packaging>pom</packaging> <!-- 2. 新增 packaging 为 pom -->

    <name>${project.artifactId}</name> <!-- 3. 新增 name 为 ${project.artifactId} -->
    <description> <!-- 4. 新增 description 为该模块的描述 -->
        demo 模块,主要实现 XXX、YYY、ZZZ 等功能。
    </description>
</project>

2.2. 新建 scrm-api 子模块

① 新建 yudao-module-scrm-api 子模块,整个过程和“新建 scrm模块”是一致的,如下图所示:

② 打开 yudao-module-scrm-api 模块的 pom.xml 文件,修改内容如下:

<?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>yudao-module-scrm</artifactId>
        <groupId>cn.iocoder.cloud</groupId>
        <version>${revision}</version> <!-- 1. 修改 version 为 ${revision} -->
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>yudao-module-scrm-api</artifactId>
    <packaging>jar</packaging> <!-- 2. 新增 packaging 为 jar -->

    <name>${project.artifactId}</name> <!-- 3. 新增 name 为 ${project.artifactId} -->
    <description> <!-- 4. 新增 description 为该模块的描述 -->
        scrm 模块 API,暴露给其它模块调用
    </description>

    <dependencies>  <!-- 5. 新增 yudao-common 依赖 -->
        <dependency>
            <groupId>cn.iocoder.cloud</groupId>
            <artifactId>yudao-common</artifactId>
        </dependency>
    </dependencies>

</project>

③ 【可选】新建 cn.iocoder.yudao.module.scrm基础包,其中 scrm为模块名。之后,新建 api 和 enums 包。如下图所示:

2.3. 新建 scrm-biz 子模块

① 新建 yudao-module-scrm-biz 子模块,整个过程和“新建 demo 模块”也是一致的,如下图所示:

② 打开 yudao-module-scrm-biz 模块的 pom.xml 文件,修改成内容如下:


<?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>yudao-module-scrm</artifactId>
        <groupId>cn.iocoder.cloud</groupId>
        <version>${revision}</version> <!-- 1. 修改 version 为 ${revision} -->
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <packaging>jar</packaging> <!-- 2. 新增 packaging 为 jar -->

    <artifactId>yudao-module-scrm-biz</artifactId>

    <name>${project.artifactId}</name> <!-- 3. 新增 name 为 ${project.artifactId} -->
    <description> <!-- 4. 新增 description 为该模块的描述 -->
        scrm 模块,主要实现 XXX、YYY、ZZZ 等功能。
    </description>

    <dependencies>  <!-- 5. 新增依赖,这里引入的都是比较常用的业务组件、技术组件 -->
        <!-- Spring Cloud 基础 -->
        <dependency>
            <groupId>cn.iocoder.cloud</groupId>
            <artifactId>yudao-spring-boot-starter-env</artifactId>
        </dependency>

        <!-- 依赖服务 -->
        <dependency>
            <groupId>cn.iocoder.cloud</groupId>
            <artifactId>yudao-module-system-api</artifactId>
            <version>${revision}</version>
        </dependency>
        <dependency>
            <groupId>cn.iocoder.cloud</groupId>
            <artifactId>yudao-module-infra-api</artifactId>
            <version>${revision}</version>
        </dependency>

        <dependency>
            <groupId>cn.iocoder.cloud</groupId>
            <artifactId>yudao-module-scrm-api</artifactId>
            <version>${revision}</version>
        </dependency>

        <!-- 业务组件 -->
        <dependency>
            <groupId>cn.iocoder.cloud</groupId>
            <artifactId>yudao-spring-boot-starter-biz-data-permission</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.iocoder.cloud</groupId>
            <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
        </dependency>

        <!-- Web 相关 -->
        <dependency>
            <groupId>cn.iocoder.cloud</groupId>
            <artifactId>yudao-spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>cn.iocoder.cloud</groupId>
            <artifactId>yudao-spring-boot-starter-security</artifactId>
        </dependency>

        <!-- DB 相关 -->
        <dependency>
            <groupId>cn.iocoder.cloud</groupId>
            <artifactId>yudao-spring-boot-starter-mybatis</artifactId>
        </dependency>

        <dependency>
            <groupId>cn.iocoder.cloud</groupId>
            <artifactId>yudao-spring-boot-starter-redis</artifactId>
        </dependency>

        <!-- RPC 远程调用相关 -->
        <dependency>
            <groupId>cn.iocoder.cloud</groupId>
            <artifactId>yudao-spring-boot-starter-rpc</artifactId>
        </dependency>

        <!-- Registry 注册中心相关 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <!-- Config 配置中心相关 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>

        <!-- Job 定时任务相关 -->
        <dependency>
            <groupId>cn.iocoder.cloud</groupId>
            <artifactId>yudao-spring-boot-starter-job</artifactId>
        </dependency>

        <!-- 消息队列相关 -->
        <dependency>
            <groupId>cn.iocoder.cloud</groupId>
            <artifactId>yudao-spring-boot-starter-mq</artifactId>
        </dependency>

        <!-- Test 测试相关 -->
        <dependency>
            <groupId>cn.iocoder.cloud</groupId>
            <artifactId>yudao-spring-boot-starter-test</artifactId>
        </dependency>

        <!-- 工具类相关 -->
        <dependency>
            <groupId>cn.iocoder.cloud</groupId>
            <artifactId>yudao-spring-boot-starter-excel</artifactId>
        </dependency>

        <!-- 监控相关 -->
        <dependency>
            <groupId>cn.iocoder.cloud</groupId>
            <artifactId>yudao-spring-boot-starter-monitor</artifactId>
        </dependency>
    </dependencies>

    <build>
        <!-- 设置构建的 jar 包名 -->
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <!-- 打包 -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring.boot.version}</version>
                <configuration>
                    <fork>true</fork>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal> <!-- 将引入的 jar 打入其中 -->
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

③ 【必选】新建 cn.iocoder.yudao.module.scrm 基础包,其中 scrm为模块名。之后,新建 controller.admin 和 controller.app等包。如下图所示:


package cn.iocoder.yudao.module.scrm.framework.security.config;

import cn.incoder.yudao.module.scrm.enums.ApiConstants;
import cn.iocoder.yudao.framework.security.config.AuthorizeRequestsCustomizer;


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer;

/**
 * scrm 模块的 Security 配置
 * @author lizhimin
 */
@Configuration(proxyBeanMethods = false, value = "scrmSecurityConfiguration")
public class SecurityConfiguration {

    @Bean("scrmAuthorizeRequestsCustomizer")
    public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() {
        return new AuthorizeRequestsCustomizer() {

            @Override
            public void customize(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry registry) {
                // TODO 芋艿:这个每个项目都需要重复配置,得捉摸有没通用的方案
                // Swagger 接口文档
                registry.requestMatchers("/v3/api-docs/**").permitAll()
                        .requestMatchers("/webjars/**").permitAll()
                        .requestMatchers("/swagger-ui").permitAll()
                        .requestMatchers("/swagger-ui/**").permitAll();
                // Druid 监控
                registry.requestMatchers("/druid/**").permitAll();
                // Spring Boot Actuator 的安全配置
                registry.requestMatchers("/actuator").permitAll()
                        .requestMatchers("/actuator/**").permitAll();
                // RPC 服务的安全配置
                registry.requestMatchers(ApiConstants.PREFIX + "/**").permitAll();
            }

        };
    }

}

下面这个是接口的路径常量类


package cn.incoder.yudao.module.scrm.enums;

import cn.iocoder.yudao.framework.common.enums.RpcConstants;

/**
 * API 相关的枚举
 *
 * @author lizhimin
 */
public class ApiConstants {

    /**
     * 服务名
     *
     * 注意,需要保证和 spring.application.name 保持一致
     */
    public static final String NAME = "scrm-server";

    public static final String PREFIX = RpcConstants.RPC_API_PREFIX +  "/scrm";

    public static final String VERSION = "1.0.0";

}

其中 ScrmServerApplication 的 Java 代码如下:

package cn.iocoder.yudao.module.scrm;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * 项目的启动类
 * @author lizhimin
 */
@SpringBootApplication
public class ScrmServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ScrmServerApplication.class, args);
    }
}

④ 打开 Maven 菜单,点击刷新按钮,让引入的 Maven 依赖生效。如下图所示:

⑤ 在 resources 目录下,新建配置文件。如下图所示:

其中 application.yml 的配置如下:


spring:
  application:
    name: scrm-server

  profiles:
    active: local

  main:
    allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。
    allow-bean-definition-overriding: true # 允许 Bean 覆盖,例如说 Feign 等会存在重复定义的服务

  config:
    import:
      - optional:classpath:application-${spring.profiles.active}.yaml # 加载【本地】配置
      - optional:nacos:${spring.application.name}-${spring.profiles.active}.yaml # 加载【Nacos】的配置

  # Servlet 配置
  servlet:
    # 文件上传相关配置项
    multipart:
      max-file-size: 16MB # 单个文件大小
      max-request-size: 32MB # 设置总上传的文件大小

  # Jackson 配置项
  jackson:
    serialization:
      write-dates-as-timestamps: true # 设置 LocalDateTime 的格式,使用时间戳
      write-date-timestamps-as-nanoseconds: false # 设置不使用 nanoseconds 的格式。例如说 1611460870.401,而是直接 1611460870401
      write-durations-as-timestamps: true # 设置 Duration 的格式,使用时间戳
      fail-on-empty-beans: false # 允许序列化无属性的 Bean

  # Cache 配置项
  cache:
    type: REDIS
    redis:
      time-to-live: 1h # 设置过期时间为 1 小时

server:
  port: 48099

logging:
  file:
    name: ${user.home}/logs/${spring.application.name}.log # 日志文件名,全路径

--- #################### 接口文档配置 ####################

springdoc:
  api-docs:
    enabled: true # 1. 是否开启 Swagger 接文档的元数据
    path: /v3/api-docs
  swagger-ui:
    enabled: true # 2.1 是否开启 Swagger 文档的官方 UI 界面
    path: /swagger-ui.html
  default-flat-param-object: true # 参见 https://doc.xiaominfo.com/docs/faq/v4/knife4j-parameterobject-flat-param 文档

knife4j:
  enable: true # 2.2 是否开启 Swagger 文档的 Knife4j UI 界面
  setting:
    language: zh_cn

# MyBatis Plus 的配置项
mybatis-plus:
  configuration:
    map-underscore-to-camel-case: true # 虽然默认为 true ,但是还是显示去指定下。
  global-config:
    db-config:
      id-type: NONE # “智能”模式,基于 IdTypeEnvironmentPostProcessor + 数据源的类型,自动适配成 AUTO、INPUT 模式。
      #      id-type: AUTO # 自增 ID,适合 MySQL 等直接自增的数据库
      #      id-type: INPUT # 用户输入 ID,适合 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库
      #      id-type: ASSIGN_ID # 分配 ID,默认使用雪花算法。注意,Oracle、PostgreSQL、Kingbase、DB2、H2 数据库时,需要去除实体类上的 @KeySequence 注解
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
    banner: false # 关闭控制台的 Banner 打印
  type-aliases-package: ${yudao.info.base-package}.dal.dataobject
  encryptor:
    password: XDV71a+xqStEA3WH # 加解密的秘钥,可使用 https://www.imaegoo.com/2020/aes-key-generator/ 网站生成

mybatis-plus-join:
  banner: false # 关闭控制台的 Banner 打印

# Spring Data Redis 配置
spring:
  data:
    redis:
      repositories:
        enabled: false # 项目未使用到 Spring Data Redis 的 Repository,所以直接禁用,保证启动速度

# VO 转换(数据翻译)相关
easy-trans:
  is-enable-global: true # 启用全局翻译(拦截所有 SpringMVC ResponseBody 进行自动翻译 )。如果对于性能要求很高可关闭此配置,或通过 @IgnoreTrans 忽略某个接口

--- #################### RPC 远程调用相关配置 ####################

--- #################### 消息队列相关 ####################

# rocketmq 配置项,对应 RocketMQProperties 配置类
rocketmq:
  # Producer 配置项
  producer:
    group: ${spring.application.name}_PRODUCER # 生产者分组

spring:
  # Kafka 配置项,对应 KafkaProperties 配置类
  kafka:
    # Kafka Producer 配置项
    producer:
      acks: 1 # 0-不应答。1-leader 应答。all-所有 leader 和 follower 应答。
      retries: 3 # 发送失败时,重试发送的次数
      value-serializer: org.springframework.kafka.support.serializer.JsonSerializer # 消息的 value 的序列化
    # Kafka Consumer 配置项
    consumer:
      auto-offset-reset: earliest # 设置消费者分组最初的消费进度为 earliest 。可参考博客 https://blog.csdn.net/lishuangzhe7047/article/details/74530417 理解
      value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
      properties:
        spring.json.trusted.packages: '*'
    # Kafka Consumer Listener 监听器配置
    listener:
      missing-topics-fatal: false # 消费监听接口监听的主题不存在时,默认会报错。所以通过设置为 false ,解决报错

--- #################### 定时任务相关配置 ####################

xxl:
  job:
    executor:
      appname: ${spring.application.name} # 执行器 AppName
      logpath: ${user.home}/logs/xxl-job/${spring.application.name} # 执行器运行日志文件存储磁盘路径
    accessToken: default_token # 执行器通讯TOKEN


--- #################### 芋道相关配置 ####################

yudao:
  info:
    version: 1.0.0
    base-package: cn.iocoder.yudao.module.scrm
  web:
    admin-ui:
      url: http://dashboard.yudao.iocoder.cn # Admin 管理后台 UI 的地址
  xss:
    enable: false
    exclude-urls: # 如下 url,仅仅是为了演示,去掉配置也没关系
      - ${management.endpoints.web.base-path}/** # 不处理 Actuator 的请求
  swagger:
    title: 管理后台
    description: 提供管理员管理的所有功能
    version: ${yudao.info.version}
  tenant: # 多租户相关配置项
    enable: true

debug: false


  • spring.application.name 配置项:可以改成你想要的服务名。
  • server.port 配置项:可以改成你想要的端口号。
  • yudao.info.version.base-package 配置项:可以改成你的项目的基准包名。
    其中 application-local.yml 的配置如下:



--- #################### 数据库相关配置 ####################
spring:
  # 数据源配置项
  autoconfigure:
    exclude:
      - com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure # 排除 Druid 的自动配置,使用 dynamic-datasource-spring-boot-starter 配置多数据源
      - de.codecentric.boot.admin.client.config.SpringBootAdminClientAutoConfiguration # 禁用 Spring Boot Admin 的 Client 的自动配置
  datasource:
    druid: # Druid 【监控】相关的全局配置
      web-stat-filter:
        enabled: true
      stat-view-servlet:
        enabled: true
        allow: # 设置白名单,不填则允许所有访问
        url-pattern: /druid/*
        login-username: # 控制台管理用户名和密码
        login-password:
      filter:
        stat:
          enabled: true
          log-slow-sql: true # 慢 SQL 记录
          slow-sql-millis: 100
          merge-sql: true
        wall:
          config:
            multi-statement-allow: true
    dynamic: # 多数据源配置
      druid: # Druid 【连接池】相关的全局配置
        initial-size: 1 # 初始连接数
        min-idle: 1 # 最小连接池数量
        max-active: 20 # 最大连接池数量
        max-wait: 600000 # 配置获取连接等待超时的时间,单位:毫秒
        time-between-eviction-runs-millis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位:毫秒
        min-evictable-idle-time-millis: 300000 # 配置一个连接在池中最小生存的时间,单位:毫秒
        max-evictable-idle-time-millis: 900000 # 配置一个连接在池中最大生存的时间,单位:毫秒
        validation-query: SELECT 1 FROM DUAL # 配置检测连接是否有效
        test-while-idle: true
        test-on-borrow: false
        test-on-return: false
      primary: master
      datasource:
        master:
          url: jdbc:mysql://127.0.0.1:3306/cloud-scrm-master?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
          #          url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true # MySQL Connector/J 5.X 连接的示例
          #          url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例
          #          url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例
          #          url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=ruoyi-vue-pro # SQLServer 连接的示例
          #          url: jdbc:dm://10.211.55.4:5236?schema=RUOYI_VUE_PRO # DM 连接的示例
          username: LZM
          password: 1234
        #          username: sa # SQL Server 连接的示例
        #          password: JSm:g(*%lU4ZAkz06cd52KqT3)i1?H7W # SQL Server 连接的示例
        #          username: SYSDBA # DM 连接的示例
        #          password: SYSDBA # DM 连接的示例
        slave: # 模拟从库,可根据自己需要修改
          lazy: true # 开启懒加载,保证启动速度
          url: jdbc:mysql://127.0.0.1:3306/cloud-scrm-slave?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true
          username: LZM
          password: 1234

  # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
  redis:
    host: 127.0.0.1 # 地址
    port: 6379 # 端口
    database: 9 # 数据库索引
#    password: 123456 # 密码,建议生产环境开启

--- #################### MQ 消息队列相关配置 ####################

# rocketmq 配置项,对应 RocketMQProperties 配置类
rocketmq:
  name-server: 127.0.0.1:9876 # RocketMQ Namesrv

spring:
  # RabbitMQ 配置项,对应 RabbitProperties 配置类
  rabbitmq:
    host: 127.0.0.1 # RabbitMQ 服务的地址
    port: 5672 # RabbitMQ 服务的端口
    username: guest # RabbitMQ 服务的账号
    password: guest # RabbitMQ 服务的密码
  # Kafka 配置项,对应 KafkaProperties 配置类
  kafka:
    bootstrap-servers: 127.0.0.1:9092 # 指定 Kafka Broker 地址,可以设置多个,以逗号分隔

--- #################### 定时任务相关配置 ####################

xxl:
  job:
    enabled: false # 是否开启调度中心,默认为 true 开启
    admin:
      addresses: http://127.0.0.1:9090/xxl-job-admin # 调度中心部署跟地址

--- #################### 服务保障相关配置 ####################

# Lock4j 配置项
lock4j:
  acquire-timeout: 3000 # 获取分布式锁超时时间,默认为 3000 毫秒
  expire: 30000 # 分布式锁的超时时间,默认为 30 毫秒

--- #################### 监控相关配置 ####################

# Actuator 监控端点的配置项
management:
  endpoints:
    web:
      base-path: /actuator # Actuator 提供的 API 接口的根目录。默认为 /actuator
      exposure:
        include: '*' # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。

# Spring Boot Admin 配置项
spring:
  boot:
    admin:
      # Spring Boot Admin Client 客户端的相关配置
      client:
        instance:
          service-host-type: IP # 注册实例时,优先使用 IP [IP, HOST_NAME, CANONICAL_HOST_NAME]

# 日志文件配置
logging:
  level:
    # 配置自己写的 MyBatis Mapper 打印日志
    cn.iocoder.yudao.module.scrm.dal.mysql: debug
    org.springframework.context.support.PostProcessorRegistrationDelegate: ERROR # TODO 芋艿:先禁用,Spring Boot 3.X 存在部分错误的 WARN 提示

--- #################### 芋道相关配置 ####################

# 芋道配置项,设置当前项目所有自定义的配置
yudao:
  env: # 多环境的配置项
    tag: ${HOSTNAME}
  captcha:
    enable: true # 本地环境,暂时关闭图片验证码,方便登录等接口的测试
  security:
    mock-enable: true
  access-log: # 访问日志的配置项
    enable: true
  cache:
    type: REDIS
    prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE::
    timeout: 24h # 超时时长,目前只对 Redis 缓存生效,默认 3 分钟


<!-- 控制台 Appender -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">     
    <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
        <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
            <pattern>${PATTERN_DEFAULT}</pattern>
        </layout>
    </encoder>
</appender>

<!-- 文件 Appender -->
<!-- 参考 Spring Boot 的 file-appender.xml 编写 -->
<appender name="FILE"  class="ch.qos.logback.core.rolling.RollingFileAppender">
    <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
        <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
            <pattern>${PATTERN_DEFAULT}</pattern>
        </layout>
    </encoder>
    <!-- 日志文件名 -->
    <file>${LOG_FILE}</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
        <!-- 滚动后的日志文件名 -->
        <fileNamePattern>${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz}</fileNamePattern>
        <!-- 启动服务时,是否清理历史日志,一般不建议清理 -->
        <cleanHistoryOnStart>${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false}</cleanHistoryOnStart>
        <!-- 日志文件,到达多少容量,进行滚动 -->
        <maxFileSize>${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB}</maxFileSize>
        <!-- 日志文件的总大小,0 表示不限制 -->
        <totalSizeCap>${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0}</totalSizeCap>
        <!-- 日志文件的保留天数 -->
        <maxHistory>${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-30}</maxHistory>
    </rollingPolicy>
</appender>
<!-- 异步写入日志,提升性能 -->
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
    <!-- 不丢失日志。默认的,如果队列的 80% 已满,则会丢弃 TRACT、DEBUG、INFO 级别的日志 -->
    <discardingThreshold>0</discardingThreshold>
    <!-- 更改默认的队列的深度,该值会影响性能。默认值为 256 -->
    <queueSize>256</queueSize>
    <appender-ref ref="FILE"/>
</appender>

<!-- SkyWalking GRPC 日志收集,实现日志中心。注意:SkyWalking 8.4.0 版本开始支持 -->
<appender name="GRPC" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
    <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
        <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
            <pattern>${PATTERN_DEFAULT}</pattern>
        </layout>
    </encoder>
</appender>

<!-- 本地环境 -->
<springProfile name="local">
    <root level="INFO">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="GRPC"/> <!-- 本地环境下,如果不想接入 SkyWalking 日志服务,可以注释掉本行 -->
        <appender-ref ref="ASYNC"/>  <!-- 本地环境下,如果不想打印日志,可以注释掉本行 -->
    </root>
</springProfile>
<!-- 其它环境 -->
<springProfile name="dev,test,stage,prod,default">
    <root level="INFO">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="ASYNC"/>
        <appender-ref ref="GRPC"/>
    </root>
</springProfile>
```

2.4. 新建 RESTful API 接口

① 在 controller.admin 包,新建一个 ScrmTestController 类,并新建一个 /scrm/test/get 接口。代码如下:

package cn.iocoder.yudao.module.scrm.controller.admin;

import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;

/**
 * @Author LiZhiMin
 * @Date 2024/10/7 15:52
 */
@Tag(name = "管理后台 - Test")
@RestController
@RequestMapping("/scrm/test")
@Validated
public class ScrmTestController {

    @GetMapping("/get")
    @Operation(summary = "获取 test 信息")
    public CommonResult<String> get() {
        return success("true-Hello-Word");
    }

}

注意,/scrm 是该模块所有 RESTful API 的基础路径,/test 是 Test 功能的基础路径。一般用表名或者业务名

②在 controller.app 包,新建一个 AppDemoTestController 类,并新建一个 /demo/test/get 接口。代码如下:

package cn.iocoder.yudao.module.scrm.controller.app;

import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;

/**
 * @Author LiZhiMin
 * @Date 2024/10/7 15:52
 */
@Tag(name = "管理后台 - Test")
@RestController
@RequestMapping("/scrm/test")
@Validated
public class ScrmTestController {

    @GetMapping("/get")
    @Operation(summary = "获取 test 信息")
    public CommonResult<String> get() {
        return success("true-Hello-Word");
    }

}

在 Controller 的命名上,额外增加 App 作为前缀,一方面区分是管理后台还是用户 App 的 Controller,另一方面避免 Spring Bean 的名字冲突。
可能你会奇怪,这里我们定义了两个 /scrm/test/get 接口,会不会存在重复导致冲突呢?答案,当然是并不会。原因是:

  • controller.admin 包下的接口,默认会增加 /admin-api,即最终的访问地址是 /admin-api/scrm/test/get
  • controller.app 包下的接口,默认会增加 /app-api,即最终的访问地址是 /app-api/scrm/test/get

2.5. 启动 scrm服务

① 运行 SystemServerApplication 类,将 system 服务启动。运行 InfraServerApplication 类,将 infra 服务启动。

② 运行 DemoServerApplication 类,将新建的 demo 服务进行启动。启动完成后,使用浏览器打开 http://127.0.0.1:48099/doc.html (opens new window)地址,进入该服务的 Swagger 接口文档。

③ 打开“管理后台 - Test”接口,进行 /admin-api/scrm/test/get 接口的调试,如下图所示:

④ 打开“用户 App - Test”接口,进行 /app-api/demo/test/get 接口的调试,如下图所示:

2.6. 网关配置

① 打开 yudao-gateway 网关项目的 application.yml 配置文件,增加 scrm 服务的路由配置。代码如下:

代码如下

  # 路由配置项,对应 RouteDefinition 数组
  routes:   这个目录下面的如下:
        ## scrm-server 服务
        - id: system-scrm-api # 路由的编号
          uri: grayLb://scrm-server
          predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组
            - Path=/admin-api/scrm/**
          filters:
            - RewritePath=/admin-api/scrm/v3/api-docs, /v3/api-docs # 配置,保证转发到 /v3/api-docs
        - id: scrm-app-api # 路由的编号
          uri: grayLb://scrm-server
          predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组
            - Path=/app-api/scrm/**
          filters:
            - RewritePath=/app-api/scrm/v3/api-docs, /v3/api-docs

knife4j:
聚合 Swagger 文档,参考 https://doc.xiaominfo.com/docs/action/springcloud-gateway 文档
gateway:
enabled: true
routes: 这里的配置如下:

      - name: scrm-server
        service-name: scrm-server
        url: /admin-api/scrm/v3/api-docs

② 运行 GatewayServerApplication 类,将 gateway 网关服务启动。

③ 使用浏览器打开 http://127.0.0.1:48080/doc.html (opens new window)地址,进入网关的 Swagger 接口文档。然后,选择 demo-server 服务,即可进行 /admin-api/demo/test/get 和 /app-api/demo/test/get 接口的调试,如下图所示:

2.2 代码生成【单表】(新增功能)

大部分项目里,其实有很多代码是重复的,几乎每个模块都有 CRUD 增删改查的功能,而这些功能的实现代码往往是大同小异的。如果这些功能都要自己去手写,非常无聊枯燥,浪费时间且效率很低,还可能会写错。

所以这种重复性的代码,项目提供了 codegen 代码生成器,只需要在数据库中设计好表结构,就可以一键生成前后端代码 + 单元测试 + Swagger 接口文档 + Validator 参数校验。

针对不同的业务场景,项目提供了三种模式:单表、树表、主子表。
本文,我们将演示“单表”的使用,基于代码生成器,在 yudao-module-system 模块中,开发一个【用户组】的功能。

1. 数据库表结构设计

设计用户组的数据库表名为 system_group,其建表语句如下:

 CREATE TABLE `scrm_group` (
    `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
    `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '名字',
    `description` varchar(512) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '描述',
    `status` tinyint NOT NULL COMMENT '状态',
    `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '创建者',
    `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '更新者',
    `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
    `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
    `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号',
    PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户组';

① 表名的前缀,要和 Maven Module 的模块名保持一致。例如说,用户组在 yudao-module-scrm模块,所以表名的前缀是 scrm_ 。

疑问:为什么要保持一致?
代码生成器会自动解析表名的前缀,获得其所属的 Maven Module 模块,简化配置过程。

② 设置 ID 主键,一般推荐使用 bigint 长整形,并设置自增长。

③ 正确设置每个字段是否允许空,代码生成器会根据它生成参数是否允许空的校验规则。

④ 正确设置注释,代码生成器会根据它生成字段名与提示等信息。

⑤ 添加 creator、create_time、updater、update_time、deleted 是必须设置的系统字段;如果开启多租户的功能,并且该表需要多租户的隔离,则需要添加 tenant_id 字段。

2. 代码生成

我进行了读写分离的操作,这里手动吧表连接加一下,没有分离的不用进行这个操作

2.1 导入表

点击 [基础设施 -> 代码生成] 菜单,点击 [基于 DB 导入] 按钮,选择 scrm_group 表,后点击 [确认] 按钮。

2.2 编辑配置

点击 scrm_group 所在行的 [编辑] 按钮,修改生成配置。后操作如下:

  • 将 status 字段的显示类型为【下拉框】,字典类型为【系统状态】。
  • 将 description 字段的【查询】取消。
  • 将 id、name、description、status 字段的【示例】填写上。

字段信息

  • 插入:新增时,是否传递该字段。
  • 编辑:修改时,是否传递该字段。
  • 列表:Table 表格,是否展示该字段。
  • 查询:搜索框,是否支持该字段查询,查询的条件是什么。
  • 允许空:新增或修改时,是否必须传递该字段,用于 Validator 参数校验。
  • 字典类型:在显示类型是下拉框、单选框、复选框时,选择使用的字典。
  • 示例:参数示例,用于 Swagger 接口文档的 example 示例。

  • 将【上级菜单】设置为【系统管理】。
  • 将【前端类型】设置为“前端项目”对应的“前端类型”。例如说,我们这里演示的是 yudao-ui-admin-vue3 前端项目,则选择了【Vue3 Element Plus 标准模版】。

生成信息

  • 生成场景:分成管理后台、用户 App 两种,用于生成 Controller 放在 admin 还是 app 包。
  • 上级菜单:生成场景是管理后台时,需要设置其所属的上级菜单。
  • 前端类型: 提供多种 UI 模版。后端的 application.yaml 配置文件中的 yudao.codegen.front-type 配置项,设置默认的 UI 模版,避免每次都需要设置。

完成后,点击 [提交] 按钮,保存生成配置。

2.3 预览代码

点击 scrm_group 所在行的 [预览] 按钮,在线预览生成的代码,检查是否符合预期。

2.4 代码生成

点击 scrm_group 所在行的 [生成代码] 按钮,下载生成代码的压缩包,双击进行解压。

代码实现?
可见 CodegenEngine 类,基于 Velocity 模板引擎,生成具体代码。模板文件,可见 resources/codegen 目录。

3. 代码运行

本小节,我们将生成的代码,复制到项目中,并进行运行。

3.1 后端代码运行

① 将生成的后端代码,复制到项目中。操作如下图所示:

② 将 ErrorCodeConstants.java_手动操作 文件的错误码,复制到该模块 ErrorCodeConstants 类中,并设置对应的错误码编号,之后进行删除。操作如下图所示:

③ 将 h2.sql 的 CREATE 语句复制到该模块的 create_tables.sql 文件,DELETE 语句复制到该模块的 clean.sql。操作如下图:

友情提示:最新版本,第 ③ 部分的单元测试,默认已经不在生成。所以,不需要操作这一步。
原因是:大多数团队,没有编写单元测试的习惯,导致生成的单元测试代码,会被直接删除。所以,我们默认不生成单元测试代码,减少不必要的代码生成。
如果想要开启,可以把 yudao.codegen.unit-test-enable 配置项设置为 true,然后重新生成代码。
另外,如果你想要编写单元测试,可以考虑使用 MarsCode (opens new window)智能编码插件,可以免费生成不错的单元测试。

疑问:create_tables.sqlclean.sql 文件的作用是什么?
项目的单元测试,需要使用到 H2 内存数据库,create_tables.sql 用于创建所有的表结构,clean.sql 用于每个单元测试的方法跑完后清理数据。

然后,运行 GroupServiceImplTest 单元测试,执行通过。
④ 打开数据库工具,运行代码生成的 sql/sql.sql 文件,用于菜单的初始化。
由于我区分了业务表所有 这个插入菜单的sql执行是在system数据库中执行的

⑤ Debug 运行 YudaoServerApplication 类,启动后端项目。通过 IDEA 的 [Actuator -> Mappings] 菜单,可以看到代码生成的 GroupController 的 RESTful API 接口已经生效。

3.2 前端代码运行

① 将生成的前端代码,复制到项目中。操作如下图所示

② 重新执行 npm run dev 命令,启动前端项目。点击 [系统管理 -> 菜单管理] 菜单,点击【刷新菜单缓存】,因为前端项目会缓存菜单在内存中的,所以需要刷新一下。

③ 点击 [系统管理 -> 用户组管理] 菜单,就可以看到用户组的 UI 界面。

至此,我们已经完成了【用户组】功能的代码生成,基本节省了你 80% 左右的开发任务,后续可以根据自己的需求,进行剩余的 20% 的开发!

4. 后续变更

随着业务的发展,已经生成代码的功能需要变更。继续以【用户组】举例子,它的 system_group 表需要新增一个分类 category 字段,此时不建议使用代码生成器,而是直接修改已经生成的代码:
① 后端:修改 GroupDO 数据实体类、GroupSaveReqVO 保存 VO 类、GroupSaveRespVO 响应 VO 类,新增 category 字段。
② 前端:修改 Vue 的 index.vue 列表和 Form 表单组件,新增 category 字段。
③ 重新编译后后端,并进行启动。
over!非常简单方便,即保证了代码的整洁规范,又不增加过多的开发量。

5. 常见问题

① 生成的代码结构,有没具体说明?
答:参见 《项目结构》 文档的说明,最好把对应视频好好看下。
② 为什么要分 XXXSaveReqVO、XXXRespVO、XXXPageReqVO 三个 VO 类?
答:星球里 https://t.zsxq.com/14Fc743WH (opens new window)进行了 VO 拆分的讨论,总体大家倾向拆分成三个 VO 类,因为这样更加清晰,而且也不会增加太多的维护工作量
可能你会想,能不能把 XXXSaveReqVO 和 XXXRespVO 合并成一个呢?有两方面的考虑:
1、一般来说,新增/修改是不传递 createTime、creator 等字段,响应是需要返回 createTime、creator 等字段,两者的字段无法不一致。
2、一旦 VO 和 DO 拆分开后,调整字段时,例如说新增一个 xxx 字段,两个 VO 的修改成本,和一个 VO 实际是差不多的。
③ 为什么 UI 界面的数据字典,下拉没有选项,或者列表没有展示它的文本?
类似 https://t.zsxq.com/owJzU (opens new window)的问题。
原因是:需要在前端的代码里,枚举一下。例如说 Vue3 + Element-Plus 版本,需要在 yudao-ui-admin-vue3/src/utils/dict.ts 的 DICT_TYPE 添加字典的 type 枚举值。

2.3 代码生成【主子表】

主子表,指的是一个主表,被多个子表所关联,关联的关系是一对一或一对多。
例如说:主表是【学生】,子表可以是:

  • 子表是【成绩】,两者是“一对多”的关系,一个学生可以有多个成绩。
  • 子表是【班级】,两者是“一对一”的关系,一个学生只能有一个班级。
    下面,我们将演示“主子表”的使用,基于代码生成器,在 yudao-module-system 模块中,开发一个【学生】的功能。

友情提示:
目前只有 yudao-ui-admin-vue3 支持主子表,yudao-ui-admin-vue2、yudao-ui-admin-vben 正在适配中!

2.3.1. 主字表模式

针对不同的交互模式,项目提供了三种主子表模式:标准、ERP、内嵌。

2.3.1.0 标准模式

对应 [基础设施 -> 代码生成案例 -> 主子表(标准)] 菜单。
在新增和修改时,主表和子表在一个弹窗表单中,一起提交。如下图所示:

2.3.1.1 内嵌模式

对应 [基础设施 -> 代码生成案例 -> 主子表(内嵌)] 菜单。

在「标准模式」的基础之上,列表 内嵌 子表的列表。如下图所示:

2.3.1.2 ERP 模式

对应 [基础设施 -> 代码生成案例 -> 主子表(ERP)] 菜单。

主表和子表,独立列表,也独立表单。如下图所示:

2.3.2. 数据库表结构设计

① 设计 主表 的数据库表名为 system_student 学生表,其建表语句如下:

CREATE TABLE `system_student` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
  `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '名字',
  `birthday` datetime NOT NULL COMMENT '出生日期',
  `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '简介',
  `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '创建者',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '更新者',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
  `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='学生表';

② 设计 子表 的数据库表名为 system_student_course 学生课程表,其建表语句如下:

CREATE TABLE `system_student_course` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
  `student_id` bigint NOT NULL COMMENT '学生编号',
  `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '名字',
  `score` tinyint NOT NULL COMMENT '分数',
  `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '创建者',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '更新者',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
  `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='学生课程表';

它和主表的关系是一对多,一个学生可以有多个课程,通过 student_id 字段进行关联。

③ 设计 子表 的数据表名为 system_student_grade 学生班级表,其建表语句如下:

CREATE TABLE `system_student_grade` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
  `student_id` bigint NOT NULL COMMENT '学生编号',
  `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '名字',
  `teacher` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '班主任',
  `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '创建者',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '更新者',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
  `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='学生班级表';

2.3.3.1 导入表

点击 [基础设施 -> 代码生成] 菜单,点击 [基于 DB 导入] 按钮,选择 system_student、system_student_course、system_student_grade 表,后点击 [确认] 按钮。

2.3.3.2 编辑配置(主表)

点击 system_student 所在行的 [编辑] 按钮,修改生成配置。后操作如下:

  • 将【生成模版】设置为【主表(标准模式)】。🔥最最关键的步骤!
  • 将【上级菜单】设置为【系统管理】。
  • 将【前端类型】设置为“前端项目”对应的“前端类型”。例如说,我们这里演示的是 yudao-ui-admin-vue3 前端项目,则选择了【Vue3 Element Plus 标准模版】。

2.3.3.3 编辑配置(子表)

① 点击 system_student_course 所在行的 [编辑] 按钮,修改生成配置。后操作如下:

  • 将【生成模版】设置为【子表】。🔥最最关键的步骤!
  • 业务名:一般建议和【主表】保持一致,所以这里改成了 student。
  • 主表信息:将【关联的主表】设置为 system_student 表,将【子表关联的字段】设置为 student_id 字段,将【关联关系】设置为“一对多”。

② 点击 system_student_grade 所在行的 [编辑] 按钮,修改生成配置。后操作如下:

  • (同上)将【生成模版】设置为【子表】。🔥最最关键的步骤!
  • (同上)业务名:一般建议和【主表】保持一致,所以这里改成了 student。
  • (基本同上,关联关系不同)主表信息:将【关联的主表】设置为 system_student 表,将【子表关联的字段】设置为
    student_id 字段,将【关联关系】设置为“一对一”。

2.3.3.4 预览代码

点击 system_student 所在行的 [预览] 按钮,在线预览生成的代码,检查是否符合预期。

2.3.3.5 生成代码

点击 system_student 所在行的 [生成] 按钮,生成代码。

2.3.4 代码运行

《代码生成【单表】》 的「3. 代码运行」一致,就不重复赘述。

2.4. 代码生成【树表】

友情提示:

本文接 《代码生成【单表】》,请务必先阅读。因为重复的内容,本文会不再赘述!

树表,是在“单表”的基础上,增加了「树形结构」的功能。

例如说:部门、分类等,是一个树形结构。我们可以通过树形结构,来展示部门、分类的层级关系。

下面,我们将演示“树表”的使用,基于代码生成器,在 yudao-module-system 模块中,开发一个【分类】的功能。

2.4.1. 数据库表结构设计

设计分类的数据库表名为 system_category,其建表语句如下:

CREATE TABLE `system_category` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
  `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '名字',
  `parent_id` bigint NOT NULL COMMENT '父级编号',
  `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '创建者',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '更新者',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
  `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='分类表';

其中 parent_id 字段,用于标识父级分类的编号。如果是顶级分类,则 parent_id 为 0。

2.4.2. 代码生成

2.4.3. 导入表

点击 [基础设施 -> 代码生成] 菜单,点击 [基于 DB 导入] 按钮,选择 system_category 表,后点击 [确认] 按钮

2.4.4. 编辑配置

点击 system_category 所在行的 [编辑] 按钮,修改生成配置。后操作如下:

  • 将【生成模版】设置为【树表】。🔥最最关键的步骤!
  • 树表信息:将【父编号字段】设置为 parent_id 字段,将【树名称字段】设置为 name 字段。
  • 将【上级菜单】设置为【系统管理】。
  • 将【前端类型】设置为“前端项目”对应的“前端类型”。例如说,我们这里演示的是 yudao-ui-admin-vue3 前端项目,则选择了【Vue3 Element Plus 标准模版】。

2.4.5. 预览代码

点击 system_category 所在行的 [预览] 按钮,在线预览生成的代码,检查是否符合预期。

2.4.6. 生成代码

点击 system_category 所在行的 [生成] 按钮,生成代码。

2.4.7 代码运行

《代码生成【单表】》 的「3. 代码运行」一致,就不重复赘述。

2.5 功能权限

2.6 数据权限

2.7 用户体系

2.8 三方登录

2.9 OAuth 2.0(SSO 单点登录)

2.10 SaaS 多租户【字段隔离】

2.11 SaaS 多租户【数据库隔离】

2.12 WebSocket 实时通信

2.13 异常处理(错误码)

2.14 参数校验、时间传参

2.15 分页实现

2.16 VO 对象转换、数据翻译

2.17 文件存储(上传下载)

2.18 Excel 导入导出

2.19 操作日志、访问日志、异常日志

2.20 MyBatis 数据库

2.21 MyBatis 联表&分页查询

2.22 多数据源(读写分离)

2.23 Redis缓存

2.24 本地缓存

2.25 异步任务

2.26 分布式锁

2.27 幂等性(防重复提交)

2.28 请求限流(RateLimiter)

2.29 HTTP 接口签名(防篡改)

2.30 单元测试

2.31 验证码

2.32 工具类Util

2.33 数据库文档

3. 微服务手册

3.1 微服务调试(必读)

3.2 注册中心 Nacos

3.3 配置中心 Nacos

3.4 服务网关 Spring Cloud Gateway

3.5 服务调用 Feign

3.6 定时任务 XXL Job

3.7 消息队列(内存)

3.8 消息队列 (Redis)

3.9 消息队列 (RocketMQ)

3.10 消息队列 (消息队列RabbitMQ)

3.11 消息队列 (Kafka)

3.12 消息队列(Cloud)

3.13 分布式事物

3.14 服务保障 Sentinel

4. 工作流手册

5. 大屏手册

6. 支付手册

6.1 功能开启

6.2 支付宝支付接入

6.3 微信公众号支付接入

6.4 微信小程序支付接入

6.5 支付宝、微信退款接入

6.6 钱包充值、支付、退款

6.7 模拟支付、退款

7. 会员手册

8. 商城手册

9. ERP手册

10. CRM手册

11. AI大模型手册

12. 公众号手册

13. 系统手册

13.1 短信配置

13.2 邮件配置

13.3 站内信配置

13.4 数据脱敏

13.5 敏感词

13.6 地区 & IP 库

14. 运维手册

13.1 开发环境

14.2 Linux 部署

14.3 Docker 部署

14.4 Jenkins 部署

14.5 宝塔部署

14.6 HTTPS 证书

14.7 服务监控

15. 前端手册 Vue 3.x

文章大部分内容来自这里,少部分是自己补充的
https://cloud.iocoder.cn/

posted @   泪伤荡  阅读(3729)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 上周热点回顾(2.17-2.23)
· 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS)
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
点击右上角即可分享
微信分享提示