如何获取自定义注解的@PathVariable 值?
How to get @PathVariable value for custom annotation?
我有一个控制器:
@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() {}
并且必须获取 {personId} 值而不是字符串“{personId}”的方法:
@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();
}
能否实现,如何实现?
更新:但是如果方法参数参数号与切入点 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());
}
}
配置class:
@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 的 运行ner:
@ContextConfiguration(classes = Config.class)
public class TestRunner extends AbstractTestNGSpringContextTests {
@Autowired
test.Test test;
@Test
public void testName() {
test.test(new PersonId("id"));
}
}
当我 运行 它时,我从方面打印 "aspect id"
并从调用的方法打印 "component id"
。
如果可能的话,您还可以使用 HandlerInterceptor 在 RequestMapping URL 中获取 PathVariable 的值。
编写拦截此请求的处理程序class。
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;
}
}
并且您必须在 spring 配置 xml 或 Spring Java 配置中配置此处理程序 bean。
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.**.AuthorisedHandler" />
</mvc:interceptor>
</mvc:interceptors>
现在,所有的请求都将通过这个拦截器。只有用@Authorised 注释的才会通过。
我有一个控制器:
@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() {}
并且必须获取 {personId} 值而不是字符串“{personId}”的方法:
@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();
}
能否实现,如何实现?
更新:但是如果方法参数参数号与切入点 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());
}
}
配置class:
@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 的 运行ner:
@ContextConfiguration(classes = Config.class)
public class TestRunner extends AbstractTestNGSpringContextTests {
@Autowired
test.Test test;
@Test
public void testName() {
test.test(new PersonId("id"));
}
}
当我 运行 它时,我从方面打印 "aspect id"
并从调用的方法打印 "component id"
。
如果可能的话,您还可以使用 HandlerInterceptor 在 RequestMapping URL 中获取 PathVariable 的值。
编写拦截此请求的处理程序class。
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;
}
}
并且您必须在 spring 配置 xml 或 Spring Java 配置中配置此处理程序 bean。
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.**.AuthorisedHandler" />
</mvc:interceptor>
</mvc:interceptors>
现在,所有的请求都将通过这个拦截器。只有用@Authorised 注释的才会通过。