AOP的另类用法 (权限校验自定义注解)

news2024/9/21 18:57:18

👳我亲爱的各位大佬们好😘😘😘
♨️本篇文章记录的为 AOP的另类用法 (权限校验&&自定义注解) 相关内容,适合在学Java的小白,帮助新手快速上手,也适合复习中,面试中的大佬🙉🙉🙉。
♨️如果文章有什么需要改进的地方还请大佬不吝赐教❤️🧡💛
👨‍🔧 个人主页 : 阿千弟
🔥 上期内容👉👉👉 : “速通“ 老生常谈的HashMap [实现原理&&源码解读]

前言 :

告别了OOP编程, 迎来了一个新的AOP编程时代👍👍👍, 最近有同学问我AOP除了写日志还能干什么, 其实AOP能干的事情挺多的, 可能只是他们写的代码中暂时用不到. 其实如果当我们写一些简单的程序的时候, SpringSecurity完全用不到的时候, 就可以使用AOP与自定义注解来为角色的访问权限进行鉴定, 绝对比Security更轻量👉👉👉.

在这里插入图片描述

文章目录

    • 前言 :
    • 自定义注解
    • AOP回顾
      • 基本概念
      • 声明一个切入点
      • 切入点指示器(PCD)
      • 基本通知
      • 通知的参数
    • AOP整合自定义注解校验接口权限
      • 引入依赖
      • 自定义注解
      • 定义切面
      • AopController
      • 测试结果

自定义注解

我们在接触框架的时候经常会用到注解, 但是我们自己自定义注解的情况比较少, 一般都是配合切面编程使用

自定义一个注解非常简单, 它就和创建一个接口一样, 如果我们创建的是一个接口的话, 那么就用interface关键字表示, 如果我们是要自定义一个注解, 那么就在interface关键字前面加上一个@符号

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface HasRole {
	String name() default "";
    String value() default "";
}
  1. 自定义注解里面还存在一些属性, 这些属性有点类似与我们的抽象方法, 是不能加方法体的, 加了是会报错的

在这里插入图片描述

  1. 自定义的属性是可以赋默认值的
// name的默认值是 ""
String name() default "";
  1. 它的返回类型必须是基础类型或者是String类型, 不可以是封装类型

  2. @Target标志自定义的注解的作用范围

类型作用范围
TYPE允许被修饰的注解作用在类, 接口和枚举上
FIELD允许作用在属性字段上
METHOD允许作用在方法上
PARAMETER允许作用在方法参数上
CONSTRUCTOR允许作用在构造器上
LOCAL_VARIABLE允许作用在本地局部变量上
ANNOTATION_TYPE允许作用在注解上
PACKAGE允许作用在包上

5. @Retention 标志自定义的作用是定义被它所注解的注解保留多久(生命周期)

一共有三种策略,定义在 RetentionPolicy 枚举中. 从注释上看:

类型解释
source注解只保留在源文件,当 Java 文件编译成 cláss 文件的时候,注解被遗弃;被编译器忽略
class注解被保留到 class 文件,但 jvm 加载 class 文件时候被遗弃,这是默认的生命周期
runtime注解不仅被保存到 class 文件中,jym 加载 class 文件之后,仍然存在

AOP回顾

基本概念

  1. Aspect(切面): 一个关注点的模块化,这个关注点可能会横切多个对象。事务管理是J2EE应用中一个关于横切关注点的很好的例子。
  2. Join point(连接点 ): 在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。
  3. Advice(通知): 在切面的某个特定的连接点(Joinpoint)上执行的动作。通知有各种类型,其中包括“around”、“before”和“after”等通知。 通知的类型将在后面部分进行讨论。许多AOP框架,包括Spring,都是以拦截器做通知模型, 并维护一个以连接点为中心的拦截器链。
  4. Pointcut(切入点 ): 匹配连接点(Joinpoint)的断言。通知和一个【切入点表】达式关联,并在满足这个切入点的连接点上运行。 【切入点表达式如何和连接点匹配】是AOP的核心:Spring缺省使用AspectJ切入点语法。
  5. Introduction(引入): Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象。例如,你可以使用一个引入来使bean实现 IsModified 接口,以便简化缓存机制。
  6. Target object(目标对象):被一个或者多个切面(aspect)所通知(advise)的对象。也有人把它叫做 被通知(advised) 对象。 既然Spring AOP是通过运行时代理实现的,这个对象永远是一个 被代理(proxied) 对象。
  7. AOP代理 AOP proxy: 在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。
    8 . Weaving(织入) : 把切面(aspect)连接到其它的应用程序类型或者对象上,并创建一个被通知(advised)的对象,这个过程叫织入。 这些可以在编译时(例如使用AspectJ编译器),类加载时和运行时完成。 Spring和其他纯Java AOP框架一样,在运行时完成织入。

声明一个切入点

【切入点确定感兴趣的连接点】,从而使我们能够控制通知何时运行。

切入点声明由两部分组成:包含【名称和方法签名】,以及确定我们感兴趣的方法执行的【切入点表达式】。

怎么确定一个方法:public void com.ddd.service.impl.*(…)

@Pointcut("execution(* transfer(..))") // the pointcut expression
private void anyOldTransfer() {} // the pointcut signature

切入点指示器(PCD)

这里只先回顾一下这两个常用的注解

@execution: (常用)用于匹配方法执行的连接点,这是在使用Spring AOP时使用的主要切入点指示符。(匹配方法)

模式描述
public * *(…)任何公共方法的执行
cn.javass…IPointcutService.*()cn.javass包及所有子包下IPointcutService接口中的任何无参方法
cn.javass….*(…)cn.javass包及所有子包下任何类的任何方法
cn.javass…IPointcutService.(*)cn.javass包及所有子包下IPointcutService接口的任何只有一个参数方法
(!cn.javass…IPointcutService+).(…)非“cn.javass包及所有子包下IPointcutService接口及子类型”的任何方法
cn.javass…IPointcutService+.()cn.javass包及所有子包下IPointcutService接口及子类型的的任何无参方法
cn.javass…IPointcut.test*(java.util.Date)cn.javass包及所有子包下IPointcut前缀类型的的以test开头的只有一个参数类型为java.util.Date的方法,注意该匹配是根据方法签名的参数类型进行匹配的,而不是根据执行时传入的参数类型决定的.如定义方法:public void test(Object obj);即使执行时传入java.util.Date,也不会匹配的;

@annotation: (常用)于匹配当前执行方法持有指定注解的方法。(方法上的注解)

在这里插入图片描述

基本通知

注解说明
@Before前置通知,在被切的方法执行前执行
@After后置通知,在被切的方法执行后执行,比return更后
@AfterRunning返回通知,在被切的方法return后执行
@AfterThrowing异常通知,在被切的方法抛异常时执行
@Around环绕通知,这是功能最强大的Advice,可以自定义执行顺序

通知的参数

任何通知方法都可以声明一个类型为【org.aspectj.lang.JoinPoint】的参数作为它的【第一个参数】(注意,around通知需要声明类型为( ProceedingJoinPoint )的第一个参数,它是【JoinPoint】的一个子类。 【JoinPoint】接口提供了许多有用的方法:

  • getArgs(): 返回方法参数。
  • getThis(): 返回代理对象。
  • getTarget(): 返回目标对象。
  • getSignature(): 返回被通知的方法的签名。
  • toString(): 打印被建议的方法的有用描述。

在这里插入图片描述

AOP整合自定义注解校验接口权限

在我们的业务开发中, 常常会遇到这样的问题 : 每当我们进行一个对数据库的操作, 通常需要鉴权用户是否具有一个正确的访问权限, 然而每次都对不同的业务流程中添加相同的鉴权的执行流程, 势必会造成代码的冗余, 而且也不利于后期代码的拓展

这时候我们可以对鉴权的业务进行切点织入, 织入切面, 化繁为简

引入依赖

pom.xml

	<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>29.0-jre</version>
    </dependency>

自定义注解

这里先模拟一个缓存的类, 因为在真实业务交易权限的过程中我们一般都是把查出的用户数据放在缓存中, 以至于不用每次使用用户信息时都需要从数据库中查询

public class CacheManager {


    //保存用户和具有的角色之间对应关系
    public static final Map<String, Set<String>> USER_ROLE_MAP = new HashMap<>();

    static{

        //用户zhangsan具有user和admin两个角色
        Set<String> roleSet3 = Sets.newHashSet("admin","user");
        USER_ROLE_MAP.put("zhangsan",roleSet3);

        //用户lisi具有user一个角色
        Set<String> roleSet4 = Sets.newHashSet("user");
        USER_ROLE_MAP.put("lisi",roleSet4);

    }

}

定义切面

【编写方法】声明一个切入点,该切入点在匹配连接点时“提供”‘Account’对象值,然后从通知中引用指定的切入点

@Component
@Aspect
public class AopConfig {

    //定义一个切点(通过注解)
    @Pointcut("@annotation(com.example.aopdemo.annotation.HasRole))")
    public void pointcut(){}


    //前置通知
    @Before("pointcut()")
    public void before(JoinPoint joinPoint){
        System.out.println("before-------------");

        //获取到HttpServletRequest,ThreadLocal
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
        HttpServletRequest request = servletRequestAttributes.getRequest();

        String username = request.getParameter("username");


        //获取当前用户的角色集合
        Set<String> userRoles = CacheManager.USER_ROLE_MAP.get(username);

        //获取当前请求的方法上的注解hasRole中设置的角色
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();

        //反射获取当前被调用的方法
        Method method = signature.getMethod();

        //判断当前方法是否有hasRole注解
        //如果有,判断是否用户具有注解属性中要求的角色
        //如果没有hasRole注解,那么说明方法不需要判断用户的角色,可以匿名访问
        HasRole hasRole = method.getDeclaredAnnotation(HasRole.class);
        if(hasRole != null && (userRoles == null || !userRoles.contains(hasRole.value()))){
            throw new RuntimeException("用户没有访问权限");
        }

    }
}

这里只是配置了一个固定的注解再在pointcut上,是不需要判断的。但是如果我们不是指定某一个具体的注解的话,那么需要增加判断。因为我们的前置通知里面除了判断接口权限,还可以做很多其他的事情

AopController

@RestController
public class AopController {

    //访问这个方法需要用户具有admin的角色
    @HasRole("admin")
    @GetMapping("query1")
    public String query1(){
        return "query1 需要 admin 角色";
    }

    //访问这个方法需要用户具有user的角色
    @HasRole("user")
    @GetMapping("query2")
    public String query2(){
        return "query2 需要 user 角色";
    }

    //任何用户都可以访问
    @GetMapping("query3")
    public String query3(){
        return "query3 可以匿名访问";
    }
}

测试结果

测试1

在这里插入图片描述
在这里插入图片描述
因为我们本次的传参是username=lbw, 然而lbw并没有admin权限, 所以此时我们的AOP生效进行拦截

测试2

在这里插入图片描述
测试3

在这里插入图片描述
这里可以匿名访问是因为, 我们并没有在query3方法上添加@HasRole注解, 这时请求的参数不会走AOP, AOP拦截不生效, 所以可以匿名访问

在这里插入图片描述

如果这篇【文章】有帮助到你💖,希望可以给我点个赞👍,创作不易,如果有对Java后端或者对spring感兴趣的朋友,请多多关注💖💖💖
👨‍🔧 个人主页 : 阿千弟

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/393193.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

磁盘存储和文件系统管理

磁盘存储和文件系统管理1. 磁盘结构1.1设备文件1. 设备类型&#xff1a;2. 磁盘设备的设备文件命名&#xff1a;3. 虚拟磁盘&#xff1a;4. 不同磁盘标识&#xff1a;a-z,aa,ab…5. 同一设备上的不同分区&#xff1a;1,2, ...6. 创建设备文件7. 工具 dd常用选项示例demo8. hexd…

maven的安装配置

目录 1. Maven的安装配置 1.1检测jdk的版本 1.2下载maven 1.3配置maven环境变量 2.认识maven的目录结构 2.1 创建一个文件夹作为项目的根目录 1.创建如下结构的目录 2. 在pom.xml文件中写入如下内容(不用记忆) 3.在mian-->java--》下边创建java文件​编辑 4.cmd下…

XGboost部分细节补充

XGBoost算法原理详解与参数详解 R语言XGBoost参数详解 XGBoost部分细节补充1. XGBoost线性模型的实现2.XGBoost对二分类和多分类的处理方法1. XGBoost线性模型的实现 前面文章中已经详细的介绍了XGBoost基于决策树的实现&#xff0c;今天我们主要介绍XGBoost基于线性模型的实现…

模式识别 —— 第二章 参数估计

模式识别 —— 第二章 参数估计 文章目录模式识别 —— 第二章 参数估计最大似然估计&#xff08;MLE&#xff09;最大后验概率估计&#xff08;MAP&#xff09;贝叶斯估计最大似然估计&#xff08;MLE&#xff09; 在语言上&#xff1a; 似然&#xff08;likelihood&#xf…

【Git】P1 Git 基础

Git 基础Git 基本概念集中式版本控制工具 与 分布式版本控制工具Git 下载与安装Bash 初始设置创建本地仓库Git 三区概念一个简单的提交流程更改文件后再次提交git 实现版本切换查看提交日志设置 git 快捷键版本切换&#xff08;一&#xff09;版本切换&#xff08;二&#xff0…

华为OD机试题,用 Java 解【数据分类】问题

华为Od必看系列 华为OD机试 全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典使用说明 参加华为od机试,一定要注意不…

0104路径搜索和单点路径-无向图-数据结构和算法(Java)

文章目录2 单点路径2.1 API2.2 算法实现后记2 单点路径 单点路径。给定一幅图和一个起点s&#xff0c;回答“从s到给定的目的顶点v是否存在一条路径&#xff1f;如果有&#xff0c;找出这条路径。”等类似问题。 2.1 API 单点路径问题在图的处理邻域中十分重要。根据标准设计…

PHP, Python和Java的区别

PHP, Python和Java是广泛使用的编程语言。每种编程语言都有其独特的优点和缺点。在本文中&#xff0c;我们将对这些编程语言进行分析&#xff0c;并探讨它们在不同应用场景中的最佳用途。一、PHPPHP是一种广泛使用的Web编程语言&#xff0c;它可以在服务器上运行&#xff0c;并…

程设 | week2:STL

&#x1f4da;回顾C &#x1f407;struct和class 从功能上说&#xff0c;struct和class几乎没什么区别在不显式声明的情况下&#xff0c;struct成员默认为public&#xff0c;class默认为private和c语言的struct不同&#xff0c;c的struct可以定义成员函数&#xff0c;重载运算…

G6绘制树形图(自定义节点、自定义边、自定义布局)

目录1 设计节点1.1 定义节点和文本1.2 增加节点1.3 自定义节点样式2 树图配置2.1 允许使用自定义dom节点2.2 内置行为自定义边layout布局demo1 设计节点 在 registerNode 中定义所有的节点 G6.registerNode(tree-node, {drawShape: function drawShape(cfg, group) {定义图中…

aws appconfig 理解和使用appconfig对应用程序进行动态配置

参考资料 Automating Feature Release using AWS AppConfig Integration with AWS CodepipelineDeploying application configuration to serverless: Introducing the AWS AppConfig Lambda extensionCreate a pipeline that uses Amazon AppConfig as a deployment provider…

秒懂算法 | 搜索基础

本篇介绍了BFS和DFS的概念、性质、模板代码。 01、搜索简介 搜索,就是查找解空间,它是“暴力法”算法思想的具体实现。 暴力法(Brute force,又译为蛮力法):把所有可能的情况都罗列出来,然后逐一检查,从中找到答案。这种方法简单、直接,不玩花样,利用了计算机强大的…

JavaScript 中的 String 类型 模板字面量定义字符串

ECMAScript 6新增了使用模板字面量定义字符串的能力。与使用单引号或双引号不同&#xff0c;模板字面量保留换行字符&#xff0c;可以跨行定义字符串&#xff1a; let str1 早起的年轻人\n喜欢经常跳步;let str2 早起的年轻人喜欢经常跳步;console.log(str1);// 早起的年轻人…

【游戏逆向】游戏玩家技能冷却分析

技能冷却对于不同的游戏有不同的存放方式,而技能冷却的遍历也大多不会和技能的普通属性放在一起,在《在**明月刀》这款游戏中,技能的冷却判断格外重要,因为技能的连贯性对打怪的效率影响很大。 我们需要找一个冷却相对较长的技能用来进行扫描和过滤,一般选择几十秒即可,…

【本周特惠课程】基于GAN的图像增强理论与实践(涵盖图像降噪、色调映射、去模糊、超分辨、修复等方向)...

前言欢迎大家关注有三AI的视频课程系列&#xff0c;我们的视频课程系列共分为5层境界&#xff0c;内容和学习路线图如下&#xff1a;第1层&#xff1a;掌握学习算法必要的预备知识&#xff0c;包括Python编程&#xff0c;深度学习基础&#xff0c;数据使用&#xff0c;框架使用…

Windows扫描工具RunScanner使用实验(21)

实验目的 掌握利用Runscanner扫描和分析电脑&#xff1b;预备知识 RunScanner是一个完全免费的Windows系统工具,您可以用它轻松地将隐藏在您系统中的autostart程序,spyware,adware,主页劫持,未经认证的驱动揪出来,并可以导入和导出报告以帮助别人或获取帮助.目前它可以…

华为OD机试题,用 Java 解【素数之积】问题

华为Od必看系列 华为OD机试 全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典使用说明 参加华为od机试,一定要注意不…

C++中的利器——模板

前文本文主要是讲解一下C中的利器——模板&#xff0c;相信铁子们在学完这一节后&#xff0c;写代码会更加的得心应手&#xff0c;更加的顺畅。一&#xff0c;泛型编程想要学习模板&#xff0c;我们要先了解为什么需要模板&#xff0c;我们可以看看下面这个程序。int add(int&a…

MDK Keil5 创建Stm32工程-理论篇(这里以Stm32F103Zet6为例)

一、文件夹创建与文件说明整个工程可以粗略的划分为几个文件夹&#xff1a;BSP底层驱动比如GPIO\Timer等驱动文件CMSIS内核相关的文件Firmware生成的固件下载文件Mycode用户编写的相关文件&#xff0c;主要编写的文件都在这个文件夹里Project工程文件startup芯片启动文件STM32F…

1.C#与.NET简介

目录 一、C#语言及其特点 二、C#与.NET Framework/.NET Core关系 三、C#应用开发 四、案例展示 五、学习环境 一、C#语言及其特点 C#是美国微软公司发布的一种面向对象的&#xff0c;运行于 .NET Framework 和 .NET Core &#xff08;完全开源&#xff0c;跨平台&#xff…