项目定位 :AI 低代码平台,前后端分离,后端是 Spring Boot 3 / Spring Cloud Alibaba。
技术栈主线 :JDK 17、Spring Boot 3.5.5、Spring Cloud 2025、Spring Cloud Alibaba、MyBatis-Plus、Shiro、JWT、Druid、Nacos、Gateway。
模块结构 :
-
jeecg-boot-base-core :公共核心能力、配置、工具类、安全、MyBatis、Shiro。
-
jeecg-module-system :系统业务模块,包含 API、业务实现、单体启动。
-
jeecg-boot-module :扩展业务模块,如 demo、AI RAG。
-
jeecg-server-cloud :微服务版本,包含 Gateway、Nacos、Cloud Start、监控等。
项目定位
JeecgBoot 是一个 企业级 AI 低代码开发平台 。
核心特点:
-
基于 Spring Boot 3
-
支持 Spring Cloud Alibaba 微服务架构
-
使用 MyBatis-Plus 做持久层
-
使用 Shiro + JWT 做认证授权
-
支持代码生成、在线表单、报表、大屏、流程、AI 应用、RAG 知识库等能力
技术栈
| 技术 | 作用 |
|---|---|
| JDK 17 | Java 基础运行版本 |
| Spring Boot 3.5.5 | 后端应用基础框架 |
| Spring Cloud 2025.0.0 | 微服务体系 |
| Spring Cloud Alibaba | 整合 Nacos、Sentinel 等阿里微服务组件 |
| MyBatis-Plus | ORM / DAO 增强 |
| Druid | 数据库连接池、SQL 监控 |
| Shiro | 权限认证框架 |
| JWT | 无状态 Token 登录 |
| Fastjson | JSON 数据处理 |
| Knife4j / Swagger | 在线接口文档 |
| MinIO / OSS | 文件对象存储 |
| XXL-JOB | 分布式任务调度 |
| Nacos | 注册中心、配置中心 |
| Gateway | 微服务网关 |
| Sentinel | 流量控制、熔断降级 |
| JimuReport | 积木报表、数据大屏能力 |
maven多模块
版本管理
Maven 多模块项目通常由一个父工程管理多个子模块。
以当前项目为例,根工程是:
核心特点:
父工程通常是 pom 打包方式。
父工程不直接写业务代码,主要负责统一管理。
子模块通过 <modules> 被父工程聚合。
子模块可以继承父 POM 的版本、插件、依赖管理配置。
多模块适合大型项目拆分,例如公共模块、业务模块、启动模块、微服务模块。
<modules> <module>jeecg-boot-base-core</module> <module>jeecg-module-system</module> <module>jeecg-boot-module</module> </modules>
<!-- 管理 Spring Cloud 全家桶的版本 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <!-- 这是一个版本清单文件 --> <scope>import</scope> <!-- 把这个版本清单导入进来 --> </dependency> </dependencies>
<properties>= 存数字的「变量盒子」**<dependencyManagement>= 用这些数字去 「锁版本」的工具
标签 作用 能不能单独锁版本? <properties>定义变量,存版本号数字 ❌ 不能 <dependencyManagement>统一管理、锁定依赖版本 ✅ 能
- parent-project
├── pom.xml
├── common-module
├── system-module
├── business-module
└── start-module
聚合和继承
Maven 多模块里最容易混淆的是:
-
聚合
module-a module-b
作用:
-
让父工程一次性构建多个子模块。
-
控制构建顺序。
-
常用于根 POM。
-
聚合关系主要影响"构建"。
一句话:
聚合解决的是"我一次构建哪些模块"。
- 继承
<parent>
<groupId>xxx</groupId>
<artifactId>parent</artifactId>
<version>1.0.0</version>
</parent>
作用:
-
子模块继承父 POM 的配置。
-
可以继承依赖版本、插件版本、属性、仓库、编码配置等。
-
继承关系主要影响"配置复用"。
一句话:
继承解决的是"我复用谁的配置"。
父工程
├── 作为聚合器:modules 管理子模块
└── 作为父 POM:parent 被子模块继承
但它们不是一回事。
一个模块可以:
-
被某个 POM 聚合,但不继承它。
-
继承某个父 POM,但不被它聚合。
-
既被聚合,又继承父 POM。
多继承
严格来说:
Maven 不支持真正意义上的多继承。
一个 pom.xml 只能有一个 <parent> 。
因为 Maven 可以通过以下方式实现类似效果:
-
父 POM 继承祖父 POM。
-
当前模块继承父 POM。
-
使用 dependencyManagement 导入多个 BOM。
-
使用 pluginManagement 管理插件版本。
-
使用 profile 做环境配置切换。
Spring Boot Parent
↑
JeecgBoot Parent
↑
子模块
JeecgBoot 根 POM 就继承了 Spring Boot Parent
因此子模块间接获得了 Spring Boot Parent 的部分配置。
依赖管理的特点
<dependencyManagement>
<dependencies>
...
</dependencies>
</dependencyManagement>
例如父 POM 写了:dependencyManagement>
<dependencies>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.12</version>
</dependency>
</dependencies>
</dependencyManagement>
子模块不会自动拥有这个依赖。子模块还需要显式声明:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
</dependency>
此时可以省略版本号,因为版本由父 POM 管理。
一句话:
dependencyManagement 管版本,不管引入。
dependencies 会直接引入依赖
如果父 POM 直接写:
```
<dependencies>
<dependency>
...
</dependency>
</dependencies>
```
那么子模块通常会继承这些依赖。
所以:
| 标签 | 位置 | 核心作用 | 特点说明 |
|---|---|---|---|
dependencies |
项目根下 / dependencyManagement 内 |
直接引入依赖,当前模块 / 子模块生效 | 声明后立即引入对应 jar 包,所有子模块可直接继承 |
dependencyManagement |
父 POM / 聚合工程根 POM | 统一管理依赖版本,不实际引入依赖 | 仅锁定版本、groupId、artifactId,子模块使用时仍需在 dependencies 声明,无需写版本 |
pluginManagement |
父 POM / 聚合工程根 POM | 统一管理插件版本,不实际启用插件 | 仅锁定插件版本、坐标,子模块需手动声明 plugins 才会生效 |
plugins |
项目根下 / pluginManagement 内 |
直接启用并配置插件,当前模块 / 子模块生效 | 声明后插件立即执行,可绑定生命周期、配置参数,子模块可继承 |
BOM 的作用
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2025.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
作用:
-
批量管理一组依赖版本。
-
避免每个依赖都手写版本。
-
保证一整套框架版本兼容。
JeecgBoot 中就导入了:
-
Spring Cloud BOM
-
Spring Cloud Alibaba BOM
一句话:
BOM 是一组依赖版本的清单。
传递依赖
A 依赖 B
B 依赖 C
那么 A 通常也会间接拥有 C。
这就是传递依赖。
优点:
-
减少重复声明。
-
框架 starter 可以自动带入所需依赖。
缺点:
-
容易引入你没意识到的 jar。
-
容易出现版本冲突。
-
可能带来安全漏洞。
-
包体积变大。
Maven 依赖冲突规则
Maven 解决冲突主要有两个规则。
如果同一个依赖出现多个版本:
项目
├── A → C:1.0
└── B → D → C:2.0
Maven 会选 C:1.0 。
因为 C:1.0 离项目更近。
一句话:
谁路径短,谁优先。
路径一样时,先声明优先
如果路径长度一样:
项目
├── A → C:1.0
└── B → C:2.0
如果 A 在 pom.xml 里写在 B 前面,那么优先选择 C:1.0 。
一句话:
路径一样,谁先声明谁优先。
依赖冲突解决


| 异常名称 | 含义 | 最常见原因 |
|---|---|---|
| ClassNotFoundException | 运行时找不到类 | 依赖没引入、jar 包未下载、打包漏包 |
| NoClassDefFoundError | 编译时有,运行时没有 | 依赖冲突、版本不兼容、类加载失败 |
| NoSuchMethodError | 找不到方法(编译通过,运行报错) | 依赖版本不一致(运行时版本和编译时不一样) |
| NoSuchFieldError | 找不到字段 | 依赖版本冲突、类版本不匹配 |
| BeanCreationException | Spring 创建 Bean 失败 | Spring 组件版本不兼容、配置错误 |
| UnsatisfiedDependencyException | Bean 依赖注入失败 | 依赖缺失、Bean 未被 Spring 管理、循环依赖 |
排查依赖冲突的方法





-
看 POM:依赖在哪里声明。
-
看树:依赖从哪里传进来。
-
看版本:最终使用哪个版本。
-
看 scope:运行时是否存在。
-
看 exclusion:是否误排除了依赖。
-
看 effective-pom:最终 Maven 配置是什么。
项目单体到微服务转换
项目里有云模式条件类:
JeecgCloudCondition.java
这类配置通常用于判断当前是否启用 Cloud 模式。
效果类似:
如果是单体模式:
加载本地调用相关 Bean
如果是微服务模式:
加载 Cloud / Feign / Nacos 相关 Bean
也就是说:
通过配置条件,决定加载单体 Bean 还是微服务 Bean。
jeecg-boot-base-core
基础
把所有业务模块都会用到的"横切能力"和"基础设施能力"沉淀成一个公共核心包。
它不应该承载具体业务,比如订单、客户、流程审批细节。
它主要解决这些问题:
所有模块怎么统一返回?
所有模块怎么统一异常?
所有模块怎么做登录鉴权?
所有模块怎么做数据权限?
所有模块怎么访问当前登录用户?
所有模块怎么防 SQL 注入?
所有模块怎么做租户隔离?
所有模块怎么统一 Swagger?
所有模块怎么接 OSS / MinIO?
所有模块怎么做字典翻译?
所以它是一个 基础设施层 + 通用能力层 + 横切关注点层 。
启动模块
↓
业务模块
↓
系统 API / 公共 API
↓
base-core
在 JeecgBoot 里:
jeecg-system-start
jeecg-system-cloud-start
jeecg-demo-cloud-start
↓
jeecg-system-biz
jeecg-module-demo
↓
jeecg-boot-base-core
上层业务模块依赖 base-core ,但 base-core 不应该反向依赖具体业务模块。
三个核心包怎么理解
org.jeecg.common
org.jeecg.config
org.jeecg.modules.base
| 包名 | 定位 | 作用 |
|---|---|---|
| org.jeecg.common | 通用模型与工具层 | 存放返回对象、异常类、常量、DTO、VO、各类工具类 |
| org.jeecg.config | 框架配置层 | 整合 Shiro、MyBatis、Swagger、Druid、WebMvc、OSS、接口签名等配置 |
| org.jeecg.modules.base | 基础服务抽象层 | 提供公共服务接口、通用 Mapper、系统日志等底层基础能力 |
org.jeecg.common
统一返回结构
java@Schema(description = "成功标志") private boolean success = true; /** * 返回处理消息 */ @Schema(description = "返回处理消息") private String message = ""; /** * 返回代码 */ @Schema(description = "返回代码") private Integer code = 0; /** * 返回数据对象 data */ @Schema(description = "返回数据对象") private T result; /** * 时间戳 */ @Schema(description = "时间戳") private long timestamp = System.currentTimeMillis();不让每个 Controller 自己随便返回数据结构。
code == 200:成功
code == 401:未登录
success == false:失败
message:提示信息
result:业务数据
统一异常处理
@RestControllerAdvice
@Slf4j
public class JeecgBootExceptionHandler
Controller 抛出的异常,统一在这里转换成 Result 返回给前端。


业务代码只负责抛异常,不负责拼错误响应。
常量和枚举
CommonConstant
ServiceNameConstants
TenantConstant
DataBaseConstant
把系统中反复使用的固定值统一收口。
这些的作用是:
把系统中反复使用的固定值统一收口。
比如:
HTTP 状态码
服务名
租户字段
数据权限标识
消息类型
文件类型
操作类型
设计原则:
不要让魔法字符串散落在业务代码里。
工具类
JwtUtil
TokenUtils
SpringContextUtils
SqlInjectionUtil
OssBootUtil
MinioUtil
CommonUtils
DateUtils
PasswordUtil
IpUtils
它们解决的是通用操作:
解析 Token
获取 Spring Bean
SQL 注入校验
文件上传
密码加密
日期转换
IP 获取
工具类是方便,但不能滥用。公共层工具类应该只放跨模块都需要的能力。
org.jeecg.config
是 Spring Boot 配置中心。
它把各种框架能力统一装配进项目。
Shiro + JWT 安全配置
请求进来
↓
JwtFilter
↓
解析 token
↓
ShiroRealm 校验用户
↓
判断权限
↓
放行或拒绝
认证鉴权属于横切能力,不应该散落在业务 Controller 里。
业务层只需要写权限注解或调用权限判断。
MyBatis-Plus 与多租户
这里通常处理:
-
MyBatis-Plus 插件
-
租户隔离
-
动态表名
-
SQL 拦截
-
数据权限条件拼接
设计思想:
租户隔离和数据权限尽量下沉到持久层拦截器,而不是每个业务 SQL 手写一遍。
这样业务代码不用到处写:
tenant_id = 当前租户
而是由框架层统一处理。
Swagger / Knife4j 配置
Swagger2Config
Swagger3Config
作用:
-
自动生成接口文档
-
扫描 Controller
-
定义接口分组、安全参数等
设计思想:
API 文档属于工程基础能力,不属于业务逻辑。
Druid 数据源配置
DruidConfig
DruidWallConfigRegister
DruidWallConfigRegister

单体 / 微服务条件配置
context.getEnvironment().getProperty(CommonConstant.CLOUD_SERVER_KEY)
如果存在云服务配置,就认为是微服务环境。
设计思想:
同一套公共代码,根据环境决定是否启用 Cloud 相关 Bean。
所以这里不是 Maven 依赖自动切换,而是:
启动模块决定依赖
配置条件决定 Bean 是否加载
org.jeecg.modules.base
这里通常放基础公共服务,例如:
BaseCommonMapper
BaseCommonService
它的作用是为公共层提供一些基础服务能力。
比如异常处理器里就依赖了:
@RestControllerAdvice
@Slf4j
public class JeecgBootExceptionHandler {
@Resource
BaseCommonService baseCommonService;
常见用途:
-
记录系统日志
-
查询公共字典
-
查询公共用户信息
-
获取公共系统配置
设计思想:
公共层有些能力需要访问数据库,但又不能直接依赖具体业务实现,所以通过基础服务接口抽象出来。
设计尊则
单向依赖原则
业务模块 → base-core
base-core 不反向依赖业务模块
这样公共层才稳定。
如果公共层依赖业务层,就会变成循环依赖。
横切能力集中管理
这些能力都属于横切关注点:
它们不属于某一个业务模块,所以放在 base-core 。
认证
鉴权
日志
异常
返回值
租户
数据权限
SQL 防护
接口文档
文件存储
统一契约
统一返回 Result
统一异常 JeecgBootException
统一登录用户 LoginUser
统一服务名 ServiceNameConstants
统一状态码 CommonConstant
好处:
-
前后端约定稳定
-
业务模块风格一致
-
微服务之间调用格式统一
-
排查问题更容易
配置优于硬编码
例如:
-
OSS 配置
-
MinIO 配置
-
Swagger 配置
-
Shiro 白名单
-
Cloud 条件
-
Druid 配置
这些都不应该写死在业务代码里。
应该通过:
application.yml
配置类
条件注解
配置属性类
可插拔能力
比如文件存储:
```
本地存储
MinIO
阿里云 OSS
七牛云
```
它们本质上都是"文件能力",不应该让业务模块关心底层是哪个供应商。
业务模块只应该调用统一工具或服务。
这就是可插拔思想。
单体和微服务兼容
单体模式
微服务模式
条件加载
配置判断
local-api / cloud-api 分离
starter 分离
jeecg-boot-module
JeecgBoot 的"业务扩展模块层"。
它不是系统核心层,也不是公共基础层,而是用来承载 可插拔业务模块、示例模块、AI 扩展模块 的地方。
启动层
↓
业务扩展层:jeecg-boot-module
↓
系统能力层:jeecg-module-system
↓
公共基础层:jeecg-boot-base-core
jeecg-boot-module 更偏向:
具体业务能力
示例业务
扩展功能
AI / RAG 等独立业务模块
目前主要包括:
jeecg-boot-module
├── jeecg-module-demo
└── jeecg-boot-module-airag

设计思路
jeecg-boot-module 的核心设计思路是:
把非系统核心业务从 system 模块中拆出来,避免系统模块越来越臃肿。
也就是说:
-
用户、角色、菜单、权限、部门等基础平台能力放在 jeecg-module-system
-
通用框架能力放在 jeecg-boot-base-core
-
独立业务、扩展业务、示例业务放在 jeecg-boot-module
这样项目不会变成一个大杂烩。
jeecg-boot-module 里的业务不应该反向修改公共核心能力。
jeecg-boot-module
↓
jeecg-module-system / system-api
↓
jeecg-boot-base-core
公共核心层不能依赖扩展业务层。
jeecg-boot-base-core
↓
jeecg-boot-module
每个扩展模块应该有自己的:
controller
service
mapper
entity
vo/dto
resources
一个业务能力尽量在一个模块内闭合。
jeecg-boot-module 的存在,本质上让项目具备一种插件化思路:
需要 demo 模块 → 引入 jeecg-module-demo
需要 AI RAG → 引入 jeecg-boot-module-airag
需要新业务 → 新增一个独立 module
好处是:
-
业务可拆分
-
功能可选装
-
模块可独立维护
-
不影响系统核心能力'
jeecg-module-system
它是整个项目的 核心业务基座 ,可以理解为:
平台级业务能力模块,提供系统管理、用户/权限/菜单/字典/租户等基础平台能力。
启动层:system-start / system-cloud-start
↓
核心业务层:jeecg-module-system ← 你现在问的
↓
公共基础层:jeecg-boot-base-core
jeecg-module-system├── jeecg-system-api ← 对外接口层
├── jeecg-system-biz ← 业务实现层
└── jeecg-system-start ← 单体启动层
jeecg-system-api
jeecg-system-api
├── jeecg-system-local-api
└── jeecg-system-cloud-api
设计思想:
业务能力的接口契约与调用方式分离。
-
local-api 给单体本 JVM 调用
-
cloud-api 给微服务场景下远程调用
这样 biz 实现层只写一份业务代码,上层调用方式可以切换。
jeecg-system-biz
这是真正承载业务逻辑的地方,一般会有:
modules
├── system ← 用户、角色、菜单、部门、字典、租户、权限...
├── message ← 消息、通知
├── monitor ← 日志、监控
├── online ← 在线表单、低代码配置
└── desform ← 设计器表单
设计思想:
业务能力放在 biz,启动层和 API 层只负责装配和暴露。
jeecg-system-start
路径: jeecg-system-start
单体 Spring Boot 启动入口,作用:
-
聚合 biz、local-api、base-core
-
提供单体 application.yml 配置
-
作为本地开发与单体部署的启动入口
对应的微服务启动入口在 jeecg-server-cloud 下。
设计准则
3.1 接口与实现分离
业务接口放 jeecg-system-api ,实现放 jeecg-system-biz 。
好处:
调用方只依赖接口,不直接耦合实现
单体/微服务两种调用方式可以各自实现同一份接口契约
后续重构业务实现更安全
jeecg-module-system 负责平台能力, jeecg-boot-module 负责扩展业务。不建议把业务功能塞进 system 模块里。
原因:
平台能力一旦被业务污染,升级与维护会越来越难。
biz 模块依赖:
base-core(基础设施、通用返回、异常、工具、配置)
必要的数据库访问(MyBatis-Plus、Druid、多租户)
不反向依赖:
启动模块
外部扩展业务模块
微服务治理模块(cloud/gateway/nacos 相关)
原则:
业务实现越纯,后面越容易复用。
jeecg-system-start 不应该写业务,它只负责:
引入依赖
写启动类
写 application.yml
提供数据库脚本与 Flyway(如果有)
提供前端可访问的静态资源
biz 模块里的业务代码不应该重新实现:
登录用户获取
权限判断
统一返回 Result
异常抛出
字典翻译
文件上传
数据权限条件
这些都应该从 jeecg-boot-base-core 拿。
原则:
横切关注点不在业务层重复造轮子。

