主流的方案有2种:查询数据时直接过滤、使用数据过滤服务
- 数据量较大且权限规则简单:推荐在查询数据时直接过滤,让数据库执行权限条件,提升性能。
- 数据量较小或需要复杂的动态权限规则:推荐使用数据过滤服务,让业务逻辑在服务层集中管理,增加灵活性。
经过分析得知:规则并不是很复杂且变更较少,所以基础框架选择查询数据时直接过滤的方式,对于复杂的业务规则,可以在服务层进行二次过滤。
以下是一个完整的方案,帮助你在 MyBatis Plus 中根据 role_data_permission
表动态生成 SQL 查询字段,实现不同角色查询不同字段的需求。这个方案包括数据库设计、数据示例、Mapper、服务层和控制层的实现代码。
1. 数据库设计
主业务数据表 (data)
data
表包含所有业务数据字段,包括一些敏感字段,管理员可以访问所有字段,普通用户只能访问部分字段。
CREATE TABLE data (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
data_field1 VARCHAR(100) NOT NULL,
data_field2 VARCHAR(100) NOT NULL,
sensitive_field1 VARCHAR(100), -- 仅管理员可见
sensitive_field2 VARCHAR(100), -- 仅管理员可见
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
角色表 (role)
role
表存储系统中的角色信息,每个角色对应不同的数据访问权限。
CREATE TABLE role (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
role_name VARCHAR(50) UNIQUE NOT NULL,
description VARCHAR(255)
);
角色-数据权限映射表 (role_data_permission)
role_data_permission
表存储每个角色可以访问的字段。不同的角色在此表中定义允许访问的数据字段。
CREATE TABLE role_data_permission (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
role_id BIGINT NOT NULL,
field_name VARCHAR(100) NOT NULL,
FOREIGN KEY (role_id) REFERENCES role(id) ON DELETE CASCADE
);
2. 数据示例
以下是一些数据示例,帮助你理解角色及其字段权限的配置。
role 表数据示例
id | role_name | description |
---|---|---|
1 | Admin | Administrator role |
2 | User | Regular user role |
role_data_permission 表数据示例
id | role_id | field_name |
---|---|---|
1 | 1 | data_field1 |
2 | 1 | data_field2 |
3 | 1 | sensitive_field1 |
4 | 1 | sensitive_field2 |
5 | 2 | data_field1 |
6 | 2 | data_field2 |
-
Admin
角色(role_id = 1)可以访问data_field1
,data_field2
,sensitive_field1
,sensitive_field2
。 -
User
角色(role_id = 2)仅能访问data_field1
和data_field2
。
3. Mapper 实现
RoleDataPermissionMapper
用于查询角色允许访问的字段列表。
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
public interface RoleDataPermissionMapper extends BaseMapper<RoleDataPermission> {
@Select("SELECT field_name FROM role_data_permission WHERE role_id = #{roleId}")
List<String> getFieldsByRoleId(@Param("roleId") Long roleId);
}
DataMapper
DataMapper
继承 MyBatis Plus 的 BaseMapper<Data>
,使用 MyBatis Plus 提供的基础查询功能。
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface DataMapper extends BaseMapper<Data> {
// 无需额外定义方法,使用 MyBatis Plus 的基础功能
}
4. 服务层实现
在服务层中,使用 QueryWrapper
根据字段权限动态设置查询字段,并执行查询。
DataService 接口
import java.util.List;
import java.util.Map;
public interface DataService {
List<Map<String, Object>> getDataByRole(Long roleId);
}
DataServiceImpl 实现类
在 DataServiceImpl
中,根据 role_id
获取该角色允许访问的字段列表,并使用 QueryWrapper
设置查询的字段。
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
@Service
public class DataServiceImpl implements DataService {
@Autowired
private DataMapper dataMapper;
@Autowired
private RoleDataPermissionMapper roleDataPermissionMapper;
@Override
public List<Map<String, Object>> getDataByRole(Long roleId) {
// 获取角色允许访问的字段列表
List<String> fields = roleDataPermissionMapper.getFieldsByRoleId(roleId);
if (fields.isEmpty()) {
throw new RuntimeException("角色没有配置任何字段权限");
}
// 使用 MyBatis Plus 的 QueryWrapper 构建动态查询
QueryWrapper<Data> queryWrapper = new QueryWrapper<>();
queryWrapper.select(fields.toArray(new String[0])); // 动态选择字段
// 执行查询并返回结果
return dataMapper.selectMaps(queryWrapper);
}
}
5. 控制层实现
控制层通过请求参数接收 roleId
并调用服务层方法获取数据,返回符合角色权限的 JSON 响应。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.http.ResponseEntity;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/data")
public class DataController {
@Autowired
private DataService dataService;
@GetMapping
public ResponseEntity<List<Map<String, Object>>> getDataByRole(
@RequestParam("roleId") Long roleId
) {
// 通过 roleId 获取数据
List<Map<String, Object>> dataList = dataService.getDataByRole(roleId);
return ResponseEntity.ok(dataList);
}
}
运行流程示例
-
用户通过
/data
接口请求数据,并传递roleId
参数。例如:GET /data?roleId=1
-
后端接收到
roleId=1
,在RoleDataPermissionMapper
中查询该角色允许访问的字段。- 对于
roleId=1
(Admin 角色),返回的字段列表为["data_field1", "data_field2", "sensitive_field1", "sensitive_field2"]
。 - 对于
roleId=2
(User 角色),返回的字段列表为["data_field1", "data_field2"]
。
- 对于
-
在
DataServiceImpl
中,根据字段权限动态生成查询,并使用QueryWrapper
指定查询的字段。- Admin 角色将查询并返回所有字段数据。
- User 角色仅查询并返回
data_field1
和data_field2
。
最终返回结果为 JSON 格式的数据列表,符合角色的字段权限。
示例返回结果
Admin 角色(roleId=1)请求返回:
[
{
"id": 1,
"data_field1": "value1",
"data_field2": "value2",
"sensitive_field1": "sensitive1",
"sensitive_field2": "sensitive2"
},
...
]
User 角色(roleId=2)请求返回:
[
{
"id": 1,
"data_field1": "value1",
"data_field2": "value2"
},
...
]
方案总结
此方案基于 MyBatis Plus 和 QueryWrapper
动态设置查询字段,结合 role_data_permission
表,实现了根据角色权限查询不同字段数据的需求。通过这种方式,系统可以灵活地控制不同角色对数据字段的访问权限。