2008-09-30 219 views
32

我使用spring 2.5和annotations来配置我的spring-mvc web上下文。不幸的是,我无法得到以下的工作。我不确定这是一个错误(看起来像是这样),还是对注释和接口实现子类的工作原理有一个基本的误解。在控制器上使用@Controller实现接口的Spring-MVC问题

例如,

@Controller 
@RequestMapping("url-mapping-here") 
public class Foo { 
    @RequestMapping(method=RequestMethod.GET) 
    public void showForm() { 
    ... 
    } 
    @RequestMapping(method=RequestMethod.POST) 
    public String processForm() { 
    ... 
    } 
} 

工作正常。当上下文启动时,这个处理程序处理的url被发现,并且一切都很好。

然而,这并不:

@Controller 
@RequestMapping("url-mapping-here") 
public class Foo implements Bar { 
    @RequestMapping(method=RequestMethod.GET) 
    public void showForm() { 
    ... 
    } 
    @RequestMapping(method=RequestMethod.POST) 
    public String processForm() { 
    ... 
    } 
} 

当我试图拉起网址,我得到以下讨厌的堆栈跟踪:

javax.servlet.ServletException: No adapter for handler [[email protected]]: Does your handler implement a supported interface like Controller? 
    org.springframework.web.servlet.DispatcherServlet.getHandlerAdapter(DispatcherServlet.java:1091) 
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:874) 
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:809) 
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571) 
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:501) 
    javax.servlet.http.HttpServlet.service(HttpServlet.java:627) 

但是,如果我改变酒吧是一个抽象超类并让Foo扩展它,然后它再次工作。

@Controller 
@RequestMapping("url-mapping-here") 
public class Foo extends Bar { 
    @RequestMapping(method=RequestMethod.GET) 
    public void showForm() { 
    ... 
    } 
    @RequestMapping(method=RequestMethod.POST) 
    public String processForm() { 
    ... 
    } 
} 

这看起来像一个错误。 @Controller注释应该足以将其标记为控制器,并且我应该能够在控制器中实现一个或多个接口,而无需执行其他任何操作。有任何想法吗?

回答

5

毫无疑问,注释和继承可能会有点棘手,但我认为这应该工作。尝试显式地将AnnotationMethodHandlerAdapter添加到您的servlet上下文中。

http://static.springframework.org/spring/docs/2.5.x/reference/mvc.html#mvc-ann-setup

如果不工作,一点点的更多信息将是有益的。具体来说,界面中的两个注释控制器方法是什么? Foo应该是RegistrationController吗?

12

埃德是正确的,加入

<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/> 
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/> 

工作正常

12

我需要做什么用

<tx:annotation-driven proxy-target-class="true"/> 

这种力量的AspectJ使用CGLIB代替

<tx:annotation-driven/> 

用于做方面而不是dy标记代理 - CGLIB不会丢失注释,因为它扩展了类,而动态代理只是公开实现的接口。

+0

所需注意的是CGLIB是相当不赞成的。 – 2015-07-28 15:44:53

0

你需要使用“代理目标类=‘真’”是DefaultAnnotationHandlerMapping#determineUrlsForHandler()方法的真正原因是:尽管它使用ListableBeanFactory#findAnnotationOnBean用于查找一个@RequestMapping注释(这大约需要任何代理问题护理),附加为@Controller注释查找使用AnnotationUtils#findAnnotation完成(不把手代理问题)

+0

你的意思是有一个错误? – Ruslan 2017-07-19 11:04:40

10

如果您想使用的接口为您的Spring MVC控制器,那么你需要走动了一下注解,如在Spring文档中提到:http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/mvc.html#mvc-ann-requestmapping

使用@RequestMapping On接口方法当应用 功能需要为控制器对象 (例如,创建代理)时发生 处理注释控制器类时的常见错误。 @Transactional方法)。通常,您将为控制器引入一个接口 ,以便使用JDK动态代理。要使此 正常工作,必须将@RequestMapping注释移动到接口 ,以及映射机制只能“看到” 代理公开的接口。或者,您可以在适用于控制器 (在我们的交易场景中)的功能配置中激活proxy-target-class =“true” 。这样做 表示应该使用基于CGLIB的子类代理,而不是基于接口的JDK代理使用 。关于各种代理 机制的更多信息,请参见第8.6节“代理机制”。

遗憾的是它并没有给这一个具体的例子。我已经找到了设置这样工作的:

@Controller 
@RequestMapping(value = "/secure/exhibitor") 
public interface ExhibitorController { 

    @RequestMapping(value = "/{id}") 
    void exhibitor(@PathVariable("id") Long id); 
} 

@Controller 
public class ExhibitorControllerImpl implements ExhibitorController { 

    @Secured({"ROLE_EXHIBITOR"}) 
    @Transactional(readOnly = true) 
    @Override 
    public void exhibitor(final Long id) { 

    } 
} 

所以,你必须在这里那是什么声明@Controller,@PathVariable和@RequestMapping注解(Spring的MVC注释),然后你可以把你的接口@例如在具体类上的Transactional或@Secured注释。由于Spring的映射方式,只需要将@Controller类型注释放在界面上即可。

请注意,如果您使用接口,则只需执行此操作。如果您对CGLib代理感到满意,则不一定需要这样做,但如果由于某种原因想要使用JDK动态代理,则可能需要这样做。

2

我知道这是为时已晚,但我写这篇文章的人有这个问题 如果您正在使用基于注解配置...的解决办法是这样的:

@Configuration 
@ComponentScan("org.foo.controller.*") 
@EnableAspectJAutoProxy(proxyTargetClass=true) 
public class AppConfig { ...}