2008-09-30 61 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 { ...}