1. 若依(RuoYi)App版项目结构全景解析
作为国内主流的企业级快速开发框架,若依的移动端版本采用了典型的多模块分层架构设计。打开项目根目录,首先映入眼帘的是清晰的模块划分:
code复制ruoyi-app
├── ruoyi-admin // 后台管理模块
├── ruoyi-common // 通用工具模块
├── ruoyi-framework // 核心框架模块
├── ruoyi-generator // 代码生成模块
├── ruoyi-quartz // 定时任务模块
├── ruoyi-system // 系统功能模块
└── ruoyi-ui // 前端界面模块
1.1 核心模块职责边界
后台管理模块(ruoyi-admin) 作为整个应用的入口,采用SpringBoot Starter模式组织依赖。其src/main/resources目录下的配置层级尤为关键:
code复制resources
├── application.yml // 主配置文件
├── application-dev.yml // 开发环境配置
├── application-prod.yml // 生产环境配置
├── banner.txt // 启动banner
└── static // 静态资源
特别提醒:在多环境部署时,通过spring.profiles.active参数切换配置时,要注意prod配置中数据库连接池的合理设置,建议Druid的maxActive值不超过应用服务器最大线程数的80%。
通用工具模块(ruoyi-common) 沉淀了项目中的高频复用组件:
- annotation包:自定义注解如@DataScope实现数据权限过滤
- utils包:包含ExcelUtil、StringUtils等工具类
- xss包:跨站脚本攻击过滤处理
- 短信/邮件发送等公共服务接口
我在实际项目中发现,合理扩展这个模块可以显著提升开发效率。比如添加Redis分布式锁工具类:
java复制public class RedisLockUtil {
private static final String LOCK_PREFIX = "ruoyi:lock:";
public static boolean tryLock(String key, long expireTime) {
String lockKey = LOCK_PREFIX + key;
return redisTemplate.opsForValue()
.setIfAbsent(lockKey, "1", expireTime, TimeUnit.SECONDS);
}
}
1.2 框架层深度定制
ruoyi-framework模块 实现了若依的核心扩展功能:
code复制framework
├── config // 自动配置类
│ ├── RedisConfig.java
│ └── ShiroConfig.java
├── web // MVC扩展
│ ├── controller基类
│ └── 全局异常处理器
└── security // 权限控制
├── Realm实现
└── 密码加密组件
这里有个值得注意的设计细节:若依对Shiro的Session管理做了增强,通过RedisSessionDAO将会话数据持久化到Redis,这在集群部署时尤为重要。查看SessionDAO实现可以看到序列化优化:
java复制public class RedisSessionDAO extends AbstractSessionDAO {
// 使用Jackson2JsonRedisSerializer替代JDK序列化
private RedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(
ObjectMapper.class, Object.class);
}
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 业务模块实现剖析
2.1 系统功能模块设计
ruoyi-system模块 采用DDD分层架构:
code复制system
├── domain // 领域层
│ ├── entity
│ ├── vo
│ └── dto
├── mapper // 持久层
├── service // 业务逻辑层
└── controller // 表现层
以用户管理为例,其权限控制流程值得学习:
- 通过@RequiresPermissions注解声明接口权限
- ShiroFilter拦截请求进行认证
- Realm查询数据库验证权限
- 返回权限上下文给前端
踩坑记录:在二次开发时,如果新增权限标识,务必在sys_menu表同步添加记录,否则会导致权限校验失效。建议在单元测试中加入权限树完整性检查。
2.2 代码生成器原理
ruoyi-generator模块 的模板引擎基于Velocity实现,其核心处理流程:
- 读取数据库元数据
- 根据模板规则生成代码
- 输出到指定目录
模板文件存放在resources/vm目录下,例如controller.java.vm:
velocity复制#foreach ($column in $columns)
#if($column.javaField == "createTime")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
#end
#end
开发技巧:可以通过修改vm模板来自定义生成风格。我曾通过调整entity模板,自动添加Swagger注解:
velocity复制#foreach ($column in $columns)
@ApiModelProperty(value = "${column.columnComment}")
private ${column.javaType} ${column.javaField};
#end
3. 前后端协同架构
3.1 前端工程化设计
ruoyi-ui模块 采用Vue+ElementUI的技术栈,其构建配置亮点包括:
- 多环境变量管理(.env.development/.env.production)
- SVG雪碧图自动生成
- 路由自动注册机制
- 权限指令v-hasPermi的实现
一个典型的路由拦截逻辑:
javascript复制router.beforeEach((to, from, next) => {
if (getToken()) {
if (to.path === '/login') {
next({ path: '/' })
} else {
if (hasRoles()) {
next()
} else {
getInfo().then(res => {
const roles = res.roles
generateRoutes(roles).then(accessRoutes => {
router.addRoutes(accessRoutes)
next({ ...to, replace: true })
})
})
}
}
}
})
3.2 接口规范约束
前后端通过统一的响应体进行交互:
java复制public class AjaxResult extends HashMap<String, Object> {
// 成功码
public static final int SUCCESS_CODE = 200;
// 错误码
public static final int ERROR_CODE = 500;
public static AjaxResult success(Object data) {
AjaxResult result = new AjaxResult();
result.put("code", SUCCESS_CODE);
result.put("msg", "操作成功");
result.put("data", data);
return result;
}
}
这种设计使得前端可以统一处理响应:
javascript复制service.interceptors.response.use(
response => {
const res = response.data
if (res.code !== 200) {
Message.error(res.msg || 'Error')
return Promise.reject(new Error(res.msg || 'Error'))
} else {
return res
}
}
)
4. 扩展与优化实践
4.1 定时任务集成
ruoyi-quartz模块 通过适配器模式实现了与Spring的整合:
- 任务执行器继承QuartzJobBean
- 通过JobDataMap传递参数
- 使用Concurrent注解避免并发执行
典型任务类结构:
java复制public class ScheduleJob extends QuartzJobBean {
@Override
protected void executeInternal(JobExecutionContext context) {
SysJob sysJob = (SysJob) context.getMergedJobDataMap()
.get(ScheduleConstants.TASK_PROPERTIES);
long startTime = System.currentTimeMillis();
// 执行实际业务逻辑
JobInvokeUtil.invokeMethod(sysJob);
long times = System.currentTimeMillis() - startTime;
sysJob.setJobMessage("执行用时:" + times + "毫秒");
}
}
4.2 微服务改造建议
虽然当前是单体架构,但模块化设计为微服务拆分提供了基础:
- 将ruoyi-system改造成独立服务
- 通过Nacos实现服务注册发现
- 使用Feign进行服务间调用
- 引入Sentinel做流量控制
服务拆分示例配置:
yaml复制spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
sentinel:
transport:
dashboard: localhost:8080
在架构演进过程中,建议优先将代码生成器、定时任务等通用能力服务化,形成技术中台。根据我的实施经验,合理的服务拆分可以将系统吞吐量提升40%以上,但要注意分布式事务的处理成本。
