当前位置: 首页 > news >正文

SpringAOP切面实例实现对数据过滤返回,SpringAOP切面实现对用户权限控制,通过@Around注解过滤修改方法返回值

文章目录

        • 需求内容:
      • 实现:
          • 步骤一:导入SpringAOP相关依赖pom.xml
          • 步骤二:自定义两个注解
          • 步骤三:需要用到的实体类
          • **步骤四:切面具体实现**
      • 用法
          • 1.需要过滤返回值的方法添加注解@FilterByUser
          • 2.数据Dto在需要过滤的字段添加@Filter注解,值为数据库中json字段的key
          • 3.数据库中添加一条记录
          • 4.完成配置的效果
      • **实现原理描述**

需求内容:

在系统已经完成的情况下,添加以下权限:

·城市为“上海”和“深圳”的“部门一”用户,只能看到用户表数据中城市为“上海或深圳”且部门为“部门一的子部门”。

所用技术包含,自定义注解,SpringAOP切面,反射以及其他SpringBoot项目常用

实现:

步骤一:导入SpringAOP相关依赖pom.xml
		<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId><version>2.6.6</version></dependency>
步骤二:自定义两个注解
package cn.fy.anno;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** @author Fy* 自定义注解,在实体类中有该注解的字段即可以被过滤* @Date 2022年12月14日 11:12:59*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Filter {//{"bumen":["部门11","部门12","部门13","部门14"]} 则keyName为 bumen//此处用“bumen”只是为了证明可以和实体类的dept不同String value() default "";}
package cn.fy.anno;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface FilterByUser {}
步骤三:需要用到的实体类

1.要查询要过滤的数据实体类,需继承2实体类,或(包含2实体类中需要查询的字段,并修改对应切面中获取前端传递用户账号的方法)

package cn.fy.dto;import cn.fy.anno.Filter;
import lombok.Data;
import java.io.Serializable;
@Data
public class User extends QueryDto implements Serializable {private String userName;@Filter("bumen")//写成拼音只是为了证明可以与实体类字段名不一致private String dept;@Filter("chengshi")private String city;
}

2.接收前端传递参数的查询实体类

package cn.fy.dto;
import lombok.Data;
@Data
public class QueryDto {int pageIndex;int pageSize;String role;//登录的用户账号String userName;
}

3.权限数据库表对应的实体类和对应Mapper

package cn.fy.dto;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
/*** @author Fy* @since 2023-02-10*/
@Data
@TableName("user_power")
public class UserPower implements Serializable {private static final long serialVersionUID = 1L;@TableId("id")private Integer id;@TableField("user_name")private String userName;@TableField("create_time")private String createTime;@TableField("json")private String json;
}package cn.fy.sql;import cn.fy.dto.UserPower;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;/*** @author Fy* @since 2023-02-10*/
@Mapper
public interface UserPowerMapper extends BaseMapper<UserPower> {}
步骤四:切面具体实现
package cn.fy.aspect;import cn.fy.anno.Filter;
import cn.fy.dto.UserPower;
import cn.fy.dto.QueryDto;
import cn.fy.sql.UserPowerMapper;
import cn.fy.sql.UserPowerMapper;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;@Component
@Aspect
@Slf4j
public class PowerAspect {@Resourceprivate UserPowerMapper userPowerMapper;//需要限定包的话则自行添加@exectution@Pointcut("@annotation(cn.fy.anno.FilterByUser)")public void pointCut() {}@Around("pointCut()")public Object around(ProceedingJoinPoint joinPoint) {Object reDto = null;Object[] args = joinPoint.getArgs();try {//执行方法并获得返回值reDto = joinPoint.proceed(args);} catch (Throwable throwable) {log.error("", throwable);throw new RuntimeException(throwable);}QueryDto queryDto = null;for (Object arg : args) {if (arg instanceof QueryDto) {queryDto = (QueryDto) arg;break;}}if (queryDto == null) {return reDto;}//此部分为MybatisPlus查询数据库方法,可自行替换LambdaQueryWrapper<UserPower> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(UserPower::getUserName, queryDto.getUserName());UserPower powerDto = userPowerMapper.selectOne(queryWrapper);log.info(JSON.toJSONString(powerDto));log.info("---查询时间戳---" + System.currentTimeMillis());JSONObject jsonObject = null;if (powerDto == null) {return reDto;}try {jsonObject = JSON.parseObject(powerDto.getJson());} catch (Exception e) {log.error("", e);}if (jsonObject == null) {return reDto;}try {if (reDto instanceof List) {//是集合List list = (List) reDto;List successList = new ArrayList();//循环整个集合for (Object o : list) {Field[] fields = o.getClass().getDeclaredFields();List<Boolean> booleanList = new ArrayList<>();for (Field field : fields) {field.setAccessible(true);Filter annotation = field.getAnnotation(Filter.class);if (annotation != null) {String keyName = annotation.value();Object o1 = jsonObject.get(keyName);//如果获取到了key的话if (!ObjectUtils.isEmpty(o1)) {List list1 = (List) o1;//如果当前记录在记录中的话booleanList.add(list1.contains(field.get(o)));if (list1.contains(field.get(o))) {log.info("key为" + keyName + ":的值【" + field.get(o) + "】在配置的权限中");}}}}if (!booleanList.contains(false)) {//证明这个数据是对的successList.add(o);}}return successList;} else {return reDto;}} catch (Exception e) {log.error("", e);}return reDto;}}

用法

1.需要过滤返回值的方法添加注解@FilterByUser

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2o1ptGjs-1676532488414)(C:\Users\song.cai\AppData\Roaming\Typora\typora-user-images\1676531140607.png)]

2.数据Dto在需要过滤的字段添加@Filter注解,值为数据库中json字段的key

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EKD75W9x-1676532488415)(C:\Users\song.cai\AppData\Roaming\Typora\typora-user-images\1676531216000.png)]

3.数据库中添加一条记录

在这里插入图片描述

4.完成配置的效果

原输出结果

[User(userName=user163122156, dept=部门11, city=北京), 
User(userName=user163122156, dept=部门11, city=上海), 
User(userName=user163122156, dept=部门2, city=上海), 
User(userName=user163122156, dept=部门11, city=深圳)]

加过滤之后输出结果

[User(userName=user163122156, dept=部门11, city=上海)]

实现原理描述

利用@Aspect注解来对切面进行编写,通过注解形式的切入点表达式,对加了@FilterByUser注解的方法进行过滤。利用@Around注解过滤修改原方法的返回值,在切面中通过反射获取原方法返回实体类中加了@Filter注解的字段,通过去查询数据库对该实体类中该字段的值进行比较过滤,多个@Filter需要全部校验通过才放行该对象,否则直接过滤掉不展示。

相关文章:

SpringAOP切面实例实现对数据过滤返回,SpringAOP切面实现对用户权限控制,通过@Around注解过滤修改方法返回值

文章目录需求内容:实现&#xff1a;步骤一&#xff1a;导入SpringAOP相关依赖pom.xml步骤二&#xff1a;自定义两个注解步骤三&#xff1a;需要用到的实体类**步骤四&#xff1a;切面具体实现**用法1.需要过滤返回值的方法添加注解FilterByUser2.数据Dto在需要过滤的字段添加Fi…...

【Kubernetes】【九】Label,Deployment,Service

Label Label是kubernetes系统中的一个重要概念。它的作用就是在资源上添加标识&#xff0c;用来对它们进行区分和选择。 Label的特点&#xff1a; 一个Label会以key/value键值对的形式附加到各种对象上&#xff0c;如Node、Pod、Service等等一个资源对象可以定义任意数量的L…...

RuoYi-Vue部署(Nginx+Tomcat)

环境搭建RuoYi-Vue搭建、Linux安装Nginx、Linux安装JDK8、Linux安装MySql8、Linux安装Redis、Linux安装Tomcat9前端打包 1.ruoyi-ui鼠标右键-->打开于终端2.安装依赖&#xff1a;npm install --registryhttps://registry.npm.taobao.org-->node_modules3.编译打包&#x…...

Hive提升篇-Hive修改事务

简介 Hive 默认是不允许数据更新操作的&#xff0c;毕竟它不擅长&#xff0c;即使在0.14版本后&#xff0c;做一些额外的配置便可开启Hive数据更新操作。而在海量数据场景下做update、delete之类的行级数据操作时&#xff0c;效率并不如意。 简单使用 修改HIVE_HOME/conf/hi…...

PMP项目管理未来的发展与趋势

什么是项目管理&#xff1f;关于项目管理的解释主要是基于国际项目管理三大体系不同的解释及本领域权威专家的解释。 项目管理就是以项目为对象的系统管理方法&#xff0c;通过一个临时性的、专门的柔性组织&#xff0c;对项目进行高效率的计划、组织、指导和控制&#xff0c;以…...

深度学习算法面试常问问题(三)

pooling层是如何进行反向传播的&#xff1f; average pooling&#xff1a; 在前向传播中&#xff0c;就是把一个patch的值取平均传递给下一层的一个像素。因此&#xff0c;在反向传播中&#xff0c;就是把某个像素的值平均分成n份 分配给上一层。 max pooling&#xff1a; 在前…...

GEE学习笔记 八十七:python版GEE动态加载地图方法

在Google Earth Engine的python版API更新后&#xff0c;之前使用folium动态加载地图的代码就不能在正常运行&#xff0c;因为整个Google Earth Engine的地图加载服务的URL发生了更新&#xff0c;所以我们也需要更新相关绘制方法。下面我会讲解一种新的绘制方法&#xff0c;大家…...

第三章 SQL错误信息

文章目录第三章 SQL错误信息SQLCODE 0和100SQLCODE -400检索SQL消息文本第三章 SQL错误信息 下表列出了SQL数字错误代码及其错误消息。这些代码作为SQLCODE变量值返回。 注意&#xff1a;虽然本文档将错误代码列为负值&#xff0c;但JDBC和ODBC客户端始终收到正值。例如&…...

axios中的resolvePromise为什么影响promise状态

axios的取消请求意思很简单&#xff0c;就是在发送请求后不久停止发送请求 本文探讨的是v0.22.0之前的CancelToken API&#xff0c;因为在阅读源码交流的时候发现很多朋友不理解为什么CancelToken中的resolvePromise会影响到实例对象身上的promise状态 即下图所示代码&#xf…...

AWS攻略——创建VPC

文章目录创建一个可以外网访问的VPCCIDR主路由表DestinationTarget主网络ACL入站规则出站规则子网创建EC2测试连接创建互联网网关&#xff08;IGW&#xff09;编辑路由表知识点参考资料在 《AWS攻略——VPC初识》一文中&#xff0c;我们在AWS默认的VPC下部署了一台可以SSH访问的…...

一文搞懂ECU休眠唤醒之利器-TJA1145

前言 首先&#xff0c;小T请教大家几个小小问题&#xff0c;你清楚&#xff1a; 什么是TJA1145吗&#xff1f;你知道休眠唤醒控制基本逻辑是怎么样的吗&#xff1f;TJA1145又是如何控制ECU进行休眠唤醒的呢&#xff1f;使用TJA1145时有哪些注意事项呢&#xff1f; 今天&…...

【Java基础】022 -- Lambda与递归练习

目录 一、Lambda表达式 1、Lambda初体验 2、函数式编程 3、Lambda表达式的标准格式 4、小结 5、Lambda表达式的省略写法 ①、示例代码 ②、小结 6、Lambda表达式的练习 ①、Lambda表达式简化Comparator接口的匿名形式 二、综合练习 1、按照要求进行排序&#xff08…...

技研智联云原生容器化平台实践

作者简介&#xff1a;郑建林&#xff0c;现任深圳市技研智联科技有限公司架构师&#xff0c;技术负责人。多年物联网及金融行业经验&#xff0c;对云计算、区块链、大数据等领域有较深入研究及应用。现主要从事 PaaS 平台建设&#xff0c;为公司各业务产品线提供平台底座如技术…...

订单服务:订单流程

订单流程 订单流程是指从订单产生到完成整个流转的过程&#xff0c;从而行程了一套标准流程规则。而不同的产品类型或业务类型在系统中的流程会千差万别&#xff0c;比如上面提到的线上实物订单和虚拟订单的流程&#xff0c;线上实物订单与 O2O 订单等&#xff0c;所以需要根据…...

Python的有用知识,一共十三个代码片段,确定不来看看吗

前言 之前发过22个小技巧&#xff0c;今天就来分享分享13个非常有用的代码片段 赶紧码住&#xff0c;看看你都了解吗 1.将两个列表合并成一个字典 假设我们在 Python 中有两个列表&#xff0c;我们希望将它们合并为字典形式&#xff0c;其中一个列表的项作为字典的键&#…...

数据结构与算法-数组

前言&#xff1a;几乎所有的编程语言都原生支持数组类型。因为数组是最简单的内存数据结构。创建一个数组&#xff1a;let arr new Array()或let arr new Array(5) // 指定长度或let arr new Array(1,2,3,4,5) // 将数组元素作为参数传给构造函数或let arr [1,2,3,4,5] // …...

PMP证书在哪个行业比较有用?

PMP 各个行业都能用&#xff0c;PMP 的知识体系是通用的&#xff0c;管理层的考试也有借鉴PMP知识的地方。历年考生考的最多的是IT 行业&#xff0c;其他行业也都有分布。PMP认证从国外引进大陆这么多年了&#xff0c;其火热程度依然不减&#xff0c;我个人认为是取决于市场的运…...

Wine零知识学习4 —— Wine编译进阶详解

本系列第3篇文章Wine零知识学习3 —— Winetricks介绍及下载和运行讲述了Wentricks的下载及使用。在Winetricks的使用过程中会发现很多应用下载会出现问题&#xff0c;会提示32位程序无法运行在64位系统上。为什么会出现这个问题&#xff1f;又如何解决此问题&#xff1f;这就是…...

win10-右键打开windows terminal

文章目录windows terminal设置右键打开打开注册表添加一个右键选项新建一个项添加右键的名称和图标右键选项执行的命令测试windows terminal windows 新一代命命令行 设置右键打开 打开注册表 WinR 输入&#xff1a; regedit 定位&#xff1a; 计算机\HKEY_CLASSES_ROOT\Di…...

关于使用CMT2300A FIFO缓存区间设置为64Byte的问题

首先请看&#xff0c;CMT2300A 是什么产品&#xff0c;或者说是 模组吗&#xff1f; 请看介绍&#xff1a; https://blog.csdn.net/sishuihuahua/article/details/105095994 以及RFPDK 的使用: 这博客&#xff0c;记录了 RFPDK 的使用,以及遇到的一些问题 我说一下&#…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI

前一阵子在百度 AI 开发者大会上&#xff0c;看到基于小智 AI DIY 玩具的演示&#xff0c;感觉有点意思&#xff0c;想着自己也来试试。 如果只是想烧录现成的固件&#xff0c;乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外&#xff0c;还提供了基于网页版的 ESP LA…...

MySQL用户和授权

开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务&#xff1a; test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

dify打造数据可视化图表

一、概述 在日常工作和学习中&#xff0c;我们经常需要和数据打交道。无论是分析报告、项目展示&#xff0c;还是简单的数据洞察&#xff0c;一个清晰直观的图表&#xff0c;往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server&#xff0c;由蚂蚁集团 AntV 团队…...

python执行测试用例,allure报乱码且未成功生成报告

allure执行测试用例时显示乱码&#xff1a;‘allure’ &#xfffd;&#xfffd;&#xfffd;&#xfffd;&#xfffd;ڲ&#xfffd;&#xfffd;&#xfffd;&#xfffd;ⲿ&#xfffd;&#xfffd;&#xfffd;Ҳ&#xfffd;&#xfffd;&#xfffd;ǿ&#xfffd;&am…...

Yolov8 目标检测蒸馏学习记录

yolov8系列模型蒸馏基本流程&#xff0c;代码下载&#xff1a;这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中&#xff0c;**知识蒸馏&#xff08;Knowledge Distillation&#xff09;**被广泛应用&#xff0c;作为提升模型…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek

文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama&#xff08;有网络的电脑&#xff09;2.2.3 安装Ollama&#xff08;无网络的电脑&#xff09;2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...

如何更改默认 Crontab 编辑器 ?

在 Linux 领域中&#xff0c;crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用&#xff0c;用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益&#xff0c;允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...

并发编程 - go版

1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程&#xff0c;系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...

Vue ③-生命周期 || 脚手架

生命周期 思考&#xff1a;什么时候可以发送初始化渲染请求&#xff1f;&#xff08;越早越好&#xff09; 什么时候可以开始操作dom&#xff1f;&#xff08;至少dom得渲染出来&#xff09; Vue生命周期&#xff1a; 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...

Vue 模板语句的数据来源

&#x1f9e9; Vue 模板语句的数据来源&#xff1a;全方位解析 Vue 模板&#xff08;<template> 部分&#xff09;中的表达式、指令绑定&#xff08;如 v-bind, v-on&#xff09;和插值&#xff08;{{ }}&#xff09;都在一个特定的作用域内求值。这个作用域由当前 组件…...