JAVA开发(AOP之ProceedingJoinPoint)

news2024/11/19 8:43:30

我们在开发过程中经常使用到自定义注解来实现在一些类或者方法执行过程中切面,统一实现某些业务操作。例如自定义注解

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Map;

@Documented
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface CtgEncrypt {

    /** 参数类型  */
    Class<?> paramType() default Map.class;

    /** 加密类型 (AES/RSA) */
    String securityType() default "AES";

    /**返回参数Request /响应参数Response */
    String reType() default "";

}

注解一般开门见山,说我要干一个什么事情。使用@interface来修饰。例如上面这个注解就是用来对方法上的参数进行加密的。

@Target({ElementType.METHOD,ElementType.TYPE})

这个代码作用的METHOD(方法)上

@Retention(RetentionPolicy.RUNTIME)

这个代码代码运行时执行操作。

自定义的注解需要实现它功能才能用,不是注解了注解本身就有这个功能,没那么强大。

第二步实现注解功能。

import java.util.Arrays;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

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.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;

import com.alibaba.fastjson.JSONObject;

import cn.ctg.common.response.ResponseCode;
import cn.ctg.common.response.ResponseData;
import cn.ctg.common.util.UserTokenUtils;
import cn.ctg.common.util.XssUtils;
import cn.hutool.json.JSONUtil;

/**
 * 切面,实现注解
 */
@Aspect
@Component
public class SecurityAspect {

    @Value("${keys.aeskey:-1}")
    private String AES_KEY;

    @Value("${keys.jwtkey:-1}")
    private String JWT_KEY;

    @Value("${xss.url:-1}")
    private String xxsUrl;

    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    /**切面*/
    @Pointcut("@annotation(cn.ctg.common.util.security.CtgDecrypt) || @annotation(cn.ctg.common.util.security.CtgEncrypt)")
    public void pointCut(){ }

    /**
     *
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("execution(* cn.ctg.*.controller.*.*(..))")
    public Object doAroundHtml(ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] args = joinPoint.getArgs();
        HttpServletRequest httpServletRequest = UserTokenUtils.getHttpServletRequest();
        String requestURI = httpServletRequest.getRequestURI();
        String[] split = xxsUrl.split("\\|");
        if(split==null){
            return joinPoint.proceed(args);
        }
        if(pathMatcher(Arrays.asList(split),requestURI)) {
            for (int i = 0; i < args.length; i++) {
                Object arg = args[i];
                Map<String, Object> map = JSONUtil.parseObj(JSONObject.toJSONString(arg));
                for (Map.Entry<String, Object> entry : map.entrySet()) {
                    if (XssUtils.isStripXSS(entry.getValue().toString())) {
                        ResponseData<Object> responseData = ResponseData.error(ResponseCode.XSS_CODE_ERROR);
                        return responseData;
                    }
                }
            }
        }
        return joinPoint.proceed(args);
    }

    /** 返回参数加密*/
    @Around("pointCut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        //执行方法,获取返回值
        Object result = joinPoint.proceed();
        String data = JSONUtil.toJsonStr(((ResponseData<?>) result).getData());
        if(data.equals("{}")){
            data = String.valueOf(((ResponseData<?>) result).getData());
        }

        /** 可以根据注解选择 加密方法 防止统一*/
        ((ResponseData<?>) result).setEncrypt(true);
        return result;
    }

    // 白名单查询
    private boolean pathMatcher(List<String> urlList, String requestUri) {
        for (String url : urlList) {
            if (antPathMatcher.match(url, requestUri)) {
                return true;
            }
        }
        return false;
    }

}

代码中的这一句 @Pointcut("@annotation(cn.ctg.common.util.security.CtgDecrypt) || @annotation(cn.ctg.common.util.security.CtgEncrypt)")

就是用来实现CtgEncrypt这个注解的

再使用@Around("pointCut()")进行方法环绕。实现注解的动作。

    /** 返回参数加密*/
    @Around("pointCut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        //执行方法,获取返回值
        Object result = joinPoint.proceed();
        String data = JSONUtil.toJsonStr(((ResponseData<?>) result).getData());
        if(data.equals("{}")){
            data = String.valueOf(((ResponseData<?>) result).getData());
        }

        /** 可以根据注解选择 加密方法 防止统一*/
        ((ResponseData<?>) result).setEncrypt(true);
        return result;
    }

这是我们看到一个重要类型ProceedingJoinPoint。执行当前切点的意思

这里就通过源码看看ProceedingJoinPoint能做什么东西。

/*******************************************************************************
 * Copyright (c) 2005 Contributors.
 * All rights reserved.
 * This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution and is available at
 * http://eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 * initial implementation              Alexandre Vasseur
 *******************************************************************************/
package org.aspectj.lang;

import org.aspectj.runtime.internal.AroundClosure;

/**
 * ProceedingJoinPoint exposes the proceed(..) method in order to support around advice in @AJ aspects
 *
 * @author Alexandre Vasseur
 */
public interface ProceedingJoinPoint extends JoinPoint {

    /**
     * The joinpoint needs to know about its closure so that proceed can delegate to closure.run().
     * This internal method should not be called directly, and won't be visible to the end-user when
     * packed in a jar (synthetic method).
     *
     * @param arc the around closure to associate with this joinpoint
     */
    void set$AroundClosure(AroundClosure arc);

    /**
     * The joinpoint needs to know about its closure so that proceed can delegate to closure.run().
     * This internal method should not be called directly, and won't be visible to the end-user when
     * packed in a jar (synthetic method). This should maintain a stack of closures as multiple around
     * advice with proceed are targeting a joinpoint and the stack will need to be unwound when
     * exiting nested advice. Passing a non null arc indicates a push, passing null indicates a pop.
     *
     * @param arc the around closure to associate with this joinpoint
     */
     default void stack$AroundClosure(AroundClosure arc) {
         throw new UnsupportedOperationException();
     }

    /**
     * Proceed with the next advice or target method invocation
     *
     * @return the result of proceeding
     * @throws Throwable if the invoked proceed throws anything
     */
    public Object proceed() throws Throwable;

    /**
     * Proceed with the next advice or target method invocation.
     *
     * Unlike code style, proceed(..) in annotation style places different requirements on the 
     * parameters passed to it.  The proceed(..) call takes, in this order:
     * <ul>
     * <li> If 'this()' was used in the pointcut for binding, it must be passed first in proceed(..).
     * <li> If 'target()' was used in the pointcut for binding, it must be passed next in proceed(..) - 
     * it will be the first argument to proceed(..) if this() was not used for binding.
     * <li> Finally come all the arguments expected at the join point, in the order they are supplied 
     * at the join point. Effectively the advice signature is ignored - it doesn't matter 
     * if a subset of arguments were bound or the ordering was changed in the advice signature, 
     * the proceed(..) calls takes all of them in the right order for the join point. 
     * </ul>
     * Since proceed(..) in this case takes an Object array, AspectJ cannot do as much 
     * compile time checking as it can for code style. If the rules above aren't obeyed 
     * then it will unfortunately manifest as a runtime error. 
     *
     * @param args the arguments to proceed with
     * @return the result of proceeding
     * @throws Throwable if the invoked proceed throws anything
     */
    public Object proceed(Object[] args) throws Throwable;

}


从源码上继承了JoinPoint

public Object proceed() throws Throwable;

Proceed with the next advice or target method invocation

继续执行下一个通知或目标方法调用

获取当前正在执行的对象(如果不可用则为空——例如静态上下文)

Object getThis();

获取目标对象(如果没有,则为空)

Object getTarget();

获取这个连接点上的参数

Object[] getArgs();

获取连接点上的签名。

Signature getSignature();

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

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

相关文章

YOLOv7:面向实时检测的目标检测器 | 附结构图

YOLOv7 在 5 FPS 到 160 FPS 范围内的速度和准确度都超过了所有已知的目标检测器&#xff0c;并且在 GPU V100 上 30 FPS 或更高的所有已知实时目标检测器中具有最高的准确度 56.8% AP。 YOLOv7-E6 目标检测器&#xff08;56 FPS V100&#xff0c;55.9% AP&#xff09;比基于Tr…

小孩护眼灯什么牌子的好?分享四款最好的台灯品牌

最近发现&#xff0c;在接送我家神兽上下学时&#xff0c;小朋友们会揉眼睛&#xff0c;眼睛始终没睁开的感觉&#xff0c;还有不少小学就戴上了眼镜&#xff0c;我深知戴眼镜&#xff0c;真的很麻烦&#xff0c;所以更加看重孩子的护眼工作。市面上越来越多护眼灯&#xff0c;…

Java高手速成 | 实现人物拼图游戏

拼图游戏指将一幅图片分割成若干拼块&#xff0c;并随机打乱顺序&#xff0c;当将所有拼块都放回原位置时就完成了拼图(游戏结束)。 01、游戏介绍 在游戏中&#xff0c;拼块以随机顺序排列&#xff0c;网格上有一个位置是空的。完成拼图的方法是利用这个空位置移动拼块&#xf…

服务搭建常见问题

怎么将myeclipse项目部署到tomcat服务器 https://www.laike.net/article-162-238315-0.html eclipse提示错误&#xff1a;save could not be completed Dynamic Web Module 4.0 requires Java 1.8 or newer. https://blog.csdn.net/xixihaha_coder/article/details/118345378 …

微星 MPG B460I GAMING EDGE WIFI +i5-10400电脑 Hackintosh 黑苹果efi引导文件

硬件型号驱动情况主板微星 MPG B460I GAMING EDGE WIFI (MS-7C86)&#xff08;LPC Controller B460芯片组&#xff09;处理器英特尔 Core i5-10400 2.90GHz 六核已驱动内存16 GB ( 芝奇 DDR4 2666MHz 8GB x 2 )已驱动硬盘朗科科技 NVMe SSD 480GB (480 GB / 固态硬盘)已驱动显…

React学习笔记:实用又好用的Hooks函数

React框架以前是采用Class类编程&#xff0c;在类编程中使用生命周期比较方便&#xff0c;但是随着迭代更新&#xff0c;官方开始推荐使用函数式编程&#xff0c;但是函数式编程就没有状态这一个概念&#xff0c;于是乎官方就定义了一系列钩子函数来弥补在这一缺陷&#xff0c;…

Rabbitmq(七) -- rabbitmq的工作模式

1. 简单模式&#xff1a;无需交换机 消息产生消息&#xff0c;将消息放入队列消息的消费者(consumer) 监听 消息队列,如果队列中有消息,就消费掉,消息被拿走后,自动从队列中删除(隐患 消息可能没有被消费者正确处理,已经从队列中消失了,造成消息的丢失&#xff0c;这里可以设置…

VTK-数据集vtkUnstructuredGrid

前言&#xff1a;本博文主要介绍vtkUnstructuredGrid的特点、结构组成&#xff0c;vtkUnstructuredGrid的创建方法&#xff0c;及其vtkUnstructuredGrid相关的接口及示例。 特点 非结构化网格数据&#xff0c;是最常见的数据集类型&#xff0c;它的拓扑结构和几何结构都是非结…

Pycharm调试功能介绍

文章目录pycharm中的debug模式debug的断点调试pycharm中的debug模式 在pycharm中&#xff0c;一共有4中方法开启debug调试&#xff0c;如下&#xff1a; 点击导航栏的run >> debug 双击打开py文件 >> 右上角点击小虫子图标。 写好if name ‘main’: >> 点…

React 类组件你不知道的细节+案例

React基础-组件-类组件 1.组件概述 目标&#xff1a;了解React组件的作用和创建组件的方式 什么是组件组件的设计思想 1.what is 组件啊&#xff1f; 在前端开发中组件就是用户界面当中一块独立的区域,在组件内部会包含这块区域中的视图代码,样式代码以及逻辑代码 React是采用…

Cadence PCB仿真使用Allegro PCB SI配置差分对的方法图文教程

⏪《上一篇》   🏡《总目录》   ⏩《下一篇》 目录 1,概述2,配置方法3,总结1,概述 本文简单介绍使用Allegro PCB SI配置差分对的方法。 2,配置方法 第1步:打开待仿真的PCB文件,并确认软件为Allegro PCB SI 如果,打开软件不是Allegro PCB SI则可这样切换 执行Fil…

天下苦“个人公众号认证”久矣,吾闻今可

大家好&#xff0c;我是小悟 一看到个人公众号可以认证&#xff0c;便以迅雷不及掩耳之势准备资料&#xff0c;一顿操作猛如虎后&#xff0c;我的号终于认证啦。 看到别人的个人公众号有认证的&#xff0c;这两天我就在想要怎么才能认证&#xff0c;于是就去搜索相关的内容&am…

电子采购系统的优势是什么 常用的电子采购系统介绍

采购是企业发展中的重要环节之一。在企业采购流程中&#xff0c;并不是简单的完成买和卖就行了&#xff0c;这其中还会涉及到各个方面。例如&#xff0c;在企业采购活动中&#xff0c;常常会遇到供应商数据维护难&#xff0c;采购成本把控难&#xff0c;供应商筛选难等问题。而…

面对集中式缓存实现上的挑战,Redis交出的是何种答卷?聊聊Redis在分布式方面的能力设计

大家好&#xff0c;又见面了。 本文是笔者作为掘金技术社区签约作者的身份输出的缓存专栏系列内容&#xff0c;将会通过系列专题&#xff0c;讲清楚缓存的方方面面。如果感兴趣&#xff0c;欢迎关注以获取后续更新。 在本专栏前面的文章中&#xff0c;我们介绍了各种本地缓存框…

数据结构与算法1—线性表

1. 线性表的定义 线性表L是n&#xff08;n≥0&#xff09;个具有相同属性的数据元素a1&#xff0c;a2&#xff0c;a3&#xff0c;…&#xff0c;an组成的有限序列&#xff0c;其中序列中元素的个数n称为线性表的长度。当n0时称为空表&#xff0c;即不含有任何元素。常常将非空…

express接口

文章目录什么是接口创建 API 路由模块编写 GET 接口编写 POST 接口完整代码CORS 跨域资源共享使用 CORS 中间件解决跨域问题实现 JSONP 接口什么是接口 API (Application Programming Interface&#xff0c;应用程序编程接口 ) 是一些预先定义的函数&#xff0c;目的是提供应用…

TCP/IP 网络模型有哪几层

备注&#xff1a;本文参考小林coding相关内容&#xff0c;侵权请联系作者删除 1.应用层 最上层的&#xff0c;也是我们能直接接触到的就是应用层&#xff08;Application Layer&#xff09;&#xff0c;我们电脑或手机使用的应用软件都是在应用层实现。那么&#xff0c;当两个…

高并发系统设计 -- 登录系统设计

同源策略 同源策略是一种安全策略。是游览器最核心最基本的安全功能。防止XSS&#xff0c;CSFR等攻击具体表现是游览器在执行脚本之前&#xff0c;会判断脚本是否与打开的网页是同源的&#xff0c;也就是协议&#xff0c;域名&#xff0c;端口是否都相同&#xff0c;相同就是同…

记录--前端性能监控初步实战

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 前言 在当下前后端分离的主流环境下&#xff0c;前端部分的优化变得越来越重要。为了提升前端的性能和用户体验&#xff0c;我觉得可能需要从三个维度采集数据进行分析。 前端埋点。通过埋点收集和统计…

SCRM与CRM的区别

当私域流量的概念兴起时&#xff0c;企业直接触达用户的场景也越来越丰富&#xff0c;SCRM形式的私域运营已然成为很多企业数字化转型布局的关键阵地。 前言 当私域流量的概念兴起时&#xff0c;企业直接触达用户的场景也越来越丰富&#xff0c;SCRM形式的私域运营已然成为很多…