Loading...
正在加载...
请稍候

RuoYi-Vue-Plus 项目详解:架构、原理与设计思想

✨步子哥 (steper) 2025年10月13日 04:41
<!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&lt;Long&gt; getRoleDataScope(Long roleId); /** * 获取菜单数据权限 * * <span class="mention-invalid">@param</span> userId 用户ID * <span class="mention-invalid">@return</span> 菜单权限标识集合 */ Set&lt;String&gt; 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&lt;String, Object&gt; 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&lt;SysUserVo&gt; 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&lt;SysUserVo&gt; 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&lt;Void&gt; 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&lt;Void&gt; 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 条回复

还没有人回复,快来发表你的看法吧!