从ProceedingJoinPoint检索参数值

问题描述 投票:9回答:3

在我的请求中,我有一个参数名称“ accessToken”,如何从ProceedingJoinPoint中获取请求参数值?

public Object handleAccessToken(ProceedingJoinPoint joinPoint) throws Throwable { 
    final Signature signature = joinPoint.getStaticPart().getSignature();
    if (signature instanceof MethodSignature) {
        final MethodSignature ms = (MethodSignature) signature;
        String[] params = ms.getParameterNames();
        for (String param : params) {
            System.out.println(param);
            // here how do i get parameter value using param ?
        }
    }
}

调用方法:

public MyResponse saveUser(
    @RequestParam("accessToken") String accessToken,
    @RequestBody final UserDto userDto
) {
    // code 
}

我想在AOP中获得此访问令牌。

提前感谢。

aop spring-aop spring-aspects
3个回答
24
投票

[好,Shamseer,我只有一点空闲时间,所以我试图回答您的问题,而不让您回答我的所有评论。我这样做的方法是,我将not使用参数名称,但是尝试在带有注释@RequestParam("accessToken")的参数上进行匹配,即,我将在注释类型和值上使用魔术名称进行匹配“ accessToken”的名称,而不是方法参数名称,该名称可能会由于不知道您的方面的人的简单重构,由于在编译过程中从类文件中删除调试信息或混淆而可能改变。

这里有一些自洽的示例代码,它们是针对AspectJ而不是Spring AOP进行测试的,但是后者的语法还是前者语法的子集:

带有主方法的示例类:

[共有三种方法,所有这些方法都在其中一个参数上带有@RequestParam批注,但是其中只有两个具有魔术值“ accessToken”。无论参数类型如何(一个String和一个int),它们都应该匹配,但是不匹配@RequestParam("someParameter")的参数。严格来说,所有方法执行都是匹配的,但是运行时反射消除了不需要的执行。如果您的注释位于类或方法级别或参数类型上,我们可以在切入点中将它们直接匹配而无需反射,但是在参数注释的情况下,这超出了AspectJ的当前(v1.8.4)功能,我们必须使用反射,很不幸。

package de.scrum_master.app;

import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

public class MyResponse {
    public MyResponse saveUser(
        @RequestParam("accessToken") String accessToken,
        @RequestBody final UserDto userDto
    ) {
        return this;
    }

    public MyResponse doSomething(
        @RequestParam("someParameter") String text,
        @RequestBody final UserDto userDto
    ) {
        return this;
    }

    public MyResponse doSomethingElse(
        @RequestParam("accessToken") int number
    ) {
        return this;
    }

    public static void main(String[] args) {
        MyResponse myResponse = new MyResponse();
        myResponse.doSomething("I am not a token", new UserDto());
        myResponse.saveUser("I am a token", new UserDto());
        myResponse.doSomethingElse(12345);
    }
}

虚拟助手类,使代码编译:

package de.scrum_master.app;

public class UserDto {}

方面:

[请注意,我的综合切入点execution(* *(..))仅用于说明。您应该将其范围缩小到实际需要的方法。

package de.scrum_master.aspect;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.web.bind.annotation.RequestParam;

@Aspect
public class AccessTokenAspect {
    @Around("execution(* *(..))")
    public Object handleAccessToken(ProceedingJoinPoint thisJoinPoint) throws Throwable {
        System.out.println(thisJoinPoint);
        Object[] args = thisJoinPoint.getArgs();
        MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getStaticPart().getSignature();
        Method method = methodSignature.getMethod();
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        assert args.length == parameterAnnotations.length;
        for (int argIndex = 0; argIndex < args.length; argIndex++) {
            for (Annotation annotation : parameterAnnotations[argIndex]) {
                if (!(annotation instanceof RequestParam))
                    continue;
                RequestParam requestParam = (RequestParam) annotation;
                if (! "accessToken".equals(requestParam.value()))
                    continue;
                System.out.println("  " + requestParam.value() + " = " + args[argIndex]);
            }
        }
        return thisJoinPoint.proceed();
    }
}

控制台输出:

execution(void de.scrum_master.app.MyResponse.main(String[]))
execution(MyResponse de.scrum_master.app.MyResponse.doSomething(String, UserDto))
execution(MyResponse de.scrum_master.app.MyResponse.saveUser(String, UserDto))
  accessToken = I am a token
execution(MyResponse de.scrum_master.app.MyResponse.doSomethingElse(int))
  accessToken = 12345

另请参见this answer有关一个相似但代码简单的问题。


7
投票

要获取作为方法参数的参数,可以尝试以下操作:

Object[] methodArguments = joinPoint.getArgs();

0
投票

如果使用@Aspect,则可以在Aspect中添加此方法,并发送JoinPoint和所需参数的名称。

private Object getParameter(ProceedingJoinPoint joinPoint, String parameterName) {
    Object valueParameter = null;
    if (Objects.nonNull(joinPoint) && joinPoint.getSignature() instanceof MethodSignature
            && Objects.nonNull(parameterName) ) {
        MethodSignature method = (MethodSignature)joinPoint.getSignature();
        String[] parameters = method.getParameterNames();
        for (int t = 0; t< parameters.length; t++) {
            if( Objects.nonNull(parameters[t]) && parameters[t].equals(parameterName)) {
                Object[] obj = joinPoint.getArgs();
                valueParameter = obj[t];
            }
        }
    }
    return valueParameter;
}

以及通话示例:

Object parameterObject = getParameter(joinPoint, "nameClient");
if ( Objects.nonNull(parameterObject) ) {
    String parametro = String.valueOf(parameterObject);
}

只需要知道要转换的对象的类型

© www.soinside.com 2019 - 2024. All rights reserved.