2008-09-30 4 views
32

Ich verwende Spring 2.5 und Anmerkungen, um meine Spring-MVC-Web-Kontext zu konfigurieren. Leider kann ich Folgendes nicht zur Arbeit bringen. Ich bin mir nicht sicher, ob dies ein Fehler ist (scheint so) oder ob es ein grundlegendes Missverständnis gibt, wie die Annotationen und Interface-Implementierungsunterklassen funktionieren.Spring-MVC Problem mit @Controller auf Controller zur Implementierung einer Schnittstelle

Zum Beispiel

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

funktioniert gut. Wenn der Kontext startet, werden die URLs entdeckt, mit denen dieser Handler arbeitet, und alles funktioniert gut.

Dies ist jedoch nicht:

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

Wenn ich versuche, die URL zu ziehen, bekomme ich folgende fiesen Stack-Trace:

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) 

Wenn ich jedoch Bar ändern, um eine abstrakt zu sein Superklasse und habe Foo erweitert, dann klappt es wieder.

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

Dies scheint wie ein Fehler. Die @Controller-Annotation sollte ausreichen, um dies als Controller zu kennzeichnen, und ich sollte in der Lage sein, eine oder mehrere Schnittstellen in meinem Controller zu implementieren, ohne etwas anderes tun zu müssen. Irgendwelche Ideen?

Antwort

5

Es besteht kein Zweifel, dass Anmerkungen und Vererbung ein wenig schwierig werden können, aber ich denke, das sollte funktionieren. Versuchen Sie explizit, den AnnotationMethodHandlerAdapter zu Ihrem Servlet-Kontext hinzuzufügen.

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

Wenn das nicht funktioniert, ein wenig mehr Informationen wären hilfreich. Genauer gesagt, sind die beiden annotierten Controller-Methoden von der Schnittstelle? Soll Foo RegistrationController sein?

12

Ed ist richtig, das Hinzufügen

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

funktioniert

12

Was ich war

<tx:annotation-driven/> 

mit

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

Diese Kräfte aspectj tun musste ersetzen CGLIB verwenden für Aspekte statt für dy Dynamische Proxies - CGLIB verliert die Annotation nicht, da sie die Klasse erweitert, während dynamische Proxies nur die implementierte Schnittstelle offenlegen.

+0

benötigt zu beachten, dass CGLIB ist eher veraltet. –

0

Der wahre Grund, warum Sie benötigen ‚Proxy-Ziel-class =‚true‘‘ zu verwenden, in DefaultAnnotationHandlerMapping#determineUrlsForHandler() Methode ist: wenn es ListableBeanFactory#findAnnotationOnBean zum Nachschlagen eine @RequestMapping Annotation verwendet (und dies kümmert sich um jegliche Proxy-Fragen), die zusätzlichen Nachschlag für @Controller Anmerkung wird mit AnnotationUtils#findAnnotation gemacht (was nicht Griffe Proxy-Probleme)

+0

Meinst du, dass es einen Fehler gibt? – Ruslan

10

Wenn Sie Schnittstellen für Ihre Spring MVC-Controller verwenden, dann müssen Sie die Anmerkungen um ein bisschen zu bewegen, wie sie in den Frühling docs erwähnt: http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/mvc.html#mvc-ann-requestmapping

Verwendung @RequestMapping auf Schnittstellenmethoden Ein häufiger Fehler, wenn mit annotierten Controller-Klassen arbeitet, wenn Funktionalität angewendet wird, die das Erstellen eines Proxy für das Controller-Objekt erfordert (z. B. @Transactional Methoden). Normalerweise werden Sie eine Schnittstelle für den Controller einführen, um dynamische JDK-Proxies zu verwenden. Um diese arbeiten zu können, müssen Sie die @RequestMapping-Annotationen auf die Schnittstelle als verschieben, da der Mapping-Mechanismus nur die Schnittstelle "sehen" kann, die von dem Proxy verfügbar gemacht wird. Alternativ können Sie in der Konfiguration für die auf den Controller angewendete Funktionalität proxy-target-class = "true" aktivieren (in unserem Transaktionsszenario in). Wenn Sie dies tun, zeigt an, dass CGLIB-basierte Unterklassen-Proxies anstelle von Schnittstellen-basierten JDK-Proxies verwendet werden sollten. Weitere Informationen zu verschiedenen Proxy-Mechanismen finden Sie in Abschnitt 8.6, "Proxy-Mechanismen".

Leider gibt es kein konkretes Beispiel dafür. Ich habe ein Setup funktioniert wie folgt gefunden:

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

    } 
} 

Also, was Sie hier haben, ist eine Schnittstelle, die die @Controller, @PathVariable und @RequestMapping Anmerkungen (die Spring MVC Anmerkungen) erklärt und dann können Sie entweder setzen Sie Ihre @ Transactional oder @Secured Annotationen zum Beispiel für die konkrete Klasse. Es sind nur die @Controller-Typ-Annotationen, die Sie aufgrund der Art und Weise, wie Spring ihre Zuordnungen durchführt, in die Schnittstelle einfügen müssen.

Beachten Sie, dass Sie dies nur tun müssen, wenn Sie eine Schnittstelle verwenden. Sie müssen es nicht unbedingt tun, wenn Sie mit CGLib-Proxies zufrieden sind, aber wenn Sie aus irgendeinem Grund dynamische JDK-Proxies verwenden möchten, könnte dies der richtige Weg sein.

2

Ich weiß es zu spät ist, aber ich bin dies für jemanden dieses Problem schreiben, wenn Sie Annotation-basierte Konfiguration verwenden ... die Lösung könnte so aussehen:

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