RuoYi-Vue 车间设备管理模块数据权限实现实操
目录
- 一、项目概述与业务需求
- 二、完整实操流程
- 步骤1:数据库建表——创建车间设备表
- 步骤2:插入测试数据
- 步骤3:代码生成——导入数据库表
- 步骤4:代码生成——进入编辑配置
- 步骤5:代码生成——填写基本信息
- 步骤6:代码生成——配置字段信息
- 步骤7:代码生成——设置生成信息
- 步骤8:代码生成——下载生成代码
- 步骤9:解压并整合代码文件
- 步骤10:查看生成的Service实现类
- 步骤11:添加数据权限注解@DataScope
- 步骤12:查看Mapper XML初始版本
- 步骤13:排查中文表名相关问题
- 步骤14:修改Mapper XML——添加部门关联与数据权限参数
- 步骤15:后台菜单配置——新增"车间设备信息"菜单
- 步骤16:后端SQL调试验证
- 步骤17:前端页面验证——管理员视图
- 步骤18:角色权限分配——为普通角色赋权
- 三、实操问题汇总(踩坑记录)
- 四、RuoYi数据权限核心原理
- 五、项目总结
一、项目概述与业务需求
1. 项目背景
在企业级后台管理系统中,数据权限控制是一个核心需求。RuoYi-Vue(若依)框架内置了一套完善的数据权限体系,通过@DataScope注解+AOP切面+动态SQL拼接的方式,实现了基于部门维度的数据隔离。本项目以"车间设备管理"为业务场景,完整演示从建表、代码生成、Mapper修改、Service注解配置到后台菜单与角色权限分配的全流程。
2. 功能需求
本实验需要实现以下核心功能:
- 管理员(admin):可以查看全部部门的设备数据(3条设备记录)
- 普通用户(ry/lewis):仅能查看自己所属部门的设备数据
- 用户 ry 属于"测试部门"(dept_id=105),角色为"普通角色"
- 用户 lewis 属于"财务部门"(dept_id=106),角色为"普通角色"
- 超级管理员角色:拥有"全部数据权限"
- 普通角色:拥有"本部门数据权限"
3. 技术栈介绍
| 技术层 | 技术选型 |
|---|---|
| 后端框架 | Spring Boot + MyBatis(RuoYi-Vue v3.8.2) |
| 前端框架 | Vue 2 + Element UI |
| 数据库 | MySQL(数据库名:ry_vue_32) |
| 开发工具 | IntelliJ IDEA、Navicat Premium Lite |
| 数据权限 | @DataScope注解 + DataScopeAspect切面 + MyBatis动态SQL |
二、完整实操流程
步骤1:数据库建表——创建车间设备表
操作页面:Navicat Premium Lite 数据库管理工具
首先在数据库中创建车间设备信息表sys_equipment。该表需要包含设备基本信息字段,以及与部门关联的dept_id字段(这是实现数据权限的关键)。
完整SQL建表语句:
-- 车间设备表
CREATE TABLE sys_equipment (
equipment_id BIGINT NOT NULL AUTO_INCREMENT COMMENT '设备ID',
dept_id BIGINT NOT NULL COMMENT '所属部门ID',
equipment_no VARCHAR(50) NOT NULL COMMENT '设备编号(Zhengyixuan_739)',
equipment_name VARCHAR(100) NOT NULL COMMENT '设备名称',
status CHAR(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
del_flag CHAR(1) DEFAULT '0' COMMENT '删除标志(0正常 2删除)',
create_by VARCHAR(64) DEFAULT '' COMMENT '创建者',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_by VARCHAR(64) DEFAULT '' COMMENT '更新者',
update_time DATETIME DEFAULT NULL COMMENT '更新时间',
remark VARCHAR(255) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (equipment_id),
KEY idx_dept_id (dept_id),
KEY idx_del_flag (del_flag)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='车间设备信息表';
字段说明:
| 字段名 | 类型 | 说明 |
|---|---|---|
| equipment_id | BIGINT | 主键ID,自增 |
| dept_id | BIGINT | 所属部门ID,数据权限过滤的关键字段 |
| equipment_no | VARCHAR(50) | 设备编号,格式为"姓名拼音_序号" |
| equipment_name | VARCHAR(100) | 设备名称(中文) |
| status | CHAR(1) | 状态:0-正常,1-停用 |
| del_flag | CHAR(1) | 删除标志:0-正常,2-删除 |
| create_by/create_time | VARCHAR/DATETIME | 创建者/创建时间 |
| update_by/update_time | VARCHAR/DATETIME | 更新者/更新时间 |
| remark | VARCHAR(255) | 备注信息 |
设计要点:
dept_id字段是数据权限的核心,标记每台设备属于哪个部门del_flag字段用于逻辑删除,与RuoYi框架规范保持一致- 表名前缀使用
sys_,与RuoYi系统表命名规范统一 - 索引设计:
idx_dept_id索引用于加速部门维度查询
执行结果:OK,运行时间 0.157s,表创建成功。

步骤2:插入测试数据
操作页面:Navicat Premium Lite 数据库管理工具
向sys_equipment表中插入3条测试数据,分别属于两个不同的部门:
- 测试部门(dept_id = 105):2台机床设备
- 财务部门(dept_id = 106):1台打印机设备
完整INSERT语句:
-- 部门:测试部门 dept_id=105; 财务部门 dept_id=106
INSERT INTO sys_equipment
(dept_id, equipment_no, equipment_name, status, del_flag, create_by)
VALUES
(105, 'Zhengyixuan_739_001', '一号机床', '0', '0', 'admin'),
(105, 'Zhengyixuan_739_002', '二号机床', '0', '0', 'admin'),
(106, 'Zhengyixuan_739_003', '财务专用打印机', '0', '0', 'admin');
数据分布说明:
| 设备编号 | 设备名称 | 所属部门 | dept_id | 创建者 |
|---|---|---|---|---|
| Zhengyixuan_739_001 | 一号机床 | 测试部门 | 105 | admin |
| Zhengyixuan_739_002 | 二号机床 | 测试部门 | 105 | admin |
| Zhengyixuan_739_003 | 财务专用打印机 | 财务部门 | 106 | admin |
执行结果:Affected rows: 3,运行时间 0.108s,数据插入成功。
数据权限测试预期:
- 登录admin用户:应看到全部3条设备记录
- 登录ry用户(测试部门):应仅看到2条测试部门的设备
- 登录lewis用户(财务部门):应仅看到1条财务部门的设备

步骤3:代码生成——导入数据库表
操作页面:若依管理系统 → 系统工具 → 代码生成 → 导入表
在RuoYi后台管理系统中,进入"系统工具 → 代码生成"页面,点击"导入"按钮,弹出"导入表"对话框。
操作步骤:
- 点击左侧菜单"系统工具" → “代码生成”
- 在代码生成页面中,点击"导入"按钮
- 在弹出的"导入表"对话框中,输入搜索条件
- 在数据列表中找到
sys_equipment表 - 勾选该表的复选框
- 点击"确定"按钮完成导入
导入成功后,代码生成列表中会出现一条新的记录,表名称为"车间设备信息表",对应实体类名为SysEquipment。

步骤4:代码生成——进入编辑配置
操作页面:若依管理系统 → 系统工具 → 代码生成 → 编辑
导入成功后,在代码生成列表中找到"车间设备信息表"这条记录,点击操作栏中的"编辑"按钮,进入生成配置页面。
此时可以看到:
- 表名称:车间设备信息表
- 表描述:车间设备信息表
- 实体类:SysEquipment
- 创建时间:2026-06-01 09:11:36

步骤5:代码生成——填写基本信息
操作页面:若依管理系统 → 代码生成 → 修改生成配置 → 基本信息
在"修改[车间设备信息表]生成配置"页面中,切换到"基本信息"选项卡,填写以下内容:
| 配置项 | 填写内容 | 说明 |
|---|---|---|
| 表名称 | 车间设备信息表 | 自动读取,无需修改 |
| 表描述 | 车间设备信息表 | 自动读取 |
| 实体类名称 | SysEquipment | Java实体类名(驼峰命名) |
| 作者 | Zhengyixuan_739 | 代码中@author标注的作者名 |
| 备注 | (留空) | 可选填写 |
填写完成后,不要急于提交,还需要配置"字段信息"和"生成信息"。

步骤6:代码生成——配置字段信息
操作页面:若依管理系统 → 代码生成 → 修改生成配置 → 字段信息
切换到"字段信息"选项卡,确认每个数据库字段对应的Java属性和类型是否正确:
| 序号 | 字段列名 | 字段描述 | 物理类型 | Java类型 | Java属性 |
|---|---|---|---|---|---|
| 1 | equipment_id | 设备ID | bigint | Long | equipmentId |
| 2 | dept_id | 所属部门 | bigint | Long | deptId |
| 3 | equipment_no | 设备编号 | varchar(50) | String | equipmentNo |
| 4 | equipment_name | 设备名称 | varchar(100) | String | equipmentName |
| 5 | status | 状态 | char(1) | String | status |
| 6 | del_flag | 删除标志 | char(1) | String | delFlag |
| 7 | create_by | 创建者 | varchar(64) | String | createBy |
| 8 | create_time | 创建时间 | datetime | Date | createTime |
| 9 | update_by | 更新者 | varchar(64) | String | updateBy |
| 10 | update_time | 更新时间 | datetime | Date | updateTime |
| 11 | remark | 备注 | varchar(500) | String | remark |
关键字段确认:
dept_id(所属部门)字段是后续数据权限过滤的核心,必须确保正确映射del_flag(删除标志)字段用于条件逻辑删除过滤

步骤7:代码生成——设置生成信息
操作页面:若依管理系统 → 代码生成 → 修改生成配置 → 生成信息
切换到"生成信息"选项卡,进行以下配置:
| 配置项 | 填写/选择内容 | 说明 |
|---|---|---|
| 生成模板 | 单表(增删改查) | 选择单表CRUD模板 |
| 前端类型 | Vue2 Element UI 模版 | 前端Vue页面类型 |
| 生成包路径 | com.ruoyi.system | Java代码的根包路径 |
| 生成模块名 | system | 模块名称 |
| 生成业务名 | equipment | 业务名称(URL路径会用到) |
| 生成功能名 | 车间设备信息 | 页面上显示的功能名称 |
| 生成代码方式 | zip压缩包 | 下载ZIP包手动解压 |
| 上级菜单 | 系统管理 | 菜单归属到"系统管理"下 |
配置完成后点击"提交"按钮保存配置。
配置效果说明:
- 后端Java代码会生成到
com.ruoyi.system包下 - 控制器路由前缀为:
/system/equipment - 前端页面文件位于Vue项目的
equipment目录下

步骤8:代码生成——下载生成代码
操作页面:若依管理系统 → 系统工具 → 代码生成
回到代码生成主页面,可以看到"车间设备信息表"这一行的更新时间已刷新(09:25:04)。点击该行操作栏中的"生成代码"按钮(红色方框高亮),系统会生成一份包含前后端全套代码的ZIP压缩包。
ZIP包中包含的文件:
- Java后端代码:Entity实体类、Mapper接口、Mapper XML、Service接口、Service实现类、Controller控制器
- Vue前端代码:列表页面(index.vue)、API接口调用(api.js)
- SQL脚本:菜单数据插入脚本(equipmentMenu.sql)

步骤9:解压并整合代码文件
操作页面:Windows文件资源管理器
将下载的ZIP压缩包解压,可以看到以下文件结构:
├── main/ (后端Java代码和资源文件)
│ └── ...
├── vue/ (前端Vue代码)
│ └── ...
└── equipmentMenu.sql (后台菜单SQL脚本)
整合步骤:
- 将
main目录下的Java文件按包结构放入项目对应位置 - 将Mapper XML文件放入
resources/mapper/system/目录 - 将
vue目录下的前端文件放入Vue项目对应位置 - 执行
equipmentMenu.sql脚本(或在后台管理界面中手动添加菜单)

步骤10:查看生成的Service实现类
操作页面:IntelliJ IDEA开发环境(RuoYi-Vue-v3.8.2项目)
打开生成的SysEquipmentServiceImpl.java文件,查看Service实现类的基本结构。
关键代码:
package com.ruoyi.system.service.impl;
import java.util.List;
import com.ruoyi.common.utils.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.system.mapper.SysEquipmentMapper;
import com.ruoyi.system.domain.SysEquipment;
import com.ruoyi.system.service.ISysEquipmentService;
import com.ruoyi.common.annotation.DataScope; // ← 需要手动导入此注解
/**
* 车间设备信息Service业务层处理
*
* @author Zhengyixuan_739
* @date 2026-06-01
*/
@Service
public class SysEquipmentServiceImpl implements ISysEquipmentService
{
@Autowired
private SysEquipmentMapper sysEquipmentMapper;
// 查询方法将在此处添加 @DataScope 注解
}
注意事项:
- 代码生成器自动生成了基本的CRUD方法框架
import com.ruoyi.common.annotation.DataScope;需要手动添加(代码生成器不会自动导入)@DataScope是RuoYi框架自定义的数据权限注解

步骤11:添加数据权限注解@DataScope
操作页面:IntelliJ IDEA开发环境(RuoYi-Vue-v3.8.2项目)
在SysEquipmentServiceImpl.java的selectSysEquipmentList方法上添加@DataScope注解,这是实现数据权限的核心步骤。
完整代码:
@Service
public class SysEquipmentServiceImpl implements ISysEquipmentService
{
@Autowired
private SysEquipmentMapper sysEquipmentMapper;
/**
* 查询车间设备信息列表
*
* @param sysEquipment 车间设备信息
* @return 车间设备信息
*/
@Override
@DataScope(deptAlias = "d", userAlias = "e") // ← 数据权限注解
public List<SysEquipment> selectSysEquipmentList(SysEquipment sysEquipment)
{
return sysEquipmentMapper.selectSysEquipmentList(sysEquipment);
}
/**
* 新增车间设备信息
*
* @param sysEquipment 车间设备信息
* @return 结果
*/
@Override
public int insertSysEquipment(SysEquipment sysEquipment)
{
sysEquipment.setCreateTime(DateUtils.getNowDate());
return sysEquipmentMapper.insertSysEquipment(sysEquipment);
}
/**
* 修改车间设备信息
*/
// ... 其他CRUD方法
}
@DataScope注解参数详解:
| 参数 | 值 | 含义 |
|---|---|---|
| deptAlias | “d” | SQL中部门表的别名(对应sys_dept d的d) |
| userAlias | “e” | SQL中主表(设备表)的别名(对应sys_equipment e的e) |
工作原理简述:
- 当调用
selectSysEquipmentList方法时,AOP切面DataScopeAspect会拦截该方法 - 切面读取当前登录用户的角色数据权限范围
- 切面根据权限范围生成对应的SQL过滤条件(如
AND (d.dept_id = 105)) - 将过滤条件拼接到SQL中的
${params.dataScope}占位符位置

步骤12:查看Mapper XML初始版本
操作页面:IntelliJ IDEA开发环境(RuoYi-Vue-v3.8.2项目)
打开代码生成器生成的SysEquipmentMapper.xml初始版本。这个版本还不能支持数据权限,需要进行关键修改。
初始Mapper XML代码:
<mapper namespace="com.ruoyi.system.mapper.SysEquipmentMapper">
<resultMap type="SysEquipment" id="SysEquipmentResult">
<result property="deptId" column="dept_id" />
<result property="equipmentNo" column="equipment_no" />
<result property="equipmentName" column="equipment_name" />
<result property="status" column="status" />
<result property="delFlag" column="del_flag" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
<result property="remark" column="remark" />
</resultMap>
<sql id="selectSysEquipmentVo">
select e.equipment_id, e.dept_id, e.equipment_no, e.equipment_name,
e.status, e.del_flag, e.create_by, e.create_time,
e.update_by, e.update_time
from sys_equipment e
</sql>
<select id="selectSysEquipmentList" parameterType="SysEquipment"
resultMap="SysEquipmentResult">
<include refid="selectSysEquipmentVo"/>
<where>
<if test="deptId != null "> and dept_id = #{deptId}</if>
<if test="equipmentNo != null and equipmentNo != ''">
and equipment_no like concat('%', #{equipmentNo}, '%')
</if>
<if test="equipmentName != null and equipmentName != ''">
and equipment_name like concat('%', #{equipmentName}, '%')
</if>
<if test="status != null and status != ''">
and status = #{status}
</if>
</where>
</select>
<!-- 其他查询、插入、更新方法... -->
</mapper>
初始版本存在的问题:
- 缺少部门表关联(LEFT JOIN):无法获取部门信息,数据权限切面无法根据部门ID过滤
- 缺少
${params.dataScope}占位符:数据权限切面生成的SQL片段没有注入点 - 缺少逻辑删除过滤(
del_flag = '0'):可能查出已删除的记录


步骤13:排查中文表名相关问题
操作页面:数据库管理工具搜索功能
在进行Mapper XML修改之前,需要先在代码中排查可能存在的"中文表名"问题。使用数据库管理工具(Navicat/DBeaver)的全局搜索功能,搜索关键字"车间设备信息表",确保所有引用处使用的是英文表名sys_equipment而非中文表名。
搜索操作:
- 搜索关键字:车间设备信息表(中文表名)
- 关联搜索:sys_equipment(英文表名)
- 找到4处匹配项,逐项检查确认
排查要点:
- 如果Mapper XML中写的是中文表名,MySQL会因字符集问题报错
- 确保所有SQL语句使用英文表名
sys_equipment - RuoYi代码生成器会自动使用英文表名,但手动修改时要特别注意

步骤14:修改Mapper XML——添加部门关联与数据权限参数
操作页面:IntelliJ IDEA开发环境(RuoYi-Vue-v3.8.2项目)
这是整个数据权限实现中最关键的一步。需要在selectSysEquipmentList查询方法中做三处关键修改(红色方框标注处)。
修改后的完整Mapper XML代码:
<mapper namespace="com.ruoyi.system.mapper.SysEquipmentMapper">
<resultMap type="SysEquipment" id="SysEquipmentResult">
<result property="updateTime" column="update_time" />
<result property="remark" column="remark" />
<!-- 其他字段映射... -->
</resultMap>
<sql id="selectSysEquipmentVo">
select e.equipment_id, e.dept_id, e.equipment_no, e.equipment_name,
e.status, e.del_flag, e.create_by, e.create_time,
e.update_by, e.update_time
from sys_equipment e
</sql>
<select id="selectSysEquipmentList" parameterType="SysEquipment"
resultMap="SysEquipmentResult">
<include refid="selectSysEquipmentVo"/>
left join sys_dept d on e.dept_id = d.dept_id 【修改1:关联部门表】
<where>
e.del_flag = '0' 【修改2:逻辑删除过滤】
${params.dataScope} 【修改3:数据权限占位符】
<if test="deptId != null "> and e.dept_id = #{deptId}</if>
<if test="equipmentNo != null and equipmentNo != ''">
and e.equipment_no like concat('%', #{equipmentNo}, '%')
</if>
<if test="equipmentName != null and equipmentName != ''">
and e.equipment_name like concat('%', #{equipmentName}, '%')
</if>
<if test="status != null and status != ''">
and e.status = #{status}
</if>
</where>
</select>
<select id="selectSysEquipmentByEquipmentId" parameterType="Long"
resultMap="SysEquipmentResult">
<include refid="selectSysEquipmentVo"/>
where equipment_id = #{equipmentId}
</select>
<insert id="insertSysEquipment" parameterType="SysEquipment"
useGeneratedKeys="true" keyProperty="equipmentId">
insert into sys_equipment
<!-- 插入字段列表... -->
</insert>
</mapper>
三处核心修改详解:
| 修改项 | 代码 | 作用 |
|---|---|---|
| 修改1:关联部门表 | left join sys_dept d on e.dept_id = d.dept_id |
关联部门表,使数据权限切面可以根据部门ID过滤。注意别名字母d与@DataScope(deptAlias = "d")中的参数保持一致 |
| 修改2:逻辑删除过滤 | e.del_flag = '0' |
只查询未被删除(del_flag=‘0’)的记录。注意添加表别名e.前缀,避免字段歧义 |
| 修改3:数据权限占位符 | ${params.dataScope} |
数据权限切面(DataScopeAspect)会动态替换此占位符。例如,普通角色登录时,此占位符会被替换为AND (d.dept_id = 105) |
注意添加表别名的重要性:
- 修改前:
del_flag = '0'(没有表别名,如果有多表可能会引起字段歧义) - 修改后:
e.del_flag = '0'(明确指定从设备表别名e取字段) - 修改前:
dept_id = #{deptId}(没有表别名) - 修改后:
e.dept_id = #{deptId}(明确指定从设备表别名e取字段)

步骤15:后台菜单配置——新增"车间设备信息"菜单
操作页面:若依管理系统 → 系统管理 → 菜单管理
代码整合完成后,需要在RuoYi后台管理系统中添加"车间设备信息"菜单,使其显示在左侧导航栏中。
重要提示:也可以直接执行代码生成时提供的equipmentMenu.sql脚本,或者在后台手动添加。
手动添加菜单的操作步骤如下:
- 进入"系统管理 → 菜单管理"页面
- 点击"新增"按钮
- 在弹出的菜单新增表单中,填写以下信息:
| 配置项 | 填写内容 | 说明 |
|---|---|---|
| 菜单名称 | 车间设备信息 | 左侧导航栏显示的名称 |
| 上级菜单 | 系统管理 | 菜单归属到"系统管理"菜单组下 |
| 显示顺序 | (按实际设置) | 菜单在导航栏中的排列顺序 |
| 路由地址 | equipment | 前端Vue页面的路由路径 |
| 权限标识 | system:equipment:list | 权限控制的标识符 |
| 菜单类型 | 菜单(M) | 选择菜单类型 |
| 菜单图标 | (选择合适的图标) | 菜单前面显示的图标 |
| 是否外链 | 否 | 不是外部链接 |
- 点击"确定"按钮完成菜单添加

步骤16:后端SQL调试验证
操作页面:IntelliJ IDEA控制台(DEBUG日志)
启动项目,访问车间设备信息页面,观察后端控制台输出的SQL调试日志,验证数据权限SQL是否正确拼接。
控制台DEBUG日志输出:
10:04:22.162 [http-nio-8080-exec-20] DEBUG c.r.s.m.S.selectSysEquipmentList_COUNT - [debug,137] - ==>
Preparing: select count(0) from (
select e.equipment_id, e.dept_id, e.equipment_no, e.equipment_name,
e.status, e.del_flag, e.create_by, e.create_time,
e.update_by, e.update_time
from sys_equipment e
left join sys_dept d on e.dept_id = d.dept_id
where e.del_flag = '0'
AND (d.dept_id = 105)
) tmp_count
10:04:22.163 [http-nio-8080-exec-20] DEBUG c.r.s.m.S.selectSysEquipmentList - [debug,137] - ==>
Preparing: select e.equipment_id, e.dept_id, e.equipment_no, e.equipment_name,
e.status, e.del_flag, e.create_by, e.create_time,
e.update_by, e.update_time
from sys_equipment e
left join sys_dept d on e.dept_id = d.dept_id
where e.del_flag = '0'
AND (d.dept_id = 105)
LIMIT ?
10:04:22.163 [http-nio-8080-exec-20] DEBUG c.r.s.m.S.selectSysEquipmentList - [debug,137] - ==>
Parameters: 10(Integer)
10:04:22.168 [http-nio-8080-exec-20] DEBUG c.r.s.m.S.selectSysEquipmentList - [debug,137] - <==
Total: 3
SQL分析——当管理员(admin)登录时:
-- 超级管理员有"全部数据权限",因此不会拼接部门过滤条件
select ... from sys_equipment e
left join sys_dept d on e.dept_id = d.dept_id
where e.del_flag = '0'
LIMIT ?
-- 查询结果: Total: 3(显示全部设备)
SQL分析——当普通用户(ry,属于测试部门dept_id=105)登录时:
-- @DataScope生成的条件: AND (d.dept_id = 105)
select ... from sys_equipment e
left join sys_dept d on e.dept_id = d.dept_id
where e.del_flag = '0'
AND (d.dept_id = 105)
LIMIT ?
-- 查询结果: Total: 2(仅显示测试部门的2台设备)
关键验证点:
${params.dataScope}被正确替换为AND (d.dept_id = 105)LEFT JOIN关联的部门表别名d被用来过滤部门ID- 逻辑删除过滤
e.del_flag = '0'正常工作 - 动态条件(equipmentNo、equipmentName等)支持模糊查询

步骤17:前端页面验证——管理员视图
操作页面:若依管理系统 → 系统管理 → 车间设备信息
使用管理员账号(admin)登录后,进入"车间设备信息"页面,验证页面功能。
页面功能说明:
(1)筛选查询区:支持按所属部门ID、设备编号、设备名称、状态等条件进行搜索
(2)功能按钮区:
- 新增:添加新的设备记录
- 修改:编辑选中的设备信息
- 删除:逻辑删除选中的设备
- 导出:导出设备列表数据
(3)数据表格(管理员视图——显示全部设备):
| 设备ID | 设备编号 | 设备名称 | 状态 | 创建时间 | 操作 |
|---|---|---|---|---|---|
| 1 | Zhengyixuan_739_001 | 一号机床 | 正常 | 2026-06-01 | 修改/删除 |
| 2 | Zhengyixuan_739_002 | 二号机床 | 正常 | 2026-06-01 | 修改/删除 |
| 3 | Zhengyixuan_739_003 | 财务专用打印机 | 正常 | 2026-06-01 | 修改/删除 |
验证结论:管理员admin可以看到所有3条设备记录(包括测试部门和财务部门的设备),数据权限对超级管理员不产生限制效果。
(4)分页区:共3条记录,支持翻页和跳转

步骤18:角色权限分配——为普通角色赋权
操作页面:若依管理系统 → 系统管理 → 角色管理 → 修改角色
最后一步是配置角色权限,确保普通角色的用户只能看到自己部门的设备数据。
操作步骤:
- 进入"系统管理 → 角色管理"页面
- 在角色列表中找到"普通角色"(权限字符:common)
- 点击该角色的"修改"按钮,弹出"修改角色"对话框
角色基本信息:
| 配置项 | 值 |
|---|---|
| 角色名称 | 普通角色 |
| 权限字符 | common |
| 角色顺序 | 2 |
| 状态 | 正常 |
菜单权限分配:
在"菜单权限"树形结构中,展开"系统管理"节点,勾选"车间设备信息"菜单项(红色方框标注),确保普通角色有权访问车间设备信息页面。
数据权限配置:
进入"系统管理 → 角色管理 → 数据权限",为"普通角色"设置数据权限范围:
| 配置项 | 选择 |
|---|---|
| 权限范围 | 本部门数据权限 |
完整配置总结:
| 角色 | 权限字符 | 菜单权限 | 数据权限 | 效果 |
|---|---|---|---|---|
| 超级管理员 | admin | 全部菜单 | 全部数据权限 | 查看所有部门的设备 |
| 普通角色 | common | 系统管理(含车间设备信息) | 本部门数据权限 | 仅查看本部门的设备 |
多账号验证:
| 登录用户 | 所属部门 | 角色 | 预期可见设备 |
|---|---|---|---|
| admin | 总公司 | 超级管理员 | 3条(全部) |
| ry | 测试部门(105) | 普通角色 | 2条(Zhengyixuan_739_001、002) |
三、实操问题汇总(踩坑记录)
问题1:中文表名导致MySQL报错
| 项目 | 说明 |
|---|---|
| 现象 | 在Mapper XML中误用了中文表名"车间设备信息表"作为SQL查询的目标表 |
| 原因 | MySQL在SQL语句中无法解析中文表名,需要严格使用英文表名sys_equipment |
| 解决方案 | 使用数据库管理工具的全局搜索功能,查找所有"车间设备信息表"的中文引用,全部替换为sys_equipment。RuoYi代码生成器会自动使用英文表名,但手动修改代码时需格外注意 |
问题2:字段歧义(Column ambiguous)报错
| 项目 | 说明 |
|---|---|
| 现象 | 启动应用后访问页面,后端报错:Column 'del_flag' in where clause is ambiguous 或 Column 'dept_id' in where clause is ambiguous |
| 原因 | 在LEFT JOIN关联部门表后,主表sys_equipment和关联表sys_dept都有del_flag等公共字段。SQL中的where del_flag = '0'没有指定表别名,MySQL无法确定使用哪个表的字段 |
| 解决方案 | 在WHERE子句中的所有字段前面加上表别名前缀:e.del_flag = '0'、e.dept_id = #{deptId}、e.status = #{status}等。确保每个字段都有明确的表别名 |
对比代码:
修改前(会报错):
<where>
del_flag = '0' ← 字段歧义!
${params.dataScope}
<if test="deptId != null "> and dept_id = #{deptId}</if> ← 字段歧义!
修改后(正确):
<where>
e.del_flag = '0' ← 明确表别名e
${params.dataScope}
<if test="deptId != null "> and e.dept_id = #{deptId}</if> ← 明确表别名e
问题3:菜单添加后不显示(缓存问题)
| 项目 | 说明 |
|---|---|
| 现象 | 在后台菜单管理中添加了"车间设备信息"菜单,但左侧导航栏没有显示 |
| 原因 | RuoYi框架对菜单进行了缓存,新增菜单后需要刷新缓存才能生效 |
| 解决方案 | 方法一:退出登录后重新登录;方法二:在系统监控中清除缓存;方法三:重新编译部署前端项目。推荐使用重新登录的方式 |
问题4:普通角色无法访问车间设备信息菜单
| 项目 | 说明 |
|---|---|
| 现象 | 使用普通角色用户(ry/lewis)登录后,左侧菜单没有"车间设备信息"选项 |
| 原因 | 新增菜单后,需要在角色管理中为"普通角色"分配该菜单的访问权限。否则即使用户属于该角色,也无法看到该菜单 |
| 解决方案 | 进入"系统管理 → 角色管理 → 修改普通角色 → 菜单权限",勾选"车间设备信息"菜单项并保存 |
问题5:数据权限不生效
| 项目 | 说明 |
|---|---|
| 现象 | @DataScope注解已添加,Mapper XML也加了LEFT JOIN和${params.dataScope},但所有用户仍然可以看到全部数据 |
| 原因 | 可能原因有三:① deptAlias/userAlias参数值与XML中的表别名不一致;② 角色的数据权限范围没有设置为"本部门数据权限";③ 实体类没有继承BaseEntity(params属性丢失) |
| 解决方案 | 逐个排查:检查注解参数与XML别名一致性 → 检查角色数据权限配置 → 检查实体类是否继承BaseEntity |
四、RuoYi数据权限核心原理
4.1 整体架构
RuoYi框架的数据权限实现采用了 “注解声明 + AOP拦截 + SQL动态拼接” 的设计模式,整体架构如下:
Controller层
↓ 调用
Service层 (@DataScope注解声明权限规则)
↓ AOP拦截
DataScopeAspect切面 (根据用户角色拼接权限SQL)
↓ 注入params.dataScope
Mapper XML (通过${params.dataScope}使用权限SQL)
↓ 最终SQL
数据库 (执行带权限过滤的SQL)
4.2 核心组件说明
(1)@DataScope注解
定义在com.ruoyi.common.annotation.DataScope,两个核心参数:
| 参数 | 说明 |
|---|---|
| deptAlias | SQL中部门表的别名,用于拼接部门ID过滤条件 |
| userAlias | SQL中主表(用户/业务表)的别名,用于拼接用户过滤条件 |
(2)DataScopeAspect切面类
这是一个AOP切面类(标注@Aspect),通过@Before("@annotation(controllerDataScope)")拦截所有标注了@DataScope的方法。其核心逻辑在dataScopeFilter方法中:
处理流程:
- 获取当前登录用户的所有角色
- 遍历角色,找到数据权限范围(全部/自定义/本部门/本部门及以下/仅本人)
- 根据权限范围生成对应的SQL片段:
- 全部数据权限:不添加任何过滤条件
- 本部门数据权限:生成
AND (d.dept_id = 当前用户部门ID) - 本部门及以下:生成
AND (d.dept_id IN (当前部门及子部门ID集合)) - 自定义数据权限:生成
AND (d.dept_id IN (自定义部门ID集合)) - 仅本人:生成
AND (e.create_by = 当前用户名)
- 将生成的SQL片段拼接后赋值给
params.dataScope
(3)params.dataScope 占位符
params是RuoYi框架中BaseEntity基类的一个Map<String, Object>属性。AOP切面将生成的权限SQL片段放入params.dataScope键中,MyBatis通过${params.dataScope}直接替换为SQL片段。
注意:这里使用的是$符号(字符串替换),而不是#符号(预编译参数)。因为这里替换的是整个SQL条件片段,而非单个参数值。
4.3 以本实验为例的完整数据流
用户ry登录 → 所属部门dept_id=105 → 角色为"普通角色" → 数据权限为"本部门数据权限"
↓
访问车间设备信息页面 → Controller调用selectSysEquipmentList()
↓
DataScopeAspect拦截 → 读取用户角色权限 → "本部门数据权限"
↓
生成SQL片段: AND (d.dept_id = 105)
↓
params.dataScope = "AND (d.dept_id = 105)"
↓
最终SQL:
SELECT ... FROM sys_equipment e
LEFT JOIN sys_dept d ON e.dept_id = d.dept_id
WHERE e.del_flag = '0'
AND (d.dept_id = 105)
↓
返回结果: 2条设备记录(仅测试部门的设备)
4.4 五种数据权限范围对应的SQL
| 权限范围 | 对应编号 | 生成的SQL片段示例 |
|---|---|---|
| 全部数据权限 | 1 | 不添加过滤条件 |
| 自定义数据权限 | 2 | AND d.dept_id IN (105, 106, ...) |
| 本部门数据权限 | 3 | AND d.dept_id = 105 |
| 本部门及以下数据权限 | 4 | AND d.dept_id IN (105, 107, 108, ...) |
| 仅本人数据权限 | 5 | AND e.create_by = 'ry' |
五、项目总结
5.1 核心要点回顾
-
数据权限的本质是对SQL的动态修改。无论是数据分页(PageHelper)还是数据权限(DataScope),本质上都是在原始SQL基础上动态拼接额外的条件语句。
-
三个关键要素缺一不可:
- Service层的
@DataScope注解(声明需要数据权限过滤) - Mapper XML中的
LEFT JOIN部门表 +${params.dataScope}占位符(提供执行机制) - 后台角色管理中的数据权限配置(定义过滤规则)
- Service层的
-
别名一致性至关重要:
@DataScope(deptAlias = "d")中的d必须与Mapper XML中sys_dept d的别名d完全一致。 -
表别名解决字段歧义:在
LEFT JOIN后,WHERE中所有字段都必须用e.字段名或d.字段名的形式明确指定来源表。
5.2 技术收获
通过本次实操,掌握了以下核心技术点:
- MyBatis动态SQL的编写(
<if>条件判断 +<include>复用 +${}字符串替换) - AOP面向切面编程的应用场景(在方法执行前拦截并修改参数)
- RuoYi框架数据权限的完整实现链路
- 数据库表设计中的权限字段预留(
dept_id、create_by) - 前后端代码生成器的使用,大幅提高开发效率
- 后台多角色权限配置与测试验证方法
5.3 拓展思考
- 数据分页与数据权限的共同点:两者本质上都是对SQL语句进行修改——分页添加
LIMIT子句,数据权限添加WHERE过滤条件 - 列权限控制:如果要实现不同用户看到不同列(如用户A看不到手机号码列),可以考虑从
SELECT列集合入手,通过动态控制列的选择来实现 - 代码复用:掌握了本次设备管理的数据权限实现后,可以为系统中的其他业务表(如学生管理、订单管理等)添加类似的数据权限控制
更多推荐

所有评论(0)