<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>RuoYi-Vue-Plus 项目详解:架构、原理与设计思想</title>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;700&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<style>
/* 基础样式 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Noto Sans SC', sans-serif;
background-color: #f5f7fa;
color: #333;
line-height: 1.6;
}
.poster-container {
width: 960px;
min-height: 3000px;
margin: 0 auto;
background-color: #ffffff;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
padding: 40px;
overflow: visible;
}
/* 标题样式 */
.main-title {
font-size: 42px;
font-weight: 700;
color: #1a73e8;
text-align: center;
margin-bottom: 30px;
padding-bottom: 15px;
border-bottom: 3px solid #e8f0fe;
}
.section-title {
font-size: 28px;
font-weight: 600;
color: #1a73e8;
margin: 40px 0 20px;
padding-left: 15px;
border-left: 5px solid #1a73e8;
}
.subsection-title {
font-size: 22px;
font-weight: 500;
color: #4285f4;
margin: 25px 0 15px;
}
/* 内容样式 */
.content {
margin-bottom: 30px;
}
p {
margin-bottom: 15px;
font-size: 18px;
text-align: justify;
}
ul, ol {
margin-left: 25px;
margin-bottom: 15px;
}
li {
margin-bottom: 10px;
font-size: 18px;
}
/* 代码块样式 */
.code-block {
background-color: #f8f9fa;
border: 1px solid #e1e4e8;
border-radius: 6px;
padding: 16px;
margin: 15px 0;
overflow-x: auto;
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
font-size: 16px;
line-height: 1.5;
}
.code-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
padding-bottom: 8px;
border-bottom: 1px solid #e1e4e8;
}
.code-language {
font-size: 14px;
font-weight: 600;
color: #6a737d;
}
pre {
margin: 0;
white-space: pre-wrap;
word-wrap: break-word;
}
/* 表格样式 */
table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
font-size: 16px;
}
th, td {
border: 1px solid #e1e4e8;
padding: 12px;
text-align: left;
}
th {
background-color: #f6f8fa;
font-weight: 600;
}
/* 高亮样式 */
.highlight {
background-color: #fff8e1;
padding: 2px 4px;
border-radius: 3px;
}
.note {
background-color: #e8f0fe;
border-left: 4px solid #1a73e8;
padding: 15px;
margin: 20px 0;
border-radius: 0 4px 4px 0;
}
/* 图标样式 */
.material-icons {
vertical-align: middle;
margin-right: 8px;
color: #1a73e8;
}
/* 架构图样式 */
.architecture-diagram {
display: flex;
flex-direction: column;
align-items: center;
margin: 30px 0;
}
.arch-layer {
width: 90%;
padding: 15px;
margin: 10px 0;
border-radius: 6px;
text-align: center;
font-weight: 500;
}
.frontend-layer {
background-color: #e8f0fe;
color: #1a73e8;
}
.backend-layer {
background-color: #e6f4ea;
color: #0f9d58;
}
.data-layer {
background-color: #fce8e6;
color: #ea4335;
}
/* 特性卡片样式 */
.feature-cards {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
margin: 20px 0;
}
.feature-card {
width: 48%;
background-color: #f8f9fa;
border-radius: 8px;
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
.feature-card h4 {
color: #1a73e8;
margin-bottom: 10px;
font-size: 20px;
}
</style>
</head>
<body>
<div class="poster-container">
<h1 class="main-title">RuoYi-Vue-Plus 项目详解:架构、原理与设计思想</h1>
<!-- 项目概述 -->
<section id="project-overview">
<h2 class="section-title">项目概述</h2>
<div class="content">
<p>RuoYi-Vue-Plus 是基于 Vue3 和 SpringBoot 的一款现代化后台管理系统,它对原始的 RuoYi-Vue 进行了全面重构,专为分布式集群和多租户场景设计。项目不仅代码和文档开放且免费,还提供了高度的可定制性和扩展性,适用于商业应用。</p>
<div class="note">
<p><i class="material-icons">info</i>RuoYi-Vue-Plus 是 dromara 组织下的开源项目,完全遵循 MIT 开源协议,可以免费用于个人及商业用途。</p>
</div>
<h3 class="subsection-title">项目定位</h3>
<p>RuoYi-Vue-Plus 定位为企业级多租户后台管理系统,旨在提供一个开箱即用、高度可扩展的开发平台,使开发者能够快速构建企业级应用,减少重复开发工作,提高开发效率。</p>
<h3 class="subsection-title">主要特点</h3>
<ul>
<li><strong>前后端分离</strong>:采用 Vue3 + SpringBoot 的前后端分离架构,便于团队协作和独立部署</li>
<li><strong>多租户支持</strong>:原生支持多租户架构,实现数据隔离和权限控制</li>
<li><strong>插件化设计</strong>:核心功能模块化,支持插件式扩展,降低系统耦合度</li>
<li><strong>权限精细控制</strong>:基于 Sa-Token 的权限认证和授权,支持数据权限和菜单权限</li>
<li><strong>工作流引擎</strong>:集成 Warm-Flow 工作流引擎,支持复杂业务流程设计</li>
<li><strong>代码生成</strong>:提供强大的代码生成器,一键生成前后端代码</li>
</ul>
</div>
</section>
<!-- 技术架构 -->
<section id="technical-architecture">
<h2 class="section-title">技术架构</h2>
<div class="content">
<h3 class="subsection-title">前端技术栈</h3>
<ul>
<li><strong>Vue 3</strong>:采用 Vue 3 作为前端框架,利用 Composition API 提高代码复用性和可维护性</li>
<li><strong>TypeScript</strong>:全面使用 TypeScript 增强代码类型安全性和开发体验</li>
<li><strong>Element Plus</strong>:基于 Element Plus 组件库构建 UI 界面,提供丰富的组件和主题定制能力</li>
<li><strong>Vite</strong>:使用 Vite 作为构建工具,提供快速的开发服务器和优化的生产构建</li>
<li><strong>Pinia</strong>:采用 Pinia 作为状态管理库,替代 Vuex,提供更简洁的 API 和更好的 TypeScript 支持</li>
</ul>
<h3 class="subsection-title">后端技术栈</h3>
<ul>
<li><strong>Spring Boot</strong>:基于 Spring Boot 3.x 框架,简化应用开发和部署</li>
<li><strong>Spring Security</strong>:集成 Spring Security 提供安全认证和授权功能</li>
<li><strong>MyBatis-Plus</strong>:使用 MyBatis-Plus 作为 ORM 框架,简化数据库操作</li>
<li><strong>Sa-Token</strong>:采用 Sa-Token 替代传统 Shiro,提供更轻量、更强大的权限控制</li>
<li><strong>Hutool</strong>:集成 Hutool 工具库,提供丰富的 Java 工具方法</li>
<li><strong>Warm-Flow</strong>:集成 Warm-Flow 工作流引擎,支持复杂业务流程设计</li>
</ul>
<h3 class="subsection-title">系统架构设计</h3>
<div class="architecture-diagram">
<div class="arch-layer frontend-layer">前端层 (Vue3 + Element Plus)</div>
<div class="arch-layer backend-layer">后端层 (Spring Boot + Sa-Token)</div>
<div class="arch-layer data-layer">数据层 (MySQL + Redis)</div>
</div>
<p>系统采用分层架构设计,清晰划分各层职责,实现高内聚低耦合。前端层负责用户界面展示和交互,后端层负责业务逻辑处理和数据访问,数据层负责数据存储和缓存。</p>
<h3 class="subsection-title">模块划分</h3>
<p>项目采用模块化设计,主要包含以下核心模块:</p>
<ul>
<li><strong>ruoyi-admin</strong>:系统启动模块,包含系统配置和启动类</li>
<li><strong>ruoyi-common</strong>:公共模块,包含工具类、通用注解和异常处理等</li>
<li><strong>ruoyi-framework</strong>:框架核心模块,包含安全、权限、缓存等核心功能</li>
<li><strong>ruoyi-system</strong>:系统管理模块,包含用户、角色、菜单等系统管理功能</li>
<li><strong>ruoyi-job</strong>:定时任务模块,提供定时任务调度功能</li>
<li><strong>ruoyi-generator</strong>:代码生成模块,提供代码生成功能</li>
</ul>
</div>
</section>
<!-- 核心特性 -->
<section id="core-features">
<h2 class="section-title">核心特性</h2>
<div class="content">
<div class="feature-cards">
<div class="feature-card">
<h4><i class="material-icons">apartment</i>多租户支持</h4>
<p>原生支持多租户架构,通过租户 ID 实现数据隔离,每个租户拥有独立的数据空间,确保数据安全。支持动态数据源切换,可配置不同租户使用不同数据库。</p>
</div>
<div class="feature-card">
<h4><i class="material-icons">security</i>权限管理</h4>
<p>基于 Sa-Token 的权限认证和授权,支持 JWT 认证。提供细粒度的权限控制,包括菜单权限、按钮权限和数据权限,满足企业级应用的复杂权限需求。</p>
</div>
<div class="feature-card">
<h4><i class="material-icons">account_tree</i>工作流引擎</h4>
<p>集成 Warm-Flow 工作流引擎,支持可视化流程设计、动态流程调整和复杂分支逻辑。与系统权限体系无缝集成,实现精细化的流程权限控制。</p>
</div>
<div class="feature-card">
<h4><i class="material-icons">code</i>代码生成</h4>
<p>提供强大的代码生成器,支持一键生成前后端代码。可根据数据库表结构生成实体类、Mapper、Service、Controller 以及前端页面,大幅提高开发效率。</p>
</div>
</div>
<h3 class="subsection-title">数据权限实现</h3>
<p>RuoYi-Vue-Plus 5.3.0 版本对数据权限系统进行了彻底重构,采用基于 Mybatis-Plus 插件的数据权限解决方案,实现了权限控制与业务逻辑的解耦。</p>
<div class="code-block">
<div class="code-header">
<span class="code-language">Java</span>
</div>
<pre>/**
* 数据权限注解
*/
<span class="mention-invalid">@Target</span>({ElementType.METHOD, ElementType.TYPE})
<span class="mention-invalid">@Retention</span>(RetentionPolicy.RUNTIME)
<span class="mention-invalid">@Documented</span>
public <span class="mention-invalid">@interface</span> DataScope {
/**
* 表别名
*/
String tableAlias() default "";
/**
* 部门ID字段名
*/
String deptId() default "";
/**
* 用户ID字段名
*/
String userId() default "";
}</pre>
</div>
<p>通过 <span class="mention-invalid">@DataScope</span> 注解,可以在 Mapper 接口上声明数据权限规则,Mybatis-Plus 插件会自动根据当前用户的角色数据权限,动态生成对应的 WHERE 条件,实现数据权限的无感过滤。</p>
<h3 class="subsection-title">多数据源支持</h3>
<p>系统支持多数据源配置,可以同时连接多种类型的数据库,实现读写分离和分库分表。通过动态数据源路由,可以根据业务需求自动切换数据源。</p>
<div class="code-block">
<div class="code-header">
<span class="code-language">YAML</span>
</div>
<pre>spring:
datasource:
dynamic:
primary: master #设置默认的数据源或者数据源组,默认值即为master
strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
datasource:
master:
url: jdbc:mysql://localhost:3306/ry-vue
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
slave:
url: jdbc:mysql://localhost:3307/ry-vue
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver</pre>
</div>
</div>
</section>
<!-- 设计思想 -->
<section id="design-philosophy">
<h2 class="section-title">设计思想</h2>
<div class="content">
<h3 class="subsection-title">架构思想</h3>
<p>RuoYi-Vue-Plus 遵循以下架构思想:</p>
<ul>
<li><strong>分层架构</strong>:采用经典的分层架构,清晰划分各层职责,实现高内聚低耦合</li>
<li><strong>模块化设计</strong>:将系统功能划分为多个独立模块,每个模块负责特定功能,便于维护和扩展</li>
<li><strong>插件化扩展</strong>:核心功能采用插件化设计,支持动态加载和卸载,提高系统灵活性</li>
<li><strong>前后端分离</strong>:采用前后端分离架构,前端负责界面展示和用户交互,后端负责业务逻辑和数据处理</li>
</ul>
<h3 class="subsection-title">开发模式</h3>
<p>项目采用以下开发模式:</p>
<ul>
<li><strong>约定优于配置</strong>:遵循约定优于配置的原则,减少配置工作,提高开发效率</li>
<li><strong>面向接口编程</strong>:采用面向接口编程的方式,定义清晰的接口规范,降低模块间耦合</li>
<li><strong>领域驱动设计</strong>:在核心业务模块采用领域驱动设计思想,以业务领域为中心组织代码</li>
<li><strong>测试驱动开发</strong>:鼓励编写单元测试和集成测试,确保代码质量和系统稳定性</li>
</ul>
<h3 class="subsection-title">设计原则</h3>
<p>项目遵循以下设计原则:</p>
<ul>
<li><strong>单一职责原则</strong>:每个类和模块只负责一项功能,保持职责单一</li>
<li><strong>开闭原则</strong>:对扩展开放,对修改关闭,通过扩展而非修改来增加新功能</li>
<li><strong>里氏替换原则</strong>:子类必须能够替换其基类,保持系统的稳定性</li>
<li><strong>接口隔离原则</strong>:使用多个专门的接口,而不是使用单一的总接口</li>
<li><strong>依赖倒置原则</strong>:依赖于抽象而非具体实现,降低模块间耦合</li>
</ul>
</div>
</section>
<!-- 原理分析 -->
<section id="principle-analysis">
<h2 class="section-title">原理分析</h2>
<div class="content">
<h3 class="subsection-title">权限控制原理</h3>
<p>RuoYi-Vue-Plus 采用 Sa-Token 作为权限控制框架,其核心原理如下:</p>
<div class="code-block">
<div class="code-header">
<span class="code-language">Java</span>
</div>
<pre>/**
* 权限服务接口
*/
public interface PermissionService {
/**
* 获取角色数据权限
*
* <span class="mention-invalid">@param</span> roleId 角色ID
* <span class="mention-invalid">@return</span> 数据权限范围
*/
Set<Long> getRoleDataScope(Long roleId);
/**
* 获取菜单数据权限
*
* <span class="mention-invalid">@param</span> userId 用户ID
* <span class="mention-invalid">@return</span> 菜单权限标识集合
*/
Set<String> getMenuPermission(Long userId);
}</pre>
</div>
<p>权限控制的核心是通过 PermissionService 接口实现的,该接口定义了获取角色数据权限和菜单权限的方法。系统在用户登录时,会加载用户的权限信息并缓存,后续请求通过拦截器进行权限校验。</p>
<h3 class="subsection-title">多租户实现原理</h3>
<p>多租户是 RuoYi-Vue-Plus 的核心特性之一,其实现原理如下:</p>
<div class="code-block">
<div class="code-header">
<span class="code-language">Java</span>
</div>
<pre>/**
* 多租户拦截器
*/
public class TenantInterceptor implements InnerInterceptor {
<span class="mention-invalid">@Override</span>
public void beforeQuery(Executor executor, MappedStatement ms, Object parameter,
RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
// 获取租户ID
Long tenantId = TenantHelper.getTenantId();
if (tenantId == null) {
return;
}
// 修改SQL,添加租户条件
String originalSql = boundSql.getSql();
String newSql = originalSql + " AND tenant_id = " + tenantId;
ReflectUtil.setFieldValue(boundSql, "sql", newSql);
}
}</pre>
</div>
<p>多租户实现的核心是通过 Mybatis-Plus 的拦截器机制,在 SQL 执行前动态添加租户条件,实现数据隔离。系统通过 TenantHelper 工具类获取当前租户 ID,并在 SQL 中自动添加租户条件,确保每个租户只能访问自己的数据。</p>
<h3 class="subsection-title">工作流引擎原理</h3>
<p>RuoYi-Vue-Plus 集成了 Warm-Flow 工作流引擎,其核心原理如下:</p>
<div class="code-block">
<div class="code-header">
<span class="code-language">Java</span>
</div>
<pre>/**
* 工作流服务接口
*/
public interface IFlwCommonService {
/**
* 构建工作流用户
*
* <span class="mention-invalid">@param</span> userId 用户ID
* <span class="mention-invalid">@return</span> 工作流用户对象
*/
User buildWorkFlowUser(Long userId);
/**
* 启动流程
*
* <span class="mention-invalid">@param</span> processKey 流程定义键
* <span class="mention-invalid">@param</span> businessKey 业务键
* <span class="mention-invalid">@param</span> variables 变量
* <span class="mention-invalid">@return</span> 流程实例ID
*/
String startProcess(String processKey, String businessKey, Map<String, Object> variables);
}</pre>
</div>
<p>工作流引擎的核心是通过流程定义、流程实例和任务三个核心概念实现的。流程定义定义了业务流程的结构和规则,流程实例是流程定义的一次执行,任务是流程实例中的具体工作项。系统通过工作流服务接口提供流程启动、任务处理、流程查询等功能。</p>
<h3 class="subsection-title">插件化设计原理</h3>
<p>RuoYi-Vue-Plus 采用插件化设计,其核心原理如下:</p>
<div class="code-block">
<div class="code-header">
<span class="code-language">Java</span>
</div>
<pre>/**
* 插件接口
*/
public interface Plugin {
/**
* 插件名称
*/
String getName();
/**
* 插件版本
*/
String getVersion();
/**
* 插件描述
*/
String getDescription();
/**
* 初始化插件
*/
void initialize();
/**
* 启动插件
*/
void start();
/**
* 停止插件
*/
void stop();
}</pre>
</div>
<p>插件化设计的核心是通过定义统一的插件接口,实现功能的动态加载和卸载。系统通过插件管理器负责插件的加载、初始化、启动和停止,实现功能的动态扩展。插件可以独立开发和部署,不影响系统的稳定性。</p>
</div>
</section>
<!-- 代码示例 -->
<section id="code-examples">
<h2 class="section-title">代码示例</h2>
<div class="content">
<h3 class="subsection-title">配置示例</h3>
<div class="code-block">
<div class="code-header">
<span class="code-language">YAML</span>
</div>
<pre># 项目配置
ruoyi:
# 名称
name: RuoYi-Vue-Plus
# 版本
version: 5.3.0
# 版权年份
copyrightYear: 2023
# 实例演示开关
demoEnabled: true
# 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
profile: D:/ruoyi/uploadPath
# 获取ip地址开关
addressEnabled: false
# 验证码类型 math 数组计算 char 字符验证
captchaType: math
# 开发环境配置
server:
# 服务器的HTTP端口,默认为8080
port: 8080
servlet:
# 应用的访问路径
context-path: /
tomcat:
# tomcat的URI编码
uri-encoding: UTF-8
# tomcat最大线程数,默认为200
max-threads: 800
# Tomcat启动初始化的线程数,默认值25
min-spare-threads: 30</pre>
</div>
<h3 class="subsection-title">核心类示例</h3>
<div class="code-block">
<div class="code-header">
<span class="code-language">Java</span>
</div>
<pre>/**
* 登录服务实现
*/
<span class="mention-invalid">@Service</span>
public class SysLoginService {
<span class="mention-invalid">@Autowired</span>
private SysUserMapper userMapper;
<span class="mention-invalid">@Autowired</span>
private SysPermissionService permissionService;
/**
* 登录验证
*
* <span class="mention-invalid">@param</span> username 用户名
* <span class="mention-invalid">@param</span> password 密码
* <span class="mention-invalid">@param</span> code 验证码
* <span class="mention-invalid">@param</span> uuid 唯一标识
* <span class="mention-invalid">@return</span> 结果
*/
public String login(String username, String password, String code, String uuid) {
// 验证码校验
validateCaptcha(username, code, uuid);
// 登录前置校验
loginPreCheck(username, password);
// 用户验证
SysUser user = loadUserByUsername(username);
if (!SecurityUtils.matchesPassword(password, user.getPassword())) {
throw new UserPasswordNotMatchException();
}
if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
throw new UserBlockedException();
}
// 生成token
return createToken(user);
}
/**
* 创建令牌
*/
public String createToken(SysUser user) {
// 生成token
String token = IdUtil.fastSimpleUUID();
// 缓存用户信息
LoginUser loginUser = new LoginUser();
loginUser.setUserId(user.getUserId());
loginUser.setUsername(user.getUserName());
loginUser.setPermission(permissionService.getMenuPermission(user.getUserId()));
// 缓存登录用户到Redis
RedisUtils.setCacheObject(CacheConstants.LOGIN_TOKEN_KEY + token, loginUser,
CacheConstants.LOGIN_TOKEN_TTL, TimeUnit.MINUTES);
return token;
}
}</pre>
</div>
<h3 class="subsection-title">接口设计示例</h3>
<div class="code-block">
<div class="code-header">
<span class="code-language">Java</span>
</div>
<pre>/**
* 用户管理接口
*/
<span class="mention-invalid">@RestController</span>
<span class="mention-invalid">@RequestMapping</span>("/system/user")
public class SysUserController extends BaseController {
<span class="mention-invalid">@Autowired</span>
private ISysUserService userService;
/**
* 获取用户列表
*/
<span class="mention-invalid">@SaCheckPermission</span>("system:user:list")
<span class="mention-invalid">@GetMapping</span>("/list")
public TableDataInfo<SysUserVo> list(SysUserBo user, PageQuery pageQuery) {
return userService.selectPageUserList(user, pageQuery);
}
/**
* 根据用户编号获取详细信息
*/
<span class="mention-invalid">@SaCheckPermission</span>("system:user:query")
<span class="mention-invalid">@GetMapping</span>("/{userId}")
public R<SysUserVo> getInfo(<span class="mention-invalid">@PathVariable</span> Long userId) {
userService.checkUserDataScope(userId);
return R.ok(userService.selectUserById(userId));
}
/**
* 新增用户
*/
<span class="mention-invalid">@SaCheckPermission</span>("system:user:add")
<span class="mention-invalid">@Log</span>(title = "用户管理", businessType = BusinessType.INSERT)
<span class="mention-invalid">@PostMapping</span>
public R<Void> add(<span class="mention-invalid">@Validated</span> <span class="mention-invalid">@RequestBody</span> SysUserBo user) {
if (!userService.checkUserNameUnique(user.getUserName())) {
return R.fail("新增用户'" + user.getUserName() + "'失败,登录账号已存在");
}
return toAjax(userService.insertUser(user));
}
/**
* 修改用户
*/
<span class="mention-invalid">@SaCheckPermission</span>("system:user:edit")
<span class="mention-invalid">@Log</span>(title = "用户管理", businessType = BusinessType.UPDATE)
<span class="mention-invalid">@PutMapping</span>
public R<Void> edit(<span class="mention-invalid">@Validated</span> <span class="mention-invalid">@RequestBody</span> SysUserBo user) {
userService.checkUserAllowed(user);
userService.checkUserDataScope(user.getUserId());
if (!userService.checkUserNameUnique(user.getUserName())) {
return R.fail("修改用户'" + user.getUserName() + "'失败,登录账号已存在");
}
return toAjax(userService.updateUser(user));
}
}</pre>
</div>
</div>
</section>
</div>
</body>
</html>
登录后可参与表态
讨论回复
0 条回复还没有人回复,快来发表你的看法吧!