11

在我的请求中,我有一个参数名称“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 中获取这个访问令牌。

提前致谢。

4

2 回答 2

27

好的,Shamseer,我只是有一点空闲时间,所以我试图回答你的问题,而不是你从我的评论中回答我的所有问题。我这样做的方法是我不会使用参数名称,而是尝试使用注释匹配参数@RequestParam("accessToken"),即我将使用“accessToken”的魔术名称而不是方法参数名称来匹配注释类型和值由于在编译期间从类文件中剥离调试信息或由于混淆,可能会由于不了解您方面的人的简单重构而改变。

这是一些针对 AspectJ 而不是 Spring AOP 测试的自洽示例代码,但后者的语法无论如何都是前者语法的子集:

带有 main 方法的示例类:

共有三种方法,它们都@RequestParam在其中一个参数上带有注解,但其中只有两个具有“accessToken”的神奇值。String无论参数类型如何( one和 one int),它们都应该匹配,但@RequestParam("someParameter")不应匹配 with 。严格来说,所有方法执行都是匹配的,但运行时反射会消除不想要的。如果您的注释将在类或方法级别或参数类型上,我们可以直接在切入点中匹配它们而无需反射,但在参数注释的情况下,这超出了 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

另请参阅有关类似代码的相关但稍微简单的问题的此答案。

于 2015-01-05T17:30:12.343 回答
10

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

Object[] methodArguments = joinPoint.getArgs();
于 2014-12-26T16:44:15.417 回答