Java 如何获取自定义批注的@PathVariable值?

Java 如何获取自定义批注的@PathVariable值?,java,spring,spring-mvc,aspectj,spring-annotations,Java,Spring,Spring Mvc,Aspectj,Spring Annotations,我有一个控制器: @Authorised(id = "{personId}") @RequestMapping(value = {"{personId}"}, method = GET) public void test(@PathVariable PersonId personId) { System.out.println(personId); //gets personId } 注释: @Target({ElementType.METHOD}) @Retention(Retent

我有一个控制器:

@Authorised(id = "{personId}")
@RequestMapping(value = {"{personId}"}, method = GET)
public void test(@PathVariable PersonId personId) {
    System.out.println(personId); //gets personId
}
注释:

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Authorised {
    String id() default "";
}
@Pointcut("@annotation(Authorised)")
private void AuthorisedMethod() {}
@Before("AuthorisedMethod()")
public void checkIfIsCurrentlyAuthenticated(JoinPoint joinPoint) throws NoSuchMethodException {
    MethodSignature signature = (MethodSignature) joinPoint.getSignature();
    String methodName = signature.getMethod().getName();
    Class<?>[] parameterTypes = signature.getMethod().getParameterTypes();
    Parameter[] parameters = signature.getMethod().getParameters();
    Authorised annotations = joinPoint.getTarget().getClass().getMethod(methodName, parameterTypes).getAnnotation(Authorised.class);
    String id = annotations.id();
    System.out.println(id); // prints: "{personId}"
    // do the chekcing
    throw new UnauthenticatedUserException();
}
切入点:

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Authorised {
    String id() default "";
}
@Pointcut("@annotation(Authorised)")
private void AuthorisedMethod() {}
@Before("AuthorisedMethod()")
public void checkIfIsCurrentlyAuthenticated(JoinPoint joinPoint) throws NoSuchMethodException {
    MethodSignature signature = (MethodSignature) joinPoint.getSignature();
    String methodName = signature.getMethod().getName();
    Class<?>[] parameterTypes = signature.getMethod().getParameterTypes();
    Parameter[] parameters = signature.getMethod().getParameters();
    Authorised annotations = joinPoint.getTarget().getClass().getMethod(methodName, parameterTypes).getAnnotation(Authorised.class);
    String id = annotations.id();
    System.out.println(id); // prints: "{personId}"
    // do the chekcing
    throw new UnauthenticatedUserException();
}
以及必须获取{personId}值而不是字符串“{personId}”的方法:

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Authorised {
    String id() default "";
}
@Pointcut("@annotation(Authorised)")
private void AuthorisedMethod() {}
@Before("AuthorisedMethod()")
public void checkIfIsCurrentlyAuthenticated(JoinPoint joinPoint) throws NoSuchMethodException {
    MethodSignature signature = (MethodSignature) joinPoint.getSignature();
    String methodName = signature.getMethod().getName();
    Class<?>[] parameterTypes = signature.getMethod().getParameterTypes();
    Parameter[] parameters = signature.getMethod().getParameters();
    Authorised annotations = joinPoint.getTarget().getClass().getMethod(methodName, parameterTypes).getAnnotation(Authorised.class);
    String id = annotations.id();
    System.out.println(id); // prints: "{personId}"
    // do the chekcing
    throw new UnauthenticatedUserException();
}
@之前(“authorizedMethod()”)
public void checkificscurrentlyauthenticated(JoinPoint-JoinPoint)抛出NoSuchMethodException{
MethodSignature=(MethodSignature)joinPoint.getSignature();
String methodName=signature.getMethod().getName();
类[]parameterTypes=signature.getMethod().getParameterTypes();
参数[]参数=signature.getMethod().getParameters();
授权注释=joinPoint.getTarget().getClass().getMethod(方法名,参数类型).getAnnotation(授权的.class);
String id=annotations.id();
System.out.println(id);//打印:{personId}
//检查
抛出新的未经身份验证的UserException();
}
它能实现吗?如何实现?

更新:但如果方法参数号和切入点args()不匹配怎么办?我的意思是,如果特定方法有参数@PathVariable PersonId PersonId和其他几个参数,但poincut只需要知道PersonId PersonId,该怎么办?


例如,@statut说您必须这样编写args():args(personId,…)

您可以修改
@Before()
注释,使其具有
personId
值,并将该值传递给aspect

@Before("AuthorisedMethod() && args(personId)")
public void checkIfIsCurrentlyAuthenticated(JoinPoint joinPoint, PersonId personId) throws NoSuchMethodException {}
为了测试它,我有以下方面:

@Aspect
@Component
public class SomeAspect {

    @Pointcut("@annotation(Authorised)")
    private void AuthorisedMethod() {
    }

    @Before("AuthorisedMethod() && args(personId)")
    public void checkIfIsCurrentlyAuthenticated(JoinPoint joinPoint, PersonId personId) throws NoSuchMethodException {
        System.out.println("aspect " + personId.getId());
    }

}
配置类:

@Configuration
@ComponentScan(basePackages = {"test"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class Config {
}
测试组件:

@Component
public class Test {

    @Authorised(id = "{personId}")
    public void test(PersonId personId) {
        System.out.println("component " + personId.getId()); //gets personId
    }
}
和testNG的跑步者:

@ContextConfiguration(classes = Config.class)
public class TestRunner extends AbstractTestNGSpringContextTests {

    @Autowired
    test.Test test;

    @Test
    public void testName() {
        test.test(new PersonId("id"));
    }

}

当我运行它时,我会从aspect中打印出
“aspect id”
,并从调用的方法中打印出
“component id”

如果可能的话,您还可以使用HandlerInterceptor在RequestMapping URL中获取PathVariable的值

编写一个拦截此请求的处理程序类

public class AuthorisedHandler extends HandlerInterceptorAdapter {

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
        throws Exception {
    if (!isResourceHandler(handler) && (handler instanceof HandlerMethod)) {

        HandlerMethod hm = (HandlerMethod) handler;
        Method method = hm.getMethod();

        Authorised authAnnotation = method.getAnnotation(Authorised.class);
        if (authAnnotation != null) {
            String personId = getPersonId(request);
            //Do all your validations Here
        }
    }
    return true;
}

@SuppressWarnings("rawtypes")
private String getPersonId(HttpServletRequest request) throws IOException {
    String personId = request.getParameter("personId");
    if(personId == null || personId.equals("")){
        Map pathVariables = (Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
        personId = (String) pathVariables.get("personId");
    }
    return personId;
}


private boolean isResourceHandler(Object handler) {
    return handler instanceof ResourceHttpRequestHandler;
}

}
您必须在SpringConfigXML或SpringJavaConfig中配置这个处理程序bean

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean class="com.**.AuthorisedHandler" />
    </mvc:interceptor>
</mvc:interceptors>


现在,所有的请求都将通过这个拦截器。只有用@authorized注释的才会通过。

如果我按照您建议的方式更改注释和方法签名,那么CheckifiScurrentAuthenticated方法根本不会被调用。你知道为什么吗@你能分享你的代码吗?我自己也试过了,效果很好。对不起,我不能,因为它是在一个更大的项目中实现的。这里是它的简化版本。但问题还是一样:)@statut@BrainDead我在答案中添加了一些测试代码,请看我唯一没有的是@EnableAspectJAutoProxy(proxyTargetClass=true)。在我添加它之后,没有任何变化。是的,这可能是解决这个问题的一种方法,但这不是我问题的答案:)