2011-02-03 76 views
1

我有一个基本的Spring MVC控制器,它看起来像这样:春AnnotationMethodHandlerAdapter上和注释读拦截

@Controller 
public void MyController { 
    @RequestMapping("/secret") 
    public String show() { 
     return "secret.jsp"; 
    } 
} 

我将不得不只能通过登录用户达到几个相似的网址。由于这是一个交叉问题,我想使用AOP,并且我想通过注释来完成这项工作。换句话说,我想在每个需要保密的控制器方法上注释一个@RequiresLogin注解。

AnnotationMethodHandlerAdapter支持拦截器的概念,这在表面上看起来就像正确的方式。但是,我想知道将调用哪种方法,以便我可以检查它是否适用于我的@RequiresLogin注释。我看到有一个传入的“Object handler”参数,但我不确定如何将其转换为将被调用的Class和Method。

想法?

+0

岂不春季安全能够处理这个,而不需要你注释你的控制器吗? – limc 2011-02-03 00:25:06

+0

也许,但我们的项目没有使用Spring Security,我想修改genearl中的方法的过滤行为,而不仅仅是授权。也许为某些方法添加一个自定义额外头文件等。 – 2011-02-03 00:34:24

回答

1

由于axtavt正确写入,如果使用proxy-target-class,Spring-AOP可以很好地与控制器配合使用。但也有使用JDK代理,如果你遵循一些(乏味)公约的可能性:

基于接口的@Controller类

一个常见的错误与 注解控制器类时发生的工作 施加时的功能,需要 创建代理代理为 控制器对象(例如 @Transactional方法)。通常,您将为 控制器引入一个接口,以便使用JDK动态 代理。 为了使这项工作必须 移动@RequestMapping注释 到接口作为映射 机制只能“看见”通过代理公开的接口 。作为 选择,你可以选择 激活代理目标类=“真”在 为应用于 控制器 功能配置(在我们的交易 在<tx:annotation-driven />情况下)。 这样做指示基于CGLIB的 子类代理应使用 代替基于接口的JDK 代理。有关 各种代理机制的更多信息,请参阅 第7.6节,“Proxying mechanisms”

来源:15.3.2 Mapping requests with @RequestMapping

2

没有好方法在拦截器中获得方法签名。

尝试将常规AOP建议应用于您的控制器,只要使用目标类代理,Spring MVC就可以很好地运行它。

1

在使用弹簧安全将这里是最佳的方法,您可以使用Spring方面实现类似的功能。以下是使用Aspect来检查包含特定注释的方法的示例。

@Aspect 
public class MyAspect { 
    @Around("execution(* com.test.controllers..*.**(..)) && " + 
      "within(@org.springframework.sterotype.Controller *)") 
    public Object execute(ProceedingJoinPoint joinPoint) { 
     Object target = joinPoint.getTarget(); 
     if (target != null) { 
      Signature tSig = joinPoint.getSignature(); 
      if (tSig instanceof MethodSignature) { 
       MethodSignature mSig = (MethodSignature) tSig; 
       Method method = mSig.getMethod(); 
       if (method != null && method.isAnnotationPresent(MyAnnotation.class)) { 
        // do something 
        // parameters are available from joinPoint.getArgs(); 
       } 
      } 
     } 
    } 
    // allow method invocation to continue 
    return joinPoint.proceed(); 
}

@Around建议的格式将特定于您的应用程序。在这个例子中,它检查包com.test.controllers和所有子包中的Controller注释的任何类。有关其他选项,请参阅http://static.springsource.org/spring/docs/3.0.x/reference/aop.html

祝你好运!

+0

是的,但是axtavt和我自己的文章中列出的限制适用(除非您使用AspectJ编译时织入) – 2011-02-03 14:18:05

0

因此,列出的这些方法都很好,但它们都有局限性。 AOP的东西是一个好主意,但它的局限性在于,如果我想重定向或修改响应,我需要一种方法来获取请求和响应对象的位置。控制器方法不一定需要这些请求和响应,并且要求它们看起来不雅观。我可以使用Spring魔法从Aspect中获取请求对象,但是我找不到获取响应的方法。

最后,我想出了一条中间路线。我使用了一个过滤器bean来获取请求和响应对象,并将它们存储在一个ThreadLocal中。然后我创建了一个引用该过滤器的方面,以便它可以轻松查看请求和响应对象。

然后我做了方面环绕基于注释的方法,所以我甚至不需要检查注释是否存在使用代码。

这种组合方式看起来很完美!

唯一的缺点是我找不到一个好的方法来编写一个集成测试,验证在有对该URL的传入请求时调用该方面。移除单个注释会让所有测试都通过但允许未经授权的用户通过,这有点令人害怕。

谢谢大家的好建议!

1

如何使用反射ResolveHandlerMethodInterceptor。 下面的代码是实验和版本相关的(spring 3.0.2)。

import java.lang.reflect.Method; 

import javax.servlet.ServletContext; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 

import org.springframework.web.context.WebApplicationContext; 
import org.springframework.web.context.support.WebApplicationContextUtils; 
import org.springframework.web.servlet.FrameworkServlet; 
import org.springframework.web.servlet.HandlerInterceptor; 
import org.springframework.web.servlet.ModelAndView; 
import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter; 

public class ResolveHandlerMethodInterceptor implements HandlerInterceptor { 
    public final static String HANDLER_METHOD = "handlerMethod"; 
    // Here is your servlet name 
    public final static String SERVLET_NAME = "XXXXX"; 


    @Override 
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object object, ModelAndView modelAndView) 
      throws Exception { 
     Method handlerMethod = (Method) request.getAttribute(HANDLER_METHOD); 
     System.out.println("postHandle>>>" + handlerMethod); 
    } 

    @Override 
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object object, Exception exception) 
      throws Exception { 
     Method handlerMethod = (Method) request.getAttribute(HANDLER_METHOD); 
     System.out.println("afterCompletion>>>" + handlerMethod); 
    } 

    @Override 
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception { 

     ServletContext servletContext = request.getSession().getServletContext(); 
     String attrName = FrameworkServlet.SERVLET_CONTEXT_PREFIX + SERVLET_NAME; 
     WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext, attrName); 
     AnnotationMethodHandlerAdapter adapter = context.getBean(AnnotationMethodHandlerAdapter.class);  

     Method getMethodResolverMethod = adapter.getClass().getDeclaredMethod("getMethodResolver", Object.class); 
     getMethodResolverMethod.setAccessible(true); 
     Object servletHandlerMethodResolver = getMethodResolverMethod.invoke(adapter, object); 

     Method resolveHandlerMethod = servletHandlerMethodResolver.getClass().getMethod("resolveHandlerMethod", HttpServletRequest.class); 
     resolveHandlerMethod.setAccessible(true); 
     Method handlerMethod = (Method) resolveHandlerMethod.invoke(servletHandlerMethodResolver, request); 
     request.setAttribute(HANDLER_METHOD, handlerMethod); 

     System.out.println("preHandle>>>" + handlerMethod); 

     return true; 
    } 
} 

== ==参考
http://toby.epril.com/?p=934
http://www.jarvana.com/jarvana/view/org/springframework/spring-webmvc/3.0.2.RELEASE/spring-webmvc-3.0.2.RELEASE-sources.jar!/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java?format=ok