mirror of
https://github.com/dromara/RuoYi-Vue-Plus.git
synced 2025-09-27 05:36:41 +08:00
840 lines
22 KiB
Markdown
840 lines
22 KiB
Markdown
# RuoYi-Vue-Plus项目分析报告
|
||
|
||
## 1. 项目概述
|
||
|
||
RuoYi-Vue-Plus是在RuoYi-Vue基础上进行重构升级的开源项目,它专为分布式集群与多租户场景设计,采用插件化和扩展包的结构形式,极大提高了系统的解耦程度和扩展性。项目使用Spring Boot 3.4、JDK 17/21,基于Vue3+TS+ElementPlus重写前端,并使用Undertow替代Tomcat作为Web容器。
|
||
|
||
### 1.1 项目特点
|
||
|
||
- 采用插件化+扩展包形式,结构解耦,易于扩展
|
||
- 严格遵守Alibaba规范,代码格式统一
|
||
- 支持多种数据库(MySQL、Oracle、PostgreSQL、SQLServer等)
|
||
- 支持多租户架构
|
||
- 前端使用Vue3+TS+ElementPlus
|
||
- 底层基于Redisson的分布式能力(分布式锁、限流等)
|
||
- 使用Sa-Token+JWT实现权限认证
|
||
- 使用Mybatis-Plus作为ORM框架
|
||
- 内置丰富的功能模块和实用工具
|
||
|
||
## 2. 项目架构
|
||
|
||
### 2.1 整体架构
|
||
|
||
RuoYi-Vue-Plus采用前后端分离的架构模式:
|
||
|
||
- 后端:Spring Boot 3.4 + MyBatis-Plus + Sa-Token
|
||
- 前端:Vue3 + TypeScript + ElementPlus
|
||
|
||
项目部署架构图:
|
||

|
||
|
||
### 2.2 目录结构
|
||
|
||
项目主要分为以下几个部分:
|
||
|
||
#### 2.2.1 后端结构
|
||
|
||
```
|
||
ruoyi-vue-plus
|
||
├── ruoyi-admin -- 启动模块,项目入口
|
||
├── ruoyi-common -- 通用模块,各种功能组件
|
||
│ ├── ruoyi-common-bom -- 依赖版本管理
|
||
│ ├── ruoyi-common-core -- 核心功能
|
||
│ ├── ruoyi-common-doc -- 接口文档
|
||
│ ├── ruoyi-common-encrypt -- 数据加解密
|
||
│ ├── ruoyi-common-excel -- Excel处理
|
||
│ ├── ruoyi-common-idempotent -- 幂等处理
|
||
│ ├── ruoyi-common-job -- 定时任务
|
||
│ ├── ruoyi-common-json -- JSON处理
|
||
│ ├── ruoyi-common-log -- 日志处理
|
||
│ ├── ruoyi-common-mail -- 邮件处理
|
||
│ ├── ruoyi-common-mybatis -- ORM配置
|
||
│ ├── ruoyi-common-oss -- 对象存储
|
||
│ ├── ruoyi-common-ratelimiter -- 限流处理
|
||
│ ├── ruoyi-common-redis -- Redis配置
|
||
│ ├── ruoyi-common-satoken -- 认证鉴权
|
||
│ ├── ruoyi-common-security -- 安全配置
|
||
│ ├── ruoyi-common-sensitive -- 数据脱敏
|
||
│ ├── ruoyi-common-sms -- 短信服务
|
||
│ ├── ruoyi-common-social -- 社交登录
|
||
│ ├── ruoyi-common-sse -- SSE推送
|
||
│ ├── ruoyi-common-tenant -- 多租户
|
||
│ ├── ruoyi-common-translation -- 数据翻译
|
||
│ ├── ruoyi-common-web -- Web功能
|
||
│ └── ruoyi-common-websocket -- WebSocket
|
||
├── ruoyi-extend -- 扩展模块
|
||
│ ├── ruoyi-monitor-admin -- 监控管理
|
||
│ └── ruoyi-snailjob-server -- 任务调度
|
||
├── ruoyi-modules -- 业务模块
|
||
│ ├── ruoyi-demo -- 示例模块
|
||
│ ├── ruoyi-generator -- 代码生成
|
||
│ ├── ruoyi-job -- 定时任务
|
||
│ ├── ruoyi-system -- 系统管理
|
||
│ └── ruoyi-workflow -- 工作流
|
||
└── ruoyi-plus-soybean -- 前端项目
|
||
```
|
||
|
||
#### 2.2.2 前端结构
|
||
|
||
```
|
||
ruoyi-plus-soybean
|
||
├── docs -- 文档
|
||
├── packages -- 功能包
|
||
├── public -- 静态资源
|
||
├── src -- 源代码目录
|
||
│ ├── assets -- 静态资源
|
||
│ ├── components -- 组件
|
||
│ ├── constants -- 常量
|
||
│ ├── enum -- 枚举
|
||
│ ├── hooks -- 钩子函数
|
||
│ ├── layouts -- 布局
|
||
│ ├── locales -- 国际化
|
||
│ ├── plugins -- 插件
|
||
│ ├── router -- 路由
|
||
│ ├── service -- 服务调用
|
||
│ ├── store -- 状态管理
|
||
│ ├── styles -- 样式
|
||
│ ├── theme -- 主题
|
||
│ ├── typings -- 类型定义
|
||
│ ├── utils -- 工具类
|
||
│ ├── views -- 视图
|
||
│ ├── App.vue -- 主组件
|
||
│ └── main.ts -- 入口文件
|
||
```
|
||
|
||
## 3. 功能模块
|
||
|
||
### 3.1 核心功能
|
||
|
||
#### 基础功能
|
||
- **多租户管理**:支持租户套餐、过期时间、用户数量等管理
|
||
- **用户权限**:用户、角色、部门、菜单权限管理
|
||
- **系统监控**:在线用户、操作日志、登录日志
|
||
- **系统管理**:参数设置、字典管理、附件管理
|
||
- **系统工具**:代码生成、表单设计、接口文档
|
||
|
||
#### 扩展功能
|
||
- **工作流**:支持复杂审批流程
|
||
- **在线构建器**:拖拽式表单生成
|
||
- **定时任务**:任务调度管理
|
||
- **系统接口**:API文档自动生成
|
||
- **服务监控**:监控系统资源和性能
|
||
- **缓存监控**:Redis监控
|
||
|
||
### 3.2 技术特性
|
||
|
||
- **数据权限**:基于Mybatis-Plus插件的无感式数据权限过滤
|
||
- **数据脱敏**:支持注解+Jackson方式的数据脱敏
|
||
- **数据加解密**:支持数据库字段级加解密
|
||
- **接口加密**:动态AES+RSA加密请求体
|
||
- **数据翻译**:注解+序列化期间自动翻译
|
||
- **多数据源**:支持动态数据源配置和切换
|
||
- **分布式锁**:基于Redisson的分布式锁
|
||
- **分布式任务调度**:基于SnailJob的分布式任务调度
|
||
- **文件存储**:支持MinIO和S3协议的对象存储
|
||
|
||
## 4. 代码规范
|
||
|
||
RuoYi-Vue-Plus项目严格遵循以下规范:
|
||
|
||
### 4.1 项目规范
|
||
|
||
- 严格遵守Alibaba编码规范
|
||
- 使用统一的代码格式化配置
|
||
- 采用插件化结构,功能模块独立封装
|
||
- 按职责分离不同类型的代码(控制器、服务、实体等)
|
||
|
||
### 4.2 编码规范
|
||
|
||
#### 后端规范
|
||
1. **命名规范**:
|
||
- 类名:大驼峰命名(如:UserController)
|
||
- 方法名/变量名:小驼峰命名(如:getUserInfo)
|
||
- 常量:全大写下划线分隔(如:MAX_COUNT)
|
||
|
||
2. **包结构**:
|
||
- controller:控制器
|
||
- service:服务层
|
||
- mapper:数据访问层
|
||
- domain:实体类(entity、vo、bo、dto等)
|
||
- util:工具类
|
||
|
||
3. **注释要求**:
|
||
- 类注释:说明类的用途
|
||
- 方法注释:说明方法功能、参数和返回值
|
||
- 关键代码注释:解释复杂逻辑
|
||
|
||
#### 前端规范
|
||
1. **命名规范**:
|
||
- 组件名:大驼峰命名(如:UserForm)
|
||
- 文件名:kebab-case(如:user-form.vue)
|
||
- 变量/方法:小驼峰命名(如:getUserInfo)
|
||
|
||
2. **目录结构**:
|
||
- components:组件
|
||
- views:页面
|
||
- api:接口定义
|
||
- utils:工具函数
|
||
- store:状态管理
|
||
|
||
3. **编码风格**:
|
||
- 使用TypeScript进行类型检查
|
||
- 组件使用组合式API (Composition API)
|
||
- 样式使用SCSS并遵循BEM规范
|
||
|
||
### 4.3 常见代码示例
|
||
|
||
#### 4.3.1 控制器规范示例
|
||
|
||
```java
|
||
/**
|
||
* 用户信息控制器
|
||
*
|
||
* @author ruoyi-vue-plus
|
||
*/
|
||
@RestController
|
||
@RequestMapping("/system/user")
|
||
public class SysUserController extends BaseController {
|
||
|
||
@Autowired
|
||
private ISysUserService userService;
|
||
|
||
/**
|
||
* 获取用户列表
|
||
*
|
||
* @param user 查询参数
|
||
* @return 用户列表
|
||
*/
|
||
@SaCheckPermission("system:user:list")
|
||
@GetMapping("/list")
|
||
public TableDataInfo<SysUserVo> list(SysUserBo user) {
|
||
startPage();
|
||
List<SysUserVo> list = userService.selectUserList(user);
|
||
return getDataTable(list);
|
||
}
|
||
|
||
/**
|
||
* 新增用户
|
||
*
|
||
* @param user 用户信息
|
||
* @return 结果
|
||
*/
|
||
@SaCheckPermission("system:user:add")
|
||
@Log(title = "用户管理", businessType = BusinessType.INSERT)
|
||
@PostMapping
|
||
public R<Void> add(@Validated @RequestBody SysUserBo user) {
|
||
return toAjax(userService.insertUser(user));
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 4.3.2 服务接口和实现规范示例
|
||
|
||
```java
|
||
/**
|
||
* 用户服务接口
|
||
*
|
||
* @author ruoyi-vue-plus
|
||
*/
|
||
public interface ISysUserService {
|
||
|
||
/**
|
||
* 查询用户列表
|
||
*
|
||
* @param user 查询参数
|
||
* @return 用户列表
|
||
*/
|
||
List<SysUserVo> selectUserList(SysUserBo user);
|
||
|
||
/**
|
||
* 新增用户
|
||
*
|
||
* @param user 用户信息
|
||
* @return 结果
|
||
*/
|
||
int insertUser(SysUserBo user);
|
||
}
|
||
|
||
/**
|
||
* 用户服务接口实现
|
||
*
|
||
* @author ruoyi-vue-plus
|
||
*/
|
||
@Service
|
||
public class SysUserServiceImpl implements ISysUserService {
|
||
|
||
@Autowired
|
||
private SysUserMapper userMapper;
|
||
|
||
/**
|
||
* 查询用户列表
|
||
*
|
||
* @param user 查询参数
|
||
* @return 用户列表
|
||
*/
|
||
@Override
|
||
public List<SysUserVo> selectUserList(SysUserBo user) {
|
||
return userMapper.selectUserList(user);
|
||
}
|
||
|
||
/**
|
||
* 新增用户
|
||
*
|
||
* @param user 用户信息
|
||
* @return 结果
|
||
*/
|
||
@Override
|
||
@Transactional(rollbackFor = Exception.class)
|
||
public int insertUser(SysUserBo user) {
|
||
// 业务逻辑实现
|
||
return userMapper.insert(user.toEntity());
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 4.3.3 实体类规范示例
|
||
|
||
```java
|
||
/**
|
||
* 用户实体类
|
||
*
|
||
* @author ruoyi-vue-plus
|
||
*/
|
||
@Data
|
||
@TableName("sys_user")
|
||
@KeySequence("sys_user_seq")
|
||
public class SysUser extends TenantEntity {
|
||
|
||
/**
|
||
* 用户ID
|
||
*/
|
||
@TableId(value = "user_id", type = IdType.ASSIGN_ID)
|
||
private Long userId;
|
||
|
||
/**
|
||
* 用户账号
|
||
*/
|
||
private String userName;
|
||
|
||
/**
|
||
* 用户昵称
|
||
*/
|
||
private String nickName;
|
||
|
||
/**
|
||
* 用户类型(sys_user系统用户)
|
||
*/
|
||
private String userType;
|
||
|
||
/**
|
||
* 手机号码
|
||
*/
|
||
@Sensitive(strategy = SensitiveStrategy.PHONE)
|
||
private String phonenumber;
|
||
|
||
/**
|
||
* 帐号状态(0正常 1停用)
|
||
*/
|
||
private String status;
|
||
}
|
||
```
|
||
|
||
#### 4.3.4 前端页面示例 (Vue3 + TS)
|
||
|
||
```typescript
|
||
<template>
|
||
<div class="app-container">
|
||
<!-- 搜索表单 -->
|
||
<el-form :model="queryParams" ref="queryFormRef" :inline="true">
|
||
<el-form-item label="用户名称" prop="userName">
|
||
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable />
|
||
</el-form-item>
|
||
<el-form-item label="手机号码" prop="phonenumber">
|
||
<el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable />
|
||
</el-form-item>
|
||
<el-form-item>
|
||
<el-button type="primary" @click="handleQuery">搜索</el-button>
|
||
<el-button @click="resetQuery">重置</el-button>
|
||
</el-form-item>
|
||
</el-form>
|
||
|
||
<!-- 操作按钮区域 -->
|
||
<el-row :gutter="10" class="mb8">
|
||
<el-col :span="1.5">
|
||
<el-button
|
||
type="primary"
|
||
plain
|
||
v-hasPermi="['system:user:add']"
|
||
@click="handleAdd"
|
||
>新增</el-button>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
<!-- 数据表格 -->
|
||
<el-table v-loading="loading" :data="userList">
|
||
<el-table-column label="用户编号" prop="userId" />
|
||
<el-table-column label="用户名称" prop="userName" :show-overflow-tooltip="true" />
|
||
<el-table-column label="用户昵称" prop="nickName" :show-overflow-tooltip="true" />
|
||
<el-table-column label="手机号码" prop="phonenumber" :show-overflow-tooltip="true" />
|
||
<el-table-column label="状态" prop="status">
|
||
<template #default="scope">
|
||
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||
<template #default="scope">
|
||
<el-button
|
||
type="text"
|
||
@click="handleUpdate(scope.row)"
|
||
v-hasPermi="['system:user:edit']"
|
||
>修改</el-button>
|
||
<el-button
|
||
type="text"
|
||
@click="handleDelete(scope.row)"
|
||
v-hasPermi="['system:user:remove']"
|
||
>删除</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
|
||
<!-- 分页 -->
|
||
<pagination
|
||
v-show="total > 0"
|
||
:total="total"
|
||
v-model:page="queryParams.pageNum"
|
||
v-model:limit="queryParams.pageSize"
|
||
@pagination="getList"
|
||
/>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, onMounted } from 'vue';
|
||
import { listUser, delUser } from '@/api/system/user';
|
||
|
||
// 定义数据
|
||
const loading = ref(false);
|
||
const total = ref(0);
|
||
const userList = ref([]);
|
||
const queryFormRef = ref<any>(null);
|
||
|
||
// 查询参数
|
||
const queryParams = ref({
|
||
pageNum: 1,
|
||
pageSize: 10,
|
||
userName: undefined,
|
||
phonenumber: undefined,
|
||
});
|
||
|
||
/** 查询用户列表 */
|
||
function getList() {
|
||
loading.value = true;
|
||
listUser(queryParams.value).then(response => {
|
||
userList.value = response.rows;
|
||
total.value = response.total;
|
||
loading.value = false;
|
||
});
|
||
}
|
||
|
||
/** 搜索按钮操作 */
|
||
function handleQuery() {
|
||
queryParams.value.pageNum = 1;
|
||
getList();
|
||
}
|
||
|
||
/** 重置按钮操作 */
|
||
function resetQuery() {
|
||
queryFormRef.value.resetFields();
|
||
handleQuery();
|
||
}
|
||
|
||
/** 新增按钮操作 */
|
||
function handleAdd() {
|
||
// 实现新增逻辑
|
||
}
|
||
|
||
/** 修改按钮操作 */
|
||
function handleUpdate(row) {
|
||
// 实现修改逻辑
|
||
}
|
||
|
||
/** 删除按钮操作 */
|
||
function handleDelete(row) {
|
||
// 实现删除逻辑
|
||
}
|
||
|
||
onMounted(() => {
|
||
getList();
|
||
});
|
||
</script>
|
||
```
|
||
|
||
## 5. 二次开发指南
|
||
|
||
### 5.1 开发环境准备
|
||
|
||
1. **基础环境**:
|
||
- JDK 17/21
|
||
- Maven 3.8+
|
||
- Node.js 16+
|
||
- MySQL 8.0+/Oracle/PostgreSQL/SQLServer
|
||
- Redis 5.0+
|
||
|
||
2. **IDE推荐**:
|
||
- IntelliJ IDEA(后端)
|
||
- VSCode(前端)
|
||
|
||
### 5.2 开发规范与原则
|
||
|
||
1. **遵循现有架构**:
|
||
- 保持与现有代码风格一致
|
||
- 保持模块的独立性和可插拔性
|
||
- 不随意修改核心模块代码
|
||
|
||
2. **扩展而非修改**:
|
||
- 通过扩展现有组件实现功能
|
||
- 避免直接修改框架核心代码
|
||
|
||
3. **注重代码质量**:
|
||
- 编写单元测试
|
||
- 遵循代码规范
|
||
- 注释完善
|
||
|
||
### 5.3 增加PMS模块实施步骤
|
||
|
||
以下是添加一个产品管理系统(PMS)模块的具体步骤:
|
||
|
||
#### 5.3.1 后端开发
|
||
|
||
1. **创建模块结构**:
|
||
```
|
||
ruoyi-modules
|
||
└── ruoyi-pms -- PMS模块
|
||
├── src/main/java/org/dromara/pms
|
||
│ ├── controller -- 控制器
|
||
│ ├── domain -- 实体类
|
||
│ │ ├── bo -- 业务对象
|
||
│ │ ├── entity -- 数据库实体
|
||
│ │ └── vo -- 视图对象
|
||
│ ├── mapper -- MyBatis接口
|
||
│ └── service -- 服务实现
|
||
└── src/main/resources
|
||
├── mapper -- MyBatis XML
|
||
└── i18n -- 国际化资源
|
||
```
|
||
|
||
2. **配置模块POM**:
|
||
- 创建pom.xml,添加必要依赖
|
||
- 在父模块中添加新模块引用
|
||
|
||
3. **创建数据库表**:
|
||
- 设计表结构
|
||
- 编写SQL脚本
|
||
|
||
4. **开发核心功能**:
|
||
- 使用代码生成器生成基础CRUD代码
|
||
- 扩展实现具体业务逻辑
|
||
- 添加权限控制
|
||
- 实现多租户和数据权限
|
||
- 添加接口文档注释
|
||
|
||
#### 5.3.2 前端开发
|
||
|
||
1. **创建模块目录**:
|
||
```
|
||
ruoyi-plus-soybean/src/views/pms
|
||
├── product -- 产品管理
|
||
├── category -- 分类管理
|
||
└── inventory -- 库存管理
|
||
```
|
||
|
||
2. **API接口定义**:
|
||
```
|
||
ruoyi-plus-soybean/src/service/api/pms
|
||
├── product.ts -- 产品API
|
||
├── category.ts -- 分类API
|
||
└── inventory.ts -- 库存API
|
||
```
|
||
|
||
3. **配置路由**:
|
||
- 在router/routes目录下创建pms.ts
|
||
- 在router/index.ts中导入并注册路由
|
||
|
||
4. **开发页面组件**:
|
||
- 列表页面
|
||
- 表单页面
|
||
- 详情页面
|
||
|
||
5. **添加权限控制**:
|
||
- 配置菜单与按钮权限
|
||
- 实现页面级与按钮级权限控制
|
||
|
||
#### 5.3.3 集成与测试
|
||
|
||
1. **数据库脚本集成**:
|
||
- 将建表SQL添加到初始化脚本中
|
||
|
||
2. **菜单配置**:
|
||
- 通过系统管理-菜单管理添加PMS模块菜单
|
||
- 配置菜单权限
|
||
|
||
3. **角色授权**:
|
||
- 为相关角色分配PMS模块权限
|
||
|
||
4. **单元测试**:
|
||
- 编写API测试
|
||
- 编写服务层测试
|
||
|
||
5. **集成测试**:
|
||
- 测试完整业务流程
|
||
- 测试与其他模块的交互
|
||
|
||
### 5.4 使用框架核心功能的最佳实践
|
||
|
||
#### 5.4.1 使用多租户
|
||
|
||
1. **实体类继承TenantEntity**:
|
||
```java
|
||
@Data
|
||
@TableName("pms_product")
|
||
public class PmsProduct extends TenantEntity {
|
||
// 实体字段定义
|
||
}
|
||
```
|
||
|
||
2. **多租户过滤配置**:
|
||
```java
|
||
@Configuration
|
||
public class TenantConfig {
|
||
/**
|
||
* 配置需要进行多租户过滤的表
|
||
*/
|
||
@Bean
|
||
public TenantLineHandler tenantLineHandler() {
|
||
return new PlusTenantLineHandler() {
|
||
@Override
|
||
public String getTenantIdColumn() {
|
||
return "tenant_id";
|
||
}
|
||
|
||
@Override
|
||
public boolean ignoreTable(String tableName) {
|
||
// 配置不需要过滤的表
|
||
return ArrayUtil.contains(IGNORE_TENANT_TABLES, tableName);
|
||
}
|
||
};
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 5.4.2 使用数据权限
|
||
|
||
1. **在Mapper接口上使用注解**:
|
||
```java
|
||
@DataPermission({
|
||
@DataColumn(key = "deptName", value = "d.dept_id"),
|
||
@DataColumn(key = "userName", value = "u.user_id")
|
||
})
|
||
public interface SysUserMapper extends BaseMapperPlus<SysUserMapper, SysUser, SysUserVo> {
|
||
// 方法定义
|
||
}
|
||
```
|
||
|
||
2. **在查询方法上使用注解**:
|
||
```java
|
||
@Override
|
||
@DataScope(userAlias = "u", deptAlias = "d")
|
||
public List<SysUserVo> selectUserList(SysUserBo user) {
|
||
return baseMapper.selectUserList(user);
|
||
}
|
||
```
|
||
|
||
#### 5.4.3 使用数据脱敏
|
||
|
||
```java
|
||
public class UserVo {
|
||
|
||
// 手机号码脱敏
|
||
@Sensitive(strategy = SensitiveStrategy.PHONE)
|
||
private String phonenumber;
|
||
|
||
// 邮箱脱敏
|
||
@Sensitive(strategy = SensitiveStrategy.EMAIL)
|
||
private String email;
|
||
|
||
// 身份证脱敏
|
||
@Sensitive(strategy = SensitiveStrategy.ID_CARD)
|
||
private String idCard;
|
||
}
|
||
```
|
||
|
||
#### 5.4.4 使用Excel导入导出
|
||
|
||
```java
|
||
@Data
|
||
@ExcelIgnoreUnannotated
|
||
public class UserImportVo {
|
||
|
||
@ExcelProperty(value = "用户编号")
|
||
private Long userId;
|
||
|
||
@ExcelProperty(value = "用户名称")
|
||
@ExcelRequired
|
||
private String userName;
|
||
|
||
@ExcelProperty(value = "用户昵称")
|
||
@ExcelRequired
|
||
private String nickName;
|
||
|
||
@ExcelProperty(value = "手机号码")
|
||
@ExcelRequired
|
||
private String phonenumber;
|
||
|
||
@ExcelProperty(value = "邮箱")
|
||
private String email;
|
||
}
|
||
|
||
@RestController
|
||
public class UserController {
|
||
|
||
/**
|
||
* 导出用户
|
||
*/
|
||
@SaCheckPermission("system:user:export")
|
||
@Log(title = "用户管理", businessType = BusinessType.EXPORT)
|
||
@PostMapping("/export")
|
||
public void export(HttpServletResponse response, SysUserBo user) {
|
||
List<SysUserVo> list = userService.selectUserList(user);
|
||
ExcelUtil.exportExcel(list, "用户数据", SysUserVo.class, response);
|
||
}
|
||
|
||
/**
|
||
* 导入用户
|
||
*/
|
||
@SaCheckPermission("system:user:import")
|
||
@Log(title = "用户管理", businessType = BusinessType.IMPORT)
|
||
@PostMapping("/importData")
|
||
public R<Void> importData(@RequestPart("file") MultipartFile file, boolean updateSupport) throws Exception {
|
||
ExcelResult<UserImportVo> result = ExcelUtil.importExcel(file, UserImportVo.class);
|
||
userService.importUser(result.getList(), updateSupport);
|
||
return R.ok();
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 5.4.5 使用接口幂等性控制
|
||
|
||
```java
|
||
@RestController
|
||
@RequestMapping("/system/user")
|
||
public class SysUserController {
|
||
|
||
/**
|
||
* 新增用户
|
||
*/
|
||
@SaCheckPermission("system:user:add")
|
||
@Log(title = "用户管理", businessType = BusinessType.INSERT)
|
||
@RepeatSubmit(interval = 5000) // 5秒内不允许重复提交
|
||
@PostMapping
|
||
public R<Void> add(@Validated @RequestBody SysUserBo user) {
|
||
return toAjax(userService.insertUser(user));
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 5.4.6 使用Redis缓存
|
||
|
||
```java
|
||
@Service
|
||
public class SysConfigServiceImpl implements ISysConfigService {
|
||
|
||
/**
|
||
* 查询参数配置信息
|
||
*
|
||
* @param configId 参数配置ID
|
||
* @return 参数配置信息
|
||
*/
|
||
@Override
|
||
@Cacheable(cacheNames = CacheNames.SYS_CONFIG, key = "#configId")
|
||
public SysConfig selectConfigById(Long configId) {
|
||
return baseMapper.selectById(configId);
|
||
}
|
||
|
||
/**
|
||
* 新增参数配置
|
||
*
|
||
* @param config 参数配置信息
|
||
* @return 结果
|
||
*/
|
||
@Override
|
||
@CachePut(cacheNames = CacheNames.SYS_CONFIG, key = "#config.configId")
|
||
public int insertConfig(SysConfig config) {
|
||
return baseMapper.insert(config);
|
||
}
|
||
|
||
/**
|
||
* 删除参数配置
|
||
*
|
||
* @param configId 参数ID
|
||
* @return 结果
|
||
*/
|
||
@Override
|
||
@CacheEvict(cacheNames = CacheNames.SYS_CONFIG, key = "#configId")
|
||
public int deleteConfigById(Long configId) {
|
||
return baseMapper.deleteById(configId);
|
||
}
|
||
}
|
||
```
|
||
|
||
## 6. 总结
|
||
|
||
RuoYi-Vue-Plus是一个功能完善、架构清晰的企业级应用开发框架,其插件化设计和模块化结构使其非常适合二次开发。在进行二次开发时,应当遵循项目的架构设计和编码规范,通过扩展而非修改的方式实现业务需求,确保系统的可维护性和可扩展性。
|
||
|
||
通过合理利用项目提供的代码生成、多租户、权限控制等特性,可以大幅提高开发效率,专注于业务逻辑的实现,而非底层架构的搭建。
|
||
|
||
## 7. 常见问题与解决方案
|
||
|
||
### 7.1 多租户问题
|
||
|
||
**问题**:如何对特定表或操作排除多租户过滤?
|
||
|
||
**解决方案**:
|
||
- 全局排除:在TenantConfig中的ignoreTable方法中添加表名
|
||
- 局部排除:使用@TenantIgnore注解标注在方法或类上
|
||
|
||
```java
|
||
@TenantIgnore
|
||
public List<SysTenant> selectTenantList(SysTenant tenant) {
|
||
return baseMapper.selectList(buildQueryWrapper(tenant));
|
||
}
|
||
```
|
||
|
||
### 7.2 权限问题
|
||
|
||
**问题**:如何实现细粒度的数据权限控制?
|
||
|
||
**解决方案**:
|
||
- 使用@DataScope注解并配置用户、部门别名
|
||
- 在Mapper层使用@DataPermission定义权限字段
|
||
- 在XML中引用权限过滤片段
|
||
|
||
### 7.3 分布式事务问题
|
||
|
||
**问题**:如何处理跨服务的分布式事务?
|
||
|
||
**解决方案**:
|
||
- 对于强一致性需求,使用Seata进行分布式事务管理
|
||
- 对于最终一致性需求,考虑使用本地消息表+定时任务或消息队列实现
|
||
- 避免长事务,将业务拆分成多个小事务
|
||
|
||
### 7.4 性能优化问题
|
||
|
||
**问题**:系统运行缓慢,如何优化?
|
||
|
||
**解决方案**:
|
||
- 使用Redis缓存热点数据,减少数据库访问
|
||
- 优化SQL查询,避免全表扫描
|
||
- 使用分页查询代替全量查询
|
||
- 合理使用索引
|
||
- 利用多级缓存(本地缓存+Redis缓存)
|
||
- 考虑使用读写分离或分库分表 |