You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
RuoYi-Vue/docs/architecture/backend-architecture.md

22 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

RuoYi-Vue 后端架构分析

版本3.8.0 | 分析日期2026-06-28 | 框架Spring Boot 2.5.8


1. 分层架构分析

1.1 整体分层概览

项目采用经典的 四层架构Controller → Service → Mapper → Domain各层职责清晰通过 Maven 多模块进行物理隔离。

┌─────────────────────────────────────────────────────────────┐
│                      ruoyi-admin (启动层)                     │
│  ┌─────────────┐  ┌─────────────┐  ┌──────────────────────┐ │
│  │ Controller  │  │  Config     │  │   Application        │ │
│  │   (18个)    │  │  (Swagger)  │  │   RuoYiApplication   │ │
│  └──────┬──────┘  └─────────────┘  └──────────────────────┘ │
│         │                                                   │
│         ▼                                                   │
│  ┌──────────────────────────────────────────────────────┐   │
│  │              ruoyi-framework (框架层)                  │   │
│  │  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐ │   │
│  │  │ Aspect   │ │ Security │ │ Config   │ │ Manager │ │   │
│  │  │ (4个切面)│ │ (JWT)    │ │ (12个)   │ │ (异步)  │ │   │
│  │  └──────────┘ └──────────┘ └──────────┘ └─────────┘ │   │
│  └──────────────────────┬───────────────────────────────┘   │
│                         │                                   │
│         ┌───────────────┼───────────────┐                   │
│         ▼               ▼               ▼                   │
│  ┌──────────┐   ┌──────────┐   ┌──────────────┐            │
│  │ruoyi-    │   │book-     │   │ stock-       │            │
│  │system    │   │system    │   │ system       │            │
│  │(15 Mapper│   │(6 Mapper │   │ (9 Mapper    │            │
│  │ 12 Service│   │ 6 Service│   │  ...         │            │
│  │ 12 Domain)│   │ 6 Domain)│   │              │            │
│  └──────────┘   └──────────┘   └──────────────┘            │
│                         │                                   │
│                         ▼                                   │
│  ┌──────────────────────────────────────────────────────┐   │
│  │               ruoyi-common (通用工具层)                │   │
│  │  BaseController / AjaxResult / BaseEntity / 注解 /    │   │
│  │  工具类(20+) / 异常类 / 过滤器 / 常量                 │   │
│  └──────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────┘

1.2 Controller 层分析

文件位置ruoyi-admin/src/main/java/com/ruoyi/web/controller/

Controller 统计

分类 数量 文件列表
系统管理 13 SysConfigController, SysDeptController, SysDictDataController, SysDictTypeController, SysIndexController, SysLoginController, SysMenuController, SysNoticeController, SysPostController, SysProfileController, SysRegisterController, SysRoleController, SysUserController
监控管理 5 CacheController, ServerController, SysLogininforController, SysOperlogController, SysUserOnlineController
业务模块 6 AccountBookController, AccountController, OperationsController, StatisticsController, StatisticsRemainController, StatisticsTotalController
工具/公共 4 CaptchaController, CommonController, SwaggerController, TestController
合计 28

设计模式

  1. 统一继承 BaseController:所有 Controller 继承 BaseController,获得分页、响应、用户上下文等通用能力。

  2. 标准 CRUD 接口模式

    GET    /list          → 分页列表查询
    GET    /{id}          → 详情查询
    POST   /              → 新增
    PUT    /              → 修改
    DELETE /{ids}         → 批量删除
    POST   /export        → Excel 导出
    POST   /importData    → Excel 导入
    
  3. 权限注解驱动:每个接口通过 @PreAuthorize("@ss.hasPermi('module:entity:action')") 进行权限控制。

  4. 操作日志注解:通过 @Log(title = "模块名", businessType = BusinessType.XXX) 声明式记录操作日志。

1.3 Service 层分析

文件位置

  • 系统模块:ruoyi-system/src/main/java/com/ruoyi/system/service/
  • 账务模块:book-system/src/main/java/com/ruoyi/booksystem/service/

接口与实现分离

采用标准的 接口 + 实现类 模式:

ISysUserService (接口)
    └── SysUserServiceImpl (实现)
模块 接口数 实现类数
ruoyi-system 12 12
book-system 6 6

事务管理

使用 @Transactional 注解管理事务,主要在以下场景使用:

场景 方法示例
新增用户(含角色/岗位关联) insertUser()
修改用户(含角色/岗位关联) updateUser()
删除用户(含关联清理) deleteUserById(), deleteUserByIds()
用户授权角色 insertUserAuth()

事务策略特点

  • 仅在涉及多表操作的复合方法上加 @Transactional
  • 简单 CRUDupdateUserStatus)不使用事务
  • 使用默认的 REQUIRED 传播级别和 RuntimeException 回滚策略

数据权限注解

Service 层通过 @DataScope(deptAlias = "d", userAlias = "u") 注解实现数据权限过滤,在方法执行前由 AOP 切面动态注入 SQL 过滤条件。

1.4 Mapper 层分析

文件位置

  • XML 映射:{module}/src/main/resources/mapper/{module}/
  • Java 接口:{module}/src/main/java/com/ruoyi/{module}/mapper/

MyBatis 映射文件统计

模块 XML 文件数 主要功能
ruoyi-system 11 用户、角色、菜单、部门、字典、岗位、日志、配置、公告
book-system 6 账户、账本、操作、统计
stock-system 9 股票、行情、财务、趋势
ruoyi-quartz 2 定时任务
ruoyi-generator 2 代码生成
合计 30

动态 SQL 使用

SysUserMapper.xml 为例,大量使用 MyBatis 动态 SQL

标签 用途 示例
<if> 条件查询 <if test="userName != null and userName != ''">
<foreach> 批量操作 <foreach collection="array" item="userId">
<include> SQL 片段复用 <include refid="selectUserVo"/>
<sql> 定义可复用片段 <sql id="selectUserVo">
<set> 动态更新 <set><if test="...">field = #{...},</if></set>
${params.dataScope} 数据权限注入 由 DataScopeAspect 动态拼接

ResultMap 关联映射

使用 <association><collection> 实现一对多关联查询:

<association property="dept" javaType="SysDept" resultMap="deptResult" />
<collection property="roles" javaType="java.util.List" resultMap="RoleResult" />

1.5 Domain 层分析

基类体系

BaseEntity (基础实体)
    ├── searchValue, createBy, createTime, updateBy, updateTime, remark, params
    │
    ├── TreeEntity (树形实体)
    │       └── parentId, ancestors
    │
    └── AjaxResult (统一响应)
            └── code, msg, data (继承 HashMap)

核心实体类

实体 位置 用途
SysUser ruoyi-common 用户信息
SysRole ruoyi-common 角色信息
SysMenu ruoyi-common 菜单/权限
SysDept ruoyi-common 部门信息
LoginUser ruoyi-common 登录用户上下文
SysConfig/SysNotice/SysOperLog ruoyi-system 系统业务实体
Account/AccountBook/Statistics book-system 账务业务实体

2. 安全配置

2.1 Spring Security 配置

配置文件ruoyi-framework/.../config/SecurityConfig.java

认证流程

HTTP Request
    │
    ▼
┌──────────────────────┐
│    CorsFilter        │ ← 跨域处理
└──────────┬───────────┘
           ▼
┌──────────────────────┐
│ JwtAuthentication    │ ← JWT Token 验证
│     TokenFilter      │
└──────────┬───────────┘
           ▼
┌──────────────────────┐
│  UsernamePassword    │ ← Spring Security 内置
│ AuthenticationFilter │
└──────────┬───────────┘
           ▼
┌──────────────────────┐
│  Controller Handler  │
└──────────────────────┘

安全配置要点

配置项 值/策略
CSRF 禁用(无状态 Token 认证)
Session STATELESS无会话
密码加密 BCryptPasswordEncoder
匿名路径 /login, /register, /captchaImage
公共资源 /**/*.html, /**/*.css, /**/*.js, /profile/**
Swagger /swagger-ui.html, /swagger-resources/**
监控 /druid/**
其他所有请求 需要认证

方法级安全

@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
  • 启用 @PreAuthorize@PostAuthorize 方法级权限控制
  • 启用 @Secured 注解支持

2.2 JWT Token 机制

核心类ruoyi-framework/.../web/service/TokenService.java

Token 结构

JWT Header + Payload                    Redis 缓存
┌─────────────────────┐              ┌──────────────────────┐
│ {                   │              │ login_tokens:{uuid}  │
│   LOGIN_USER_KEY    │──uuid──→    │ {                    │
│   : uuid            │              │   LoginUser Object   │
│ }                   │              │   TTL: 30min         │
└─────────────────────┘              └──────────────────────┘

关键参数

参数 配置项 默认值
Token Header token.header Authorization
Token Secret token.secret 自定义密钥
Token 有效期 token.expireTime 30 分钟
自动刷新阈值 硬编码 剩余不足 20 分钟时刷新

Token 工作流程

  1. 登录 → 生成 UUID → 存入 Redis → JWT 携带 UUID → 返回 Token
  2. 请求 → 提取 Token → 解析 UUID → Redis 获取用户 → 验证有效期
  3. 刷新 → 距过期不足 20 分钟 → 自动续期 Redis TTL
  4. 登出 → 删除 Redis 中的用户缓存

2.3 权限控制体系

权限模型

用户 (SysUser)
  └── 角色 (SysRole) [多对多]
        └── 菜单/权限 (SysMenu) [多对多]
              └── 权限标识: "system:user:list"

三种权限控制方式

方式 注解/实现 层级 用途
URL 级 Spring Security antMatchers 网关 公开/匿名资源
方法级 @PreAuthorize("@ss.hasPermi('...')") Controller 功能权限
数据级 @DataScope(deptAlias, userAlias) Service 数据范围过滤

PermissionService 权限判断

@Service("ss")
public class PermissionService {
    hasPermi("system:user:list")    // 是否拥有某权限
    lacksPermi("system:user:list")  // 是否不拥有某权限
    hasAnyPermi("a,b,c")            // 是否拥有任一权限
    hasRole("admin")                // 是否拥有某角色
    lacksRole("admin")              // 是否不拥有某角色
    hasAnyRoles("admin,common")     // 是否拥有任一角色
}

权限标识约定:{模块}:{实体}:{操作},如 system:user:listbooksystem:account:add


3. AOP 切面分析

文件位置ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/

3.1 切面总览

┌─────────────────────────────────────────────────────┐
│                  AOP 切面 (4个)                       │
│                                                     │
│  ┌──────────────┐  ┌──────────────┐                │
│  │ LogAspect    │  │ DataScope    │                │
│  │ @AfterRet    │  │ @Before      │                │
│  │ @AfterThrow  │  │ 数据权限过滤  │                │
│  └──────────────┘  └──────────────┘                │
│                                                     │
│  ┌──────────────┐  ┌──────────────┐                │
│  │ DataSource   │  │ RateLimiter  │                │
│  │ @Around      │  │ @Before      │                │
│  │ 多数据源切换  │  │ Redis 限流   │                │
│  │ Order(1)     │  │              │                │
│  └──────────────┘  └──────────────┘                │
└─────────────────────────────────────────────────────┘

3.2 日志切面 (LogAspect)

属性
触发方式 @annotation(Log)
通知类型 @AfterReturning(成功)、@AfterThrowing(异常)
记录内容 操作用户、IP、URL、方法名、请求参数、响应结果、业务类型、状态
写入策略 异步写入AsyncManager + AsyncFactory不阻塞主线程
参数过滤 自动过滤 MultipartFile、HttpServletRequest 等不可序列化对象

3.3 数据权限切面 (DataScopeAspect)

属性
触发方式 @annotation(DataScope)
通知类型 @Before
权限级别 5 种:全部(1)、自定义(2)、本部门(3)、本部门及以下(4)、仅本人(5)
实现原理 在查询参数 params.dataScope 中注入 SQL 片段XML 中通过 ${params.dataScope} 拼接
安全机制 执行前先清空 dataScope 参数防止 SQL 注入

SQL 拼接示例

-- 本部门权限
AND (d.dept_id = 100)
-- 本部门及以下
AND (d.dept_id IN (SELECT dept_id FROM sys_dept WHERE dept_id = 100 
     OR find_in_set(100, ancestors)))

3.4 数据源切面 (DataSourceAspect)

属性
触发方式 @annotation(DataSource)@within(DataSource)
通知类型 @Around
优先级 @Order(1)(最高优先级)
实现原理 通过 ThreadLocal 设置当前线程的数据源标识,执行完毕后清理
底层支持 DynamicDataSource(继承 AbstractRoutingDataSource

3.5 限流切面 (RateLimiterAspect)

属性
触发方式 @annotation(RateLimiter)
通知类型 @Before
存储介质 Redis + Lua 脚本(原子操作)
限流维度 默认方法级、IPIP + 方法级)
可配置参数 key(键前缀)、time(时间窗口/秒)、count(最大请求数)
默认值 60 秒内最多 100 次请求
失败响应 抛出 ServiceException("访问过于频繁,请稍候再试")

4. 模块依赖

4.1 模块依赖图

                    ┌─────────────┐
                    │ ruoyi-admin │  ← 启动入口,打包部署
                    └──────┬──────┘
                           │
            ┌──────────────┼──────────────┐
            ▼              ▼              ▼
     ┌───────────┐  ┌───────────┐  ┌──────────────┐
     │ruoyi-     │  │ruoyi-     │  │ ruoyi-       │
     │system     │  │quartz     │  │ generator    │
     └─────┬─────┘  └─────┬─────┘  └──────┬───────┘
           │              │               │
           ▼              ▼               ▼
     ┌──────────────────────────────────────────┐
     │          ruoyi-framework                  │
     │  (Security, AOP, DataSource, Config)      │
     └────────────────────┬─────────────────────┘
                          │
           ┌──────────────┼──────────────┐
           ▼              ▼              ▼
     ┌───────────┐  ┌───────────┐  ┌──────────────┐
     │book-      │  │stock-     │  │ ruoyi-       │
     │system     │  │system     │  │ common       │
     └─────┬─────┘  └─────┬─────┘  └──────┬───────┘
           │              │               │
           └──────────────┼───────────────┘
                          ▼
                   (所有业务模块依赖)

4.2 模块职责

模块 职责 核心内容
ruoyi-admin 启动入口 & Controller 层 SpringBoot 启动类、Controller、Swagger 配置
ruoyi-framework 框架核心 Security 配置、JWT、AOP 切面、数据源、Redis、MyBatis 配置
ruoyi-system 系统管理业务 用户、角色、菜单、部门、字典、岗位、日志的 Service/Mapper/Domain
ruoyi-common 通用工具 基类、工具类、注解、常量、异常、过滤器、分页组件
book-system 账务业务模块 账本、账户、操作记录、统计的 CRUD
stock-system 股票业务模块 股票信息、行情、财务、趋势分析
ruoyi-quartz 定时任务 基于 Quartz 的任务调度
ruoyi-generator 代码生成 基于 Velocity 模板的代码生成器

4.3 技术栈汇总

分类 技术 版本
核心框架 Spring Boot 2.5.8
JDK Java 1.8
安全框架 Spring Security + JWT 内置 + jjwt 0.9.1
ORM MyBatis 2.2.0 (spring-boot-starter)
分页 PageHelper 1.4.0
数据库连接池 Druid 1.2.8
缓存 Redis (Spring Data Redis) 内置
API 文档 Springfox Swagger 3 3.0.0
JSON FastJSON 1.2.79
Excel Apache POI 4.1.2
验证码 Kaptcha 2.3.2
代码生成 Velocity 2.3
系统监控 Oshi 5.8.6

5. 存在的问题

# 问题 严重等级 影响范围 优化建议
1 fastjson 版本存在已知漏洞 🔴 全系统 fastjson 1.2.79 存在多个 CVE 漏洞(如 CVE-2022-25845建议升级至 2.xfastjson2或替换为 Jackson/Gson
2 使用已废弃的 WebSecurityConfigurerAdapter 🟡 安全配置 Spring Security 5.7+ 已废弃 WebSecurityConfigurerAdapter,应改用 SecurityFilterChain Bean 配置方式
3 Token 解析异常被静默吞没 🟡 认证模块 TokenService.getLoginUser() 中 catch 块为空(第 72-74 行),异常被完全忽略,建议至少记录 WARN 日志
4 SQL 注入风险:${params.dataScope} 🟡 数据权限层 MyBatis XML 中 ${params.dataScope} 使用 ${} 直接拼接,虽有 DataScopeAspect 前置清空防护,但仍存在绕过风险;建议使用参数化方案或严格校验
5 业务 Controller 缺少 @Log 注解 🟢 book-system book-system 下的 Controller 中 AccountController 等部分接口缺少 @Log 操作日志注解,审计不完整
6 缺少统一 DTO/VO 分层 🟢 全系统 Domain 实体直接暴露给 Controller 层(如 SysUser 同时用于数据库映射和接口响应),密码等敏感字段需额外处理;建议引入独立的 DTO/VO 对象
7 Service 层直接注入 Mapper而非通过接口 🟢 全系统 SysUserServiceImpl 中使用 @Autowired private SysUserMapper userMapper 直接注入实现类,虽然 MyBatis 通过代理实现,但不符合面向接口编程原则
8 缺少接口版本控制 🟢 API 设计 所有 API 路径无版本号(如 /api/v1/system/user),未来接口升级时无法平滑过渡

文档结束