requestmapping que mvc formulario example español ejemplo arquitectura java spring-mvc controller annotations

java - que - spring mvc example



Spring-MVC Problema al usar @Controller en el controlador que implementa una interfaz (6)

Ed tiene razón, agregando

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

funciona bien

Estoy usando la primavera 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.

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.

Esto sin embargo no:

@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 trato de levantar la url, obtengo el siguiente rastro desagradable de la pila:

javax.servlet.ServletException: No adapter for handler [com.shaneleopard.web.controller.RegistrationController@e973e3]: 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 como una superclase abstracta y hago que Foo la extienda, entonces 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() { ... } }

Esto 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?


La verdadera razón por la que necesita usar ''proxy-target-class = "true"'' está en DefaultAnnotationHandlerMapping#determineUrlsForHandler() método DefaultAnnotationHandlerMapping#determineUrlsForHandler() : aunque utiliza ListableBeanFactory#findAnnotationOnBean para buscar una anotación @RequestMapping (y esto se ocupa de cualquier problema de proxy) , la búsqueda adicional para la anotación @Controller se realiza usando AnnotationUtils#findAnnotation (que no maneja problemas de proxy)


Lo que tenía que hacer era reemplazar

<tx:annotation-driven/>

con

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

Esto obliga a un aspecto a usar CGLIB para hacer aspectos en lugar de proxies dinámicos: CGLIB no pierde la anotación, ya que amplía la clase, mientras que los proxies dinámicos solo exponen la interfaz implementada.


No hay duda de que las anotaciones y la herencia pueden ser un poco complicadas, pero creo que debería 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 útil. Específicamente, ¿están los dos métodos de control anotados de la interfaz? Se supone que Foo es RegistrationController?


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

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


Si desea utilizar interfaces para sus controladores Spring MVC, debe mover las anotaciones un poco, como se menciona en los documentos de Spring: 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 Una falla común cuando se trabaja con clases de controlador anotadas ocurre cuando se aplica una funcionalidad que requiere la creación de un proxy para el objeto controlador (por ejemplo, los métodos @Transactional). Por lo general, se introducirá una interfaz para el controlador con el fin de utilizar proxies dinámicos JDK. Para que esto funcione, debe mover las anotaciones @RequestMapping a la interfaz, 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 los proxies de subclass basados ​​en CGLIB se deben usar en lugar de los proxies JDK basados ​​en interfaz. Para obtener más información sobre diversos mecanismos de proxying, consulte la Sección 8.6, "Mecanismos de proxying".

Desafortunadamente 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) { } }

Entonces, lo que tienes aquí es una interfaz que declara las anotaciones @Controller, @PathVariable y @RequestMapping (las anotaciones Spring MVC) y luego puedes poner tus anotaciones @Transactional o @Secured, 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 usa 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.