📅 创建时间:2026-05-20
🏷️ 标签: Spring Boot 4 Apache Shiro MyBatis Thymeleaf 后台管理系统 代码生成 若依
📍 项目路径:E:\workSpace\RuoYi
🌐 官网:www.ruoyi.vip
RuoYi(若依)是国内最流行的开源 Java 后台管理系统之一,基于 Spring Boot + Shiro + MyBatis + Thymeleaf 构建,提供完整的权限管理、代码生成、系统监控等企业级功能。v4.8.3 版本升级至 Spring Boot 4.0.3 + Java 17,采用 Jakarta EE 命名空间。
RuoYi-Cloud。
| 模块 | 核心类 | 职责 |
|---|---|---|
ruoyi-common | BaseEntity, BaseController, AjaxResult, TableDataInfo | 公共基类、响应封装、分页集成、工具类、自定义注解 |
ruoyi-system | SysUser, SysRole, SysMenu, SysDept, SysPost, SysConfig, SysDict* | 系统管理领域模型 + Service + Mapper(21 个 XML 映射文件) |
ruoyi-framework | ShiroConfig, UserRealm, LogAspect, DataScopeAspect, AsyncManager | 安全认证、AOP 切面、数据源路由、异步任务、公共服务 |
ruoyi-quartz | SysJob, SysJobLog, QuartzJobFactory | Quartz 定时任务调度与日志 |
ruoyi-generator | GenTable, GenTableColumn, GenTableServiceImpl | 代码生成:读取 information_schema,Velocity 渲染模板 |
ruoyi-admin | RuoYiApplication, 所有 Controller | 应用入口、Web 层、Thymeleaf 模板、静态资源 |
POST /logincaptchaValidate 过滤器先校验验证码UserRealm.doGetAuthenticationInfo() 委托给 SysLoginService.login()UserRealm.doGetAuthorizationInfo() 加载当前用户的角色集合和菜单权限集合,返回 SimpleAuthorizationInfo,Shiro 据此做访问控制。
| URL 模式 | 过滤器 | 说明 |
|---|---|---|
/favicon.ico, /css/**, /js/**, /img/** 等 | anon | 静态资源,匿名可访问 |
/captcha/captchaImage** | anon | 验证码图片,匿名可访问 |
/login | anon, captchaValidate | 登录页,需验证码校验 |
/register | anon, captchaValidate | 注册页,需验证码校验 |
/logout | logout | 登出处理 |
/** | user, kickout, onlineSession, syncOnlineSession, csrfValidateFilter | 所有其他页面:认证 + 踢人 + 在线会话 + 同步 + CSRF |
| 过滤器 | 功能 |
|---|---|
captchaValidate | 校验验证码正确性 |
onlineSession | 检查 Session 状态(过期/强制下线) |
syncOnlineSession | 异步同步 Session 属性变更到数据库 |
kickout | 同用户最大并发会话控制(EhCache 实现) |
csrfValidateFilter | CSRF 防护(默认禁用) |
logout | 自定义登出逻辑 |
RuoYi 将 Shiro Session 持久化到 sys_user_online 数据库表,实现:
| 配置项 | 值 | 说明 |
|---|---|---|
| Session 超时 | 30 分钟 | 过期自动清除 |
| 数据库同步周期 | 1 分钟 | Session 属性变更延迟写入 DB |
| 验证间隔 | 10 分钟 | 定时检查过期 Session |
| 最大并发会话 | -1(无限制) | 可配置,超出后按策略踢人 |
| Remember Me | AES-128 Cookie | 30 天有效期,HttpOnly |
SysPasswordService)loginRecordCache 跟踪)/system/*, /monitor/*, /tool/*SqlUtil 工具类 + Druid WallFilterRuoYi 采用经典的 服务端渲染 模式,没有独立的前端框架(无 Vue/React/Angular)。前端由 Thymeleaf 模板 + jQuery + Bootstrap 构成,适合后台管理系统的快速开发。
ruoyi-admin/src/main/resources/
├── templates/ # Thymeleaf 模板
│ ├── system/ # 系统管理页面
│ │ ├── user/ # 用户管理
│ │ ├── role/ # 角色管理
│ │ ├── menu/ # 菜单管理
│ │ ├── dept/ # 部门管理
│ │ ├── dict/ # 字典管理
│ │ ├── config/ # 参数设置
│ │ ├── notice/ # 通知公告
│ │ ├── login.html # 登录页
│ │ ├── register.html # 注册页
│ │ └── index.html # 主框架页
│ ├── monitor/ # 监控页面
│ │ ├── cache/ # 缓存监控
│ │ ├── server/ # 服务器监控
│ │ ├── online/ # 在线用户
│ │ └── operlog/, logininfor/ # 日志管理
│ ├── tool/ # 工具页面
│ │ ├── gen/ # 代码生成
│ │ └── build/ # 表单构建
│ ├── demo/ # 演示页面
│ └── error/ # 错误页面 (404, 500)
└── static/
├── css/ # 样式表
├── js/ # jQuery + Bootstrap + 插件
├── ajax/ # AJAX 工具函数
├── ruoyi/ # 若依自定义 JS/CSS
├── i18n/ # 国际化资源
├── img/, fonts/ # 图片/字体
└── file/ # 上传文件目录
通过 thymeleaf-extras-shiro 在模板中直接做权限判断:
<!-- 有 user:list 权限才显示按钮 -->
<shiro:hasPermission name="system:user:add">
<button class="btn btn-primary">新增用户</button>
</shiro:hasPermission>
<!-- 有 admin 角色才显示 -->
<shiro:hasRole name="admin">
<div>管理员专属内容</div>
</shiro:hasRole>
| 技术 | 用途 |
|---|---|
| jQuery | DOM 操作、AJAX 请求、事件处理 |
| Bootstrap | 响应式布局、组件(表格、表单、模态框) |
| Bootstrap Table | 数据表格(分页、排序、搜索、导出) |
| Summernote | 富文本编辑器 |
| Bootstrap Select | 下拉选择组件 |
| iCheck | 美化复选框/单选框 |
所有 Controller 继承 BaseController,获得统一的分页和响应处理能力:
| 方法 | 功能 |
|---|---|
startPage() | 启动 PageHelper 分页拦截,下一个 MyBatis 查询自动添加 LIMIT |
getDataTable(List) | 将列表封装为 TableDataInfo(含 total、rows、code、msg) |
toAjax(boolean) | 将布尔结果封装为 AjaxResult(成功/失败 + 提示信息) |
@InitBinder | 日期类型自动转换 |
ShiroUtils.getSysUser() | 获取当前登录用户信息 |
// AjaxResult - 操作响应
{
"code": 0, // 0=成功, 500=失败
"msg": "操作成功", // 提示信息
"data": { ... } // 可选的业务数据
}
// TableDataInfo - 分页响应
{
"code": 0,
"msg": "查询成功",
"rows": [ ... ], // 数据列表
"total": 100 // 总记录数
}
@DataScope 注解 + DataScopeAspect 实现行级数据安全:
@DataScope(deptAlias = "d", userAlias = "u")
public List<SysUser> selectUserList(SysUser user) {
return mapper.selectUserList(user);
}
// 自动追加: AND d.dept_id IN (SELECT dept_id FROM sys_role_dept WHERE role_id = ...)
通过 @DataSource 注解 + DataSourceAspect AOP 实现声明式数据源切换:
@DataSource(value = DataSourceType.SLAVE)
public List<SysUser> selectUserListFromSlave(SysUser user) {
return mapper.selectUserList(user);
}
底层使用 DynamicDataSource(继承 AbstractRoutingDataSource)+ ThreadLocal 实现运行时切换。从库默认禁用。
| 模块 | Mapper 数量 | 核心 Mapper |
|---|---|---|
ruoyi-system | 21 个 XML | SysUserMapper, SysRoleMapper, SysMenuMapper, SysDeptMapper, SysConfigMapper, SysDictDataMapper, SysLogininforMapper, SysOperLogMapper ... |
ruoyi-quartz | 2 个 XML | SysJobMapper, SysJobLogMapper |
ruoyi-generator | 2 个 XML | GenTableMapper, GenTableColumnMapper |
配置: 二级缓存启用,useGeneratedKeys,SLF4J 日志,PageHelper MySQL 方言分页。
所有 Controller 位于 ruoyi-admin/src/main/java/com/ruoyi/web/controller/,按功能域组织:
/common)| Controller | 路由 | 功能 |
|---|---|---|
CommonController | /common/download, /common/upload, /common/uploads | 文件上传/下载 |
/system)| Controller | 路由 | 功能 |
|---|---|---|
SysLoginController | /login | 登录页面与登录提交 |
SysIndexController | /index | 主框架页面 |
SysCaptchaController | /captcha/captchaImage | 验证码图片生成 (Kaptcha) |
SysRegisterController | /register | 用户注册 |
SysUserController | /system/user/** | 用户 CRUD + 重置密码 + 分配角色 |
SysRoleController | /system/role/** | 角色 CRUD + 菜单权限分配 |
SysMenuController | /system/menu/** | 菜单/权限树 CRUD |
SysDeptController | /system/dept/** | 部门树 CRUD |
SysPostController | /system/post/** | 岗位 CRUD |
SysDictTypeController | /system/dict/type/** | 字典类型 CRUD |
SysDictDataController | /system/dict/data/** | 字典数据 CRUD |
SysConfigController | /system/config/** | 系统参数配置 |
SysNoticeController | /system/notice/** | 通知公告 CRUD |
SysProfileController | /system/user/profile/** | 个人信息修改/密码修改 |
/monitor)| Controller | 路由 | 功能 |
|---|---|---|
CacheController | /monitor/cache/** | EhCache 缓存查看/清除 |
DruidController | /monitor/druid/** | Druid 监控页重定向 |
ServerController | /monitor/server/** | 服务器信息 (CPU/内存/磁盘 via oshi) |
SysLogininforController | /monitor/logininfor/** | 登录日志查询/删除/导出 |
SysOperlogController | /monitor/operlog/** | 操作日志查询/删除/导出 |
SysUserOnlineController | /monitor/online/** | 在线用户列表/强退 |
/tool)| Controller | 路由 | 功能 |
|---|---|---|
GenController | /tool/gen/** | 代码生成(导入表、预览、生成下载) |
SwaggerController | /tool/swagger | Swagger UI 重定向 |
BuildController | /tool/build/** | 表单构建器 |
| 模板 | 生成物 | 说明 |
|---|---|---|
domain.java.vm | 实体类 | 继承 BaseEntity,@Excel 注解 |
sub-domain.java.vm | 子表实体 | 主从表的从表实体 |
controller.java.vm | Controller | CRUD + 分页 + 导出 + 权限注解 |
mapper.java.vm | Mapper 接口 | MyBatis Mapper Interface |
mapper.xml.vm | Mapper XML | SQL 映射(select/insert/update/delete) |
service.java.vm | Service 接口 | 业务方法定义 |
serviceImpl.java.vm | Service 实现 | 业务逻辑 + 事务注解 |
list.html.vm | 列表页 | Bootstrap Table + 搜索表单 |
add.html.vm | 新增页 | 表单页面 |
edit.html.vm | 编辑页 | 表单页面(回显数据) |
view.html.vm | 详情页 | 只读展示 |
tree.html.vm | 树形选择 | 关联字典/树表时使用 |
list-tree.html.vm | 树表列表 | 左树右表布局 |
sql.vm | SQL 脚本 | DDL + 菜单插入 SQL |
RuoYi 大量使用自定义注解 + AOP 切面实现横切关注点的解耦,是其架构的核心设计亮点:
| 注解 | 切面 | 功能 | 实现原理 |
|---|---|---|---|
@Log |
LogAspect |
操作日志自动记录 | 拦截 Controller 方法,记录操作人、IP、方法名、参数、耗时,异步写入 sys_oper_log 表 |
@DataScope |
DataScopeAspect |
行级数据权限过滤 | 根据用户部门/角色,向 MyBatis 参数注入 SQL WHERE 条件 |
@DataSource |
DataSourceAspect |
多数据源声明式切换 | 方法执行前设置 ThreadLocal 数据源标识,DynamicDataSource 据此路由 |
@RepeatSubmit |
重复提交切面 | 防止表单重复提交 | 基于请求参数 Hash + 时间窗口判断 |
@PermissionsAspect |
权限校验切面 | 方法级权限控制 | 通过 Shiro SecurityUtils.getSubject().isPermitted() 校验 |
AsyncManager + AsyncFactory 模式:
AsyncManager:基于 ScheduledExecutorService 的单线程异步任务管理器AsyncFactory:工厂方法创建具体任务(记录登录日志、清理过期 Session 等)// 使用示例
AsyncManager.me().execute(AsyncFactory.recordLogininfor(
username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")
));
| 注解 | 所在模块 | 用途 |
|---|---|---|
@Log | ruoyi-common | 操作日志记录 |
@DataScope | ruoyi-common | 数据权限过滤 |
@DataSource | ruoyi-common | 多数据源切换 |
@Excel | ruoyi-common | Excel 导入导出列映射 |
@RepeatSubmit | ruoyi-common | 防重复提交 |
@Sensitive | ruoyi-common | 数据脱敏(手机号/身份证等) |
@Anonymous | ruoyi-common | 匿名可访问端点(免认证) |
| 技术 | 版本 | 用途 |
|---|---|---|
| Java | 17 | 运行时 (Jakarta EE 命名空间) |
| Spring Boot | 4.0.3 | 应用框架 (WebMVC) |
| Apache Shiro | 2.1.0 (jakarta) | 认证、授权、会话管理 |
| MyBatis | 4.0.1 | ORM / SQL 映射 |
| Druid | 1.2.28 | 数据库连接池 + SQL 监控 |
| Thymeleaf | - | 服务端 HTML 模板引擎 |
| PageHelper | 2.1.1 | MyBatis 分页插件 |
| EhCache | - | 本地缓存(Shiro 缓存后端) |
| Quartz | - | 定时任务调度 |
| Apache Velocity | 2.3 | 代码生成模板引擎 |
| Kaptcha | 2.3.3 | 验证码图片生成 |
| Springdoc OpenAPI | 3.0.2 | Swagger UI / API 文档 |
| MySQL | 8.x | 关系数据库 |
| Apache POI | 4.1.2 | Excel 导入导出 |
| oshi-core | 6.10.0 | 服务器硬件监控(CPU/内存/磁盘) |
| YAUAA | - | User-Agent 解析(浏览器/OS 识别) |
| FastJSON | 1.2.83 | JSON 序列化 |
| thymeleaf-extras-shiro | - | Thymeleaf 中的 Shiro 权限标签 |
| 方式 | 说明 |
|---|---|
| 可执行 JAR | spring-boot-maven-plugin 打包,java -jar ruoyi-admin.jar 运行 |
| WAR 部署 | maven-war-plugin 打 WAR,部署到外部 Tomcat |
| Linux 脚本 | ry.sh start|stop|restart|status |
| Windows 脚本 | ry.bat 交互式菜单(启动/停止/重启/状态) |
-Xms512m -Xmx1024m # 堆内存 512M~1G
-XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m # 元空间
-XX:+HeapDumpOnOutOfMemoryError # OOM 时 dump
-XX:+UseParallelGC -XX:+UseParallelOldGC # 并行 GC
-Duser.timezone=Asia/Shanghai # 时区设置
| 监控项 | 实现 | 入口 |
|---|---|---|
| 服务器状态 | oshi-core (CPU/内存/JVM/磁盘) | /monitor/server |
| SQL 监控 | Druid StatView (慢 SQL >1s) | /druid |
| 在线用户 | Session-in-DB 查询 | /monitor/online |
| 缓存监控 | EhCache 管理 UI | /monitor/cache |
| 操作日志 | @Log + LogAspect → sys_oper_log | /monitor/operlog |
| 登录日志 | AsyncFactory → sys_logininfor | /monitor/logininfor |
| API 文档 | Springdoc OpenAPI 3 | /swagger-ui.html |
| 缓存名 | 最大条目 | 过期策略 | 用途 |
|---|---|---|---|
loginRecordCache | 2000 | 空闲 10 分钟 | 密码错误次数跟踪(锁定机制) |
sys-userCache | 10000 | 永不过期 | 活跃用户缓存 |
sys-authCache | 10000 | LRU 淘汰 | 用户授权信息(角色/权限) |
sys-config | 1000 | 永久 | 系统配置参数 |
sys-dict | 1000 | 永久 | 字典数据 |
shiro-activeSessionCache | 10000 | 永不过期 | Shiro 活跃 Session |
RuoYi 是单体应用,但通过 Maven 多模块实现了清晰的代码分层:common → system → framework → admin。每层职责明确,依赖单向,体现了"单体不等于混乱"的理念。
@Log、@DataScope、@DataSource、@RepeatSubmit 等注解+切面的组合,让业务代码只需关注核心逻辑,横切关注点完全解耦。这是 RuoYi 最值得学习的设计模式。
将 Session 持久化到数据库,虽然性能不如 Redis,但实现简单、支持跨实例共享、且天然支持在线用户管理。对于中小型项目,这是务实的选择。
不是简单的模板脚手架,而是读取真实数据库元数据,生成的代码完全符合项目规范(BaseEntity、@Excel、PageHelper、Thymeleaf 模板),可直接生产使用。
@DataScope 通过 AOP 自动向 SQL 注入过滤条件,实现行级数据安全。这种"声明式数据权限"比在每个查询中手动加条件优雅得多。
Thymeleaf SSR + jQuery + Bootstrap 的组合虽然"传统",但对于后台管理系统来说开发效率极高:不需要前端构建工具、不需要 API 文档、前后端一体化部署。
ShiroConfig 中自定义过滤器链的配置细节DataScopeAspect 如何动态向 MyBatis 注入 SQL 条件OnlineSessionDAO 的 Session 持久化实现KickoutSessionFilter 的并发会话控制算法AsyncManager 的异步任务调度机制| 维度 | RuoYi (若依) | Mall-Swarm (商城) |
|---|---|---|
| 架构风格 | 单体 (Monolith) | 微服务 (Microservices) |
| 安全框架 | Apache Shiro | Sa-Token |
| 前端方案 | Thymeleaf SSR | UniApp (Vue 2) |
| 配置管理 | application.yml | Nacos Config Center |
| 会话管理 | Shiro Session-in-DB | Redis Token |
| 适用场景 | 后台管理系统 | C 端电商应用 |
| 部署复杂度 | 单 JAR + MySQL | 多服务 + 中间件集群 |
📅 生成时间:2026-05-20 | 📁 项目路径:E:\workSpace\RuoYi
🤖 由 Claude Code 自动生成 | 📚 知识库:C:\Users\sunjie\Documents\我的知识库\技术项目知识库