2008-09-30 13 views
32

Estoy usando el resorte 2.5 y las anotaciones para configurar mi contexto web spring-mvc. Lamentablemente, no puedo hacer que lo siguiente funcione. No estoy seguro de si esto es un error (me parece) o si hay un malentendido básico sobre cómo funcionan las anotaciones y la subclasificación de implementación de interfaz.Spring-MVC Problema al usar @Controller en el controlador que implementa una interfaz

Por ejemplo,

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

funciona bien. Cuando se inicia el contexto, se descubren las direcciones URL con las que trata este controlador, y todo funciona muy bien.

Sin embargo, esto no lo hace:

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

Cuando intento de levantar la url, me sale el siguiente seguimiento de la pila desagradable:

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) 

Sin embargo, si cambio Bar ser un resumen superclase y hacer que Foo lo extienda, luego funciona de nuevo.

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

Parece un error. La anotación @Controller debería ser suficiente para marcar esto como un controlador, y debería ser capaz de implementar una o más interfaces en mi controlador sin tener que hacer nada más. ¿Algunas ideas?

Respuesta

5

No hay duda de que las anotaciones y la herencia pueden ser un poco complicadas, pero creo que deberían funcionar. Intente agregar explícitamente AnnotationMethodHandlerAdapter a su contexto de servlet.

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

Si eso no funciona, un poco más de información sería de gran ayuda. Específicamente, ¿están los dos métodos de control anotados de la interfaz? Se supone que Foo es RegistrationController?

12

Ed es correcto, añadiendo

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

funciona bien

12

Lo que tenía que hacer era reemplazar

<tx:annotation-driven/> 

con

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

Este aspectj fuerzas de usar CGLIB para hacer aspectos en lugar de dy proxies namic: CGLIB no pierde la anotación ya que amplía la clase, mientras que los proxies dinámicos simplemente exponen la interfaz implementada.

+0

necesarios para señalar que CGLIB es bastante obsoleto. –

0

La verdadera razón es necesario utilizar '-target-clase proxy = 'true'' está en DefaultAnnotationHandlerMapping#determineUrlsForHandler() método: a pesar de que utiliza ListableBeanFactory#findAnnotationOnBean para buscar una anotación de @RequestMapping (y esto se encarga acerca de cualquier problema de proxy), el adicional de búsqueda para @Controller anotación se realiza utilizando AnnotationUtils#findAnnotation (que no se ocupa de cuestiones de proxy)

+0

¿Quieres decir que hay un error? – Ruslan

10

Si desea usar interfaces para sus controladores Spring MVC, entonces usted necesita para mover las anotaciones de todo un poco, como se menciona en los documentos de primavera: http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/mvc.html#mvc-ann-requestmapping

Uso de @RequestMapping en métodos de interfaz Un error común cuando trabaja con clases de controlador anotadas sucede al aplicar la funcionalidad que requiere la creación de un proxy para el objeto controlador (p. @Transactional methods). Por lo general, se introducirá una interfaz para el controlador con el fin de utilizar proxies dinámicos JDK. Para que este funcione, debe mover las anotaciones @RequestMapping a la interfaz como , así como el mecanismo de asignación solo puede "ver" la interfaz expuesta por el proxy. Alternativamente, puede activar proxy-target-class = "true" en la configuración de la funcionalidad aplicada al controlador (en nuestro escenario de transacciones). Al hacerlo, indica que se deben usar proxies de subclass basados ​​en CGLIB en lugar de los proxys JDK basados ​​en interfaz . Para obtener más información sobre los diversos mecanismos de proxying , consulte la Sección 8.6, "Mecanismos de proxying".

Desafortunadamente, esto no da un ejemplo concreto de esto. He encontrado una configuración como esta funciona:

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

    } 
} 

Así que lo que tenemos aquí es una interfaz que declara el @Controller, @PathVariable y anotaciones @RequestMapping (las anotaciones Spring MVC) y entonces usted puede poner su @ Anotaciones transaccionales o seguras por ejemplo en la clase concreta. Son solo las anotaciones de tipo @Controller que debe poner en la interfaz debido a la forma en que Spring realiza sus asignaciones.

Tenga en cuenta que solo necesita hacer esto si utiliza una interfaz. No es necesario que lo haga si está satisfecho con los proxies CGLib, pero si por algún motivo desea utilizar proxys dinámicos JDK, este podría ser el camino a seguir.

2

sé que es demasiado tarde, pero estoy escribiendo esto para cualquiera que tenga este problema si está utilizando la configuración basada en la anotación ... la solución podría ser así:

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