2008-09-30 21 views
32

Używam wiosny 2.5 i adnotacji do konfiguracji mojego kontekstu webowego spring-mvc. Niestety, nie mogę wykonać poniższych czynności. Nie jestem pewien, czy jest to błąd (wygląda na to), czy też istnieje podstawowe nieporozumienie dotyczące działania podklasowania i implementacji podklas.Spring-MVC Problem przy użyciu @Controller na kontrolerze implementującym interfejs

Na przykład

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

działa dobrze. Po uruchomieniu kontekstu odkrywane są adresy URL obsługiwane przez ten program obsługi i wszystko działa świetnie.

To jednak nie:

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

Kiedy próbuję podciągnąć url, otrzymuję następujący paskudny ślad stosu:

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) 

Jednak jeśli zmienię Bar być abstrakcyjny nadklasy i Foo przedłużyć ją, a następnie działa ponownie.

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

Wydaje się, że to błąd. Adnotacja @Controller powinna być wystarczająca, aby oznaczyć to jako kontroler, i powinienem być w stanie zaimplementować jeden lub więcej interfejsów w moim kontrolerze bez konieczności robienia czegokolwiek innego. Jakieś pomysły?

Odpowiedz

5

Nie ulega wątpliwości, że adnotacje i dziedziczenie mogą trochę skomplikować, ale myślę, że to powinno zadziałać. Spróbuj jawnie dodać AdnotationMethodHandlerAdapter do kontekstu serwletu.

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

Jeśli to nie zadziała, trochę więcej informacji byłoby pomocne. W szczególności, czy dwie metody kontrolera są adnotowane z interfejsu? Czy Foo ma być kontrolerem RegistrationController?

12

Ed ma rację, dodając

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

działa dobrze

12

Co muszę zrobić było zastąpić

<tx:annotation-driven/> 

z

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

Zmusza AspectJ do wykorzystania CGLIB za robienie aspektów zamiast dy namiczne proxy - CGLIB nie traci adnotacji, ponieważ rozszerza klasę, podczas gdy dynamiczne serwery proxy ujawniają zaimplementowany interfejs.

+0

potrzebne, aby pamiętać, że CGLIB jest raczej przestarzałe. –

0

Prawdziwy powód, trzeba użyć „proxy-target-class =«true»” jest w DefaultAnnotationHandlerMapping#determineUrlsForHandler() metody: chociaż używa ListableBeanFactory#findAnnotationOnBean dla patrząc na @RequestMapping adnotacji (i dba o wszelkich kwestiach proxy), dodatkowy odnośnika do @Controller adnotacji odbywa się za pomocą AnnotationUtils#findAnnotation (co nie uchwyty kwestie proxy)

+0

Czy masz na myśli błąd? – Ruslan

10

Jeśli chcesz korzystać z interfejsów dla kontrolerów Wiosna MVC następnie trzeba przenieść adnotacje się trochę, jak wspomniano w docs wiosny: http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/mvc.html#mvc-ann-requestmapping

Korzystanie @RequestMapping On Interface Methods Typowa pułapka, gdy pracująca z przypisanymi klasami kontrolerów, dzieje się podczas stosowania funkcji , która wymaga utworzenia proxy dla obiektu kontrolera (np. @ Metody transakcyjne). Zazwyczaj do kontrolera zostanie wprowadzony interfejs w celu korzystania z dynamicznych serwerów proxy JDK. Aby działało to , musisz przenieść adnotacje @RequestMapping do interfejsu jako , a mechanizm odwzorowania może "zobaczyć" tylko interfejs odsłonięty przez serwer proxy. Alternatywnie można aktywować proxy-target-class = "true" w konfiguracji dla funkcji zastosowanej do kontrolera (w naszym scenariuszu transakcji w). W ten sposób wskazuje, że proxy proxy oparte na CGLIB powinny być używane zamiast proxy proxy JDK opartego na interfejsie. Aby uzyskać więcej informacji na temat różnych mechanizmów proxy, należy zapoznać się z sekcją 8.6, "Mechanizmy proxy".

Niestety nie daje tego konkretnego przykładu. Znalazłem konfiguracji jak to działa:

@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) { 

    } 
} 

Więc co masz tutaj jest interfejs, który deklaruje @Controller, @PathVariable i @RequestMapping adnotacje (adnotacje Wiosną MVC), a następnie można albo umieścić swój @ Adnotacje transakcyjne lub @Sprawdzone na przykład na konkretnej klasie. To tylko adnotacje typu @Controller, które należy umieścić w interfejsie ze względu na sposób, w jaki Spring wykonuje odwzorowania.

Pamiętaj, że musisz to zrobić tylko, jeśli używasz interfejsu. Nie musisz tego robić, jeśli jesteś zadowolony z serwerów proxy CGLib, ale jeśli z jakiegoś powodu chcesz korzystać z dynamicznych serwerów proxy JDK, może to być droga.

2

wiem, że jest zbyt późno, ale piszę to dla każdego, kto ma ten problem jeśli używasz konfiguracji adnotacji w oparciu ... rozwiązaniem może być tak:

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