news 2026/5/4 23:28:54

SpringBoot 数据权限新姿势,注解+动态SQL真香!

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SpringBoot 数据权限新姿势,注解+动态SQL真香!

介绍

easy-data-scop 是一个通过动态注入SQL实现的数据权限项目。支持MyBatis、MyBatis-plus、MyBatis-flex。使用简单,无需设置各种复杂配置,仅仅通过注解便可实现效果功能。

基础项目搭建

1.数据库

图片

这是一张简单的用户表,接下来我们将为这张表编写以下数据权限

  • 仅看id为1的人

  • 仅看年龄为111的人

  • 仅看年龄为222的人

  • 看年龄为111、222的人

2.导入依赖基础依赖 (使用MyBatis-plus、MyBatis XML演示)
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>2.2.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <version>2.2.1.RELEASE</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.3.0</version> </dependency> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <version>8.0.33</version> </dependency> </dependencies>
3.核心依赖
<dependency> <groupId>cn.zlinchuan</groupId> <artifactId>ds-mybatis</artifactId> <version>1.0.1</version> </dependency>
4.启动类
@SpringBootApplication publicclassMain{ publicstaticvoidmain(String[] args){ SpringApplication.run(Main.class); } }
5.省略编写Mapper、Service
6.application.yml
server: port:8001 # DataSource Config spring: datasource: driver-class-name:com.mysql.cj.jdbc.Driver url:url username:name password:password mybatis: mapper-locations:classpath:mapper/*.xml# XML映射文件路径 mybatis-plus: configuration: log-impl:org.apache.ibatis.logging.stdout.StdOutImpl
7.测试
@Autowired private UserService userService; @Test publicvoidtest(){ userService.getAll().forEach(System.out::println); }

图片

到这里项目就已经搭建完成了

使用 easy-data-scope

图片

实现核心接口DataScopeFindRule并交由Spring管理

图片

easy-data-scope` 会去代理 `@DataScope` 方法调用 `find()` 获取到 `DataScopeInfo
DataScopeInfo介绍

easy-data-scope会根据find()方法返回的DataScopeInfo列表来构建SQL

图片

@DataScope介绍

可以编写在对应需要数据权限拦截的方法上

属性:

public@interface DataScope { /** * 通过传递给DataScopeFindRule.find方法来获取指定的数据权限实体 * @return */ String[] keys(); /** * 构建模板 * TODO 注意:当key为多个时此值生效 * key1 ==SQL==> table1.column1 = 1 * key2 ==SQL==> table2.column2 = 2 * 示例:template = "{key1} OR {key2}" * 通过template生成后的SQL:table1.column1 = 1 OR table2.column2 = 2 * @return */ String template()default ""; /** * 是否对数据权限进行自动合并 * 当操作符为 =、!= 时间如果TableName、ColumnName、操作符一样,并且使用的是 Value 形式将会对数据权限进行合并为 IN、NOT IN * 示例: * 权限1:=、table1、column1、Value1 >>> table1.column1 = Value1 * 权限2:=、table1、column1、Value2 >>> table1.column1 = Value2 * 最终合并 in table1、column1、“Value1, Value2" >>> table1.column1 in (Value1, Value2) * @return */ booleanmerge()defaultfalse; /** * 逻辑符 * 决定数据权限SQL拼接到当前执行的SQL中用的使用的是 WHERE还是AND还是OR.. * TODO 注意:在flag为true时此值将会失效 * @return */ String logical()default SqlConsts.AND; /** * 是否使用数据权限标记位标记位,true是 false否 * @return */ booleanflag()defaultfalse; }

图片

实现前文的数据权限

编写DataScopeFindRule find方法

@Override public List<DataScopeInfo> find(String[] key){ // 模拟的用户登陆Session UserSessionInfo userSession = UserSessionContext.getUserSession(); if (userSession != null) { // 数据库中查询 QueryWrapper<AuthDatascopeEntity> idQueryWrapper = new QueryWrapper<>(); // 查询用户Session中保存用户有哪些数据权限 idQueryWrapper.in("id", userSession.getDataScopeIds()); idQueryWrapper.in("datascope_key", key); List<AuthDatascopeEntity> authDatascopes = authDataSocpeMapper.selectList(idQueryWrapper); // 构建出DataScopeInfo List<DataScopeInfo> dataScopeInfos = new ArrayList<>(authDatascopes.size()); for (AuthDatascopeEntity authDatascope : authDatascopes) { DataScopeInfo dataScopeInfo = new DataScopeInfo(); dataScopeInfo.setKey(authDatascope.getDatascopeKey()); dataScopeInfo.setOperator(authDatascope.getDatascopeOpName()); dataScopeInfo.setTableName(authDatascope.getDatascopeTbName()); dataScopeInfo.setColumnName(authDatascope.getDatascopeColName()); dataScopeInfo.setSql(authDatascope.getDatascopeSql()); dataScopeInfo.setValue(authDatascope.getDatascopeValue()); dataScopeInfo.setSort(authDatascope.getDatascopeSort()); dataScopeInfos.add(dataScopeInfo); } return dataScopeInfos; } return Collections.emptyList(); }
创建数据权限表
-- auto-generated definition createtable auth_datascope ( id int auto_increment comment'编号' primary key , datascope_key varchar(200) nullcomment'数据权限标识' , datascope_name varchar(200) nullcomment'数据权限名称' , datascope_tb_name varchar(500) nullcomment'数据权限表别名' , datascope_col_name varchar(500) nullcomment'数据权限字段名' , datascope_op_name varchar(10) nullcomment'数据权限操作符' , datascope_sql varchar(5000) nullcomment'数据权限sql' , datascope_value varchar(200) nullcomment'数据权限值' , datascope_sort int nullcomment'数据权限排序' , datascope_des varchar(500) nullcomment'数据权限描述' ) comment'数据权限表';

1.只看Id为1的记录

图片

将对应实体添加到库中,实现动态配置

编写Service

@DataScope(keys = "USER_LIST_ID", logical = SqlConsts.WHERE) public List<UserEntity> getAll(){ return userMapper.selectList(null); }

调用后得到结果

SELECTid,username,age FROMuserWHERE ( user.id = 1)

2.仅看年龄为111的人

图片

@DataScope(keys = "USER_LIST_AGE111", logical = SqlConsts.WHERE) public List<UserEntity> getAll2(){ return userMapper.selectList(null); }

调用后得到结果

SELECTid,username,age FROMuserWHERE ( user.age = 111)

3.仅看年龄为222的人

图片

@DataScope(keys = "USER_LIST_AGE222", logical = SqlConsts.WHERE) public List<UserEntity> getAll3(){ return userMapper.selectList(null); }

调用后得到结果

SELECTid,username,age FROMuserWHERE ( user.age = 222)

4.看年龄为111、222的人(merge属性)

其他的不用动,使用注解中的 merge 属性,在keys中将两个前两个key都加上

@DataScope(keys = {"USER_LIST_AGE111", "USER_LIST_AGE222"}, merge = true, logical = SqlConsts.WHERE) public List<UserEntity> getAll4(){ return userMapper.selectList(null); }

调用后得到结果

SELECTid,username,age FROMuserWHERE ( user.age IN (111, 222))

更多操作

@DataScope.flag

Mapper.xml

@DataScope(keys = {"USER_LIST_AGE111", "USER_LIST_AGE222"}, merge = true, flag = true) List<UserEntity> getAll5(); <selectid="getAll5"resultType="cn.zlinchuan.entity.UserEntity"> select * from (select * from user where {{_DATA_SCOPE_FLAG}}) t where 1 = 1 </select>

注意{{_DATA_SCOPE_FLAG}}为程序定义占位,不能修改

sql

select * from (select * fromuserwhere user.age IN (111, 222)) t where1 = 1
@DataScope.template
@DataScope(keys = {"USER_LIST_AGE111", "USER_LIST_AGE222"}, flag = true, template = "{{USER_LIST_AGE111}} OR {{USER_LIST_AGE222}}") List<UserEntity> getAll6(); <selectid="getAll6"resultType="cn.zlinchuan.entity.UserEntity"> select * from (select * from user where {{_DATA_SCOPE_FLAG}}) t where 1 = 1 </select>

sql

select * from (select * fromuserwhere user.age = 111OR user.age = 222) t where1 = 1

项目源码地址

https://github.com/zoulinchuan/easy-data-scope

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/3 5:56:05

KLayout版图设计工具:从入门到精通的完整操作指南

KLayout版图设计工具&#xff1a;从入门到精通的完整操作指南 【免费下载链接】klayout KLayout Main Sources 项目地址: https://gitcode.com/gh_mirrors/kl/klayout 在集成电路设计领域&#xff0c;专业版图设计工具对于提升设计效率和质量至关重要。KLayout作为业界领…

作者头像 李华
网站建设 2026/5/3 16:29:08

WeMod专业版完整解锁终极方案:零成本畅享高级游戏辅助特权

WeMod专业版完整解锁终极方案&#xff1a;零成本畅享高级游戏辅助特权 【免费下载链接】Wemod-Patcher WeMod patcher allows you to get some WeMod Pro features absolutely free 项目地址: https://gitcode.com/gh_mirrors/we/Wemod-Patcher 还在为WeMod免费版的功能…

作者头像 李华
网站建设 2026/5/3 7:27:05

基于单片机的温度报警设定范围系统设计

一、设计背景与核心需求 在工业生产、仓储管理、家庭环境监测等场景中&#xff0c;温度超出安全范围易引发设备故障、物资损坏甚至安全事故&#xff0c;传统固定阈值温度报警器难以适配不同场景的温度管控需求。基于单片机的温度报警设定范围系统&#xff0c;借助单片机的传感器…

作者头像 李华
网站建设 2026/5/1 10:42:57

参数少≠性能弱:VibeThinker打破小模型无法推理的偏见

参数少≠性能弱&#xff1a;VibeThinker打破小模型无法推理的偏见 在AI领域&#xff0c;我们似乎早已习惯了这样的叙事——更大的模型意味着更强的能力。百亿、千亿参数的大语言模型轮番登场&#xff0c;动辄消耗数百万美元训练成本&#xff0c;部署时还需要多卡并行甚至专用集…

作者头像 李华
网站建设 2026/5/1 17:53:34

游戏外设终极配置指南:从入门到精通的完整解决方案

游戏外设终极配置指南&#xff1a;从入门到精通的完整解决方案 【免费下载链接】logitech-pubg PUBG no recoil script for Logitech gaming mouse / 绝地求生 罗技 鼠标宏 项目地址: https://gitcode.com/gh_mirrors/lo/logitech-pubg 想要在激烈的游戏对战中占据绝对优…

作者头像 李华