que mvc example java spring spring-mvc servlets

java - example - spring mvc vs spring boot



¿Por qué Spring MVC responde con un 404 e informa "No se encontró asignación para la solicitud HTTP con URI[...] en DispatcherServlet"? (6)

En mi caso, estaba siguiendo la documentación de Interceptors Spring para la versión 5.1.2 (mientras usaba Spring Boot v2.0.4.RELEASE ) y la clase WebConfig tenía la anotación @EnableWebMvc , que parecía estar en conflicto con algo más en mi aplicación que era evitar que mis activos estáticos se resuelvan correctamente (es decir, no se devolvieron archivos CSS o JS al cliente).

Después de probar muchas cosas diferentes, intenté eliminar @EnableWebMvc y funcionó.

Editar: Aquí está la documentación de referencia que dice que debe eliminar la anotación @EnableWebMvc

Aparentemente, en mi caso, al menos, ya estoy configurando mi aplicación Spring (aunque no usando web.xml o cualquier otro archivo estático, definitivamente es programáticamente), por lo que fue un conflicto allí.

Estoy escribiendo una aplicación Spring MVC implementada en Tomcat. Vea el siguiente ejemplo mínimo, completo y verificable

public class Application extends AbstractAnnotationConfigDispatcherServletInitializer { protected Class<?>[] getRootConfigClasses() { return new Class<?>[] { }; } protected Class<?>[] getServletConfigClasses() { return new Class<?>[] { SpringServletConfig.class }; } protected String[] getServletMappings() { return new String[] { "/*" }; } }

Donde está SpringServletConfig

@Configuration @ComponentScan("com.example.controllers") @EnableWebMvc public class SpringServletConfig { @Bean public InternalResourceViewResolver resolver() { InternalResourceViewResolver vr = new InternalResourceViewResolver(); vr.setPrefix("/WEB-INF/jsps/"); vr.setSuffix(".jsp"); return vr; } }

Finalmente, tengo un @Controller en el paquete com.example.controllers

@Controller public class ExampleController { @RequestMapping(path = "/home", method = RequestMethod.GET) public String example() { return "index"; } }

El nombre de contexto de mi aplicación es Example . Cuando envío una solicitud a

http://localhost:8080/Example/home

la aplicación responde con un estado HTTP 404 y registra lo siguiente

WARN o.s.web.servlet.PageNotFound - No mapping found for HTTP request with URI `[/Example/WEB-INF/jsps/index.jsp]` in `DispatcherServlet` with name ''dispatcher''

Tengo un recurso JSP en /WEB-INF/jsps/index.jsp Esperaba que Spring MVC usara mi controlador para manejar la solicitud y reenviarla a JSP, entonces, ¿por qué responde con un 404?

Esto está destinado a ser una publicación canónica para preguntas sobre este mensaje de advertencia.


Encontré otra razón para el mismo error. Esto también podría deberse a los archivos de clase no generados para su archivo controller.java. Como resultado, el servlet del despachador mencionado en web.xml no puede asignarlo al método apropiado en la clase de controlador.

@Controller Class Controller{ @RequestMapping(value="/abc.html")//abc is the requesting page public void method() {.....} }

En eclipse en Proyecto-> seleccione limpiar -> Proyecto de compilación. Compruebe si el archivo de clase se ha generado para el archivo del controlador en compilaciones en su espacio de trabajo.


Limpia tu servidor. Tal vez elimine el servidor y agregue el proyecto una vez más y Ejecute.

  1. Detenga el servidor Tomcat

  2. Haga clic derecho en el servidor y seleccione "Limpiar"

  3. Haga clic derecho en el servidor nuevamente y seleccione "Limpiar directorio de trabajo de Tomcat"


Para mí, descubrí que mis clases de destino se generaron en un patrón de carpeta no igual al de origen. Esto es posiblemente en eclipse. Agrego carpetas para contener mis controladores y no los agrego como paquetes. Así que terminé definiendo una ruta incorrecta en la configuración de primavera.

Mi clase objetivo estaba generando clases en la aplicación y me refería a com.happy.app

<context:annotation-config /> <context:component-scan base-package="com.happy.app"></context:component-scan>

Agregué paquetes (no carpetas) para com.happy.app y moví los archivos de carpetas a paquetes en eclipse y resolvió el problema.


Resolví mi problema cuando, además de lo descrito anteriormente: `

@Bean public InternalResourceViewResolver resolver() { InternalResourceViewResolver vr = new InternalResourceViewResolver(); vr.setPrefix("/WEB-INF/jsps/"); vr.setSuffix(".jsp"); return vr; }

added tomcat-embed-jasper:

<dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <scope>provided</scope> </dependency>

`from: el archivo JSP no se procesa en la aplicación web Spring Boot


Su aplicación Spring MVC estándar atenderá todas las solicitudes a través de un DispatcherServlet que haya registrado con su contenedor de Servlet.

DispatcherServlet analiza su ApplicationContext y, si está disponible, el ApplicationContext registrado con un ContextLoaderListener para beans especiales que necesita para configurar su lógica de servicio de solicitudes. Estos beans se describen en la documentación .

Posiblemente el más importante, frijoles de tipo HandlerMapping map

solicitudes entrantes a manejadores y una lista de preprocesadores y postprocesadores (interceptores de manejador) basados ​​en algunos criterios cuyos detalles varían según la implementación de HandlerMapping . La implementación más popular admite controladores anotados, pero también existen otras implementaciones.

El javadoc de HandlerMapping describe además cómo deben comportarse las implementaciones.

DispatcherServlet encuentra todos los beans de este tipo y los registra en algún orden (se puede personalizar). Mientras se atiende una solicitud, DispatcherServlet recorre estos objetos HandlerMapping y prueba cada uno de ellos con getHandler para encontrar uno que pueda manejar la solicitud entrante, representada como la HttpServletRequest estándar. A partir de 4.3.x, si no encuentra ninguno , registra la advertencia que ve

No se encontró ninguna asignación para la solicitud HTTP con URI [/some/path] en DispatcherServlet con el nombre SomeName

e NoHandlerFoundException una NoHandlerFoundException o confirma inmediatamente la respuesta con un código de estado 404 No encontrado.

¿Por qué el DispatcherServlet encontró un HandlerMapping que pudiera manejar mi solicitud?

La implementación más común de HandlerMapping es RequestMappingHandlerMapping , que maneja el registro de beans @Controller como manejadores (realmente sus métodos anotados @RequestMapping ). Puede declarar un bean de este tipo usted mismo (con @Bean o <bean> u otro mecanismo) o puede usar las opciones integradas . Estos son:

  1. @Configuration su clase de @EnableWebMvc con @EnableWebMvc .
  2. Declare un miembro <mvc:annotation-driven /> en su configuración XML.

Como se describe en el enlace anterior, ambos registrarán un bean RequestMappingHandlerMapping (y un montón de otras cosas). Sin embargo, un HandlerMapping no es muy útil sin un controlador. RequestMappingHandlerMapping espera algunos beans @Controller por lo que debe declararlos también, a través de los métodos @Bean en una configuración Java o declaraciones <bean> en una configuración XML o mediante el escaneo de componentes de las clases anotadas @Controller . Asegúrese de que estos frijoles estén presentes.

Si recibe el mensaje de advertencia y un 404 y ha configurado todo lo anterior correctamente, entonces está enviando su solicitud al URI incorrecto , uno que no es manejado por un método de controlador anotado @RequestMapping detectado.

La biblioteca spring-webmvc ofrece otras implementaciones de HandlerMapping . Por ejemplo, BeanNameUrlHandlerMapping maps

desde URL a beans con nombres que comienzan con una barra diagonal ("/")

y siempre puedes escribir el tuyo. Obviamente, tendrá que asegurarse de que la solicitud que está enviando coincide con al menos uno de los HandlerMapping objeto HandlerMapping registrado.

Si no registra implícita o explícitamente ningún HandlerMapping (o si detectAllHandlerMappings es true ), DispatcherServlet registra algunos defaults . Estos se definen en DispatcherServlet.properties en el mismo paquete que la clase DispatcherServlet . Son BeanNameUrlHandlerMapping y DefaultAnnotationHandlerMapping (que es similar a RequestMappingHandlerMapping pero en desuso).

Depuración

Spring MVC registrará los controladores registrados a través de RequestMappingHandlerMapping . Por ejemplo, un @Controller como

@Controller public class ExampleController { @RequestMapping(path = "/example", method = RequestMethod.GET, headers = "X-Custom") public String example() { return "example-view-name"; } }

registrará lo siguiente en el nivel INFO

Mapped "{[/example],methods=[GET],headers=[X-Custom]}" onto public java.lang.String com.spring.servlet.ExampleController.example()

Esto describe el mapeo registrado. Cuando vea la advertencia de que no se encontró ningún controlador, compare el URI en el mensaje con la asignación que se muestra aquí. Todas las restricciones especificadas en @RequestMapping deben coincidir para que Spring MVC seleccione el controlador.

Otras implementaciones de HandlerMapping registran sus propias declaraciones que deberían insinuar sus asignaciones y sus controladores correspondientes.

Del mismo modo, habilite el registro de Spring en el nivel DEBUG para ver qué beans registra Spring. Debe informar qué clases anotadas encuentra, qué paquetes analiza y qué beans inicializa. Si los que esperaba no están presentes, revise la configuración de ApplicationContext .

Otros errores comunes

Un DispatcherServlet es solo un Servlet Java EE típico. Lo registra con su típica declaración <web.xml> <servlet-class> y <servlet-mapping> , o directamente a través de ServletContext#addServlet en un WebApplicationInitializer , o con cualquier mecanismo que utilice Spring boot. Como tal, debe confiar en la lógica de mapeo de url especificada en la especificación de Servlet , consulte el Capítulo 12. Consulte también

Con eso en mente, un error común es registrar el DispatcherServlet con una asignación de URL de /* , devolviendo un nombre de vista desde un método de controlador @RequestMapping y esperando que se represente un JSP. Por ejemplo, considere un método de controlador como

@RequestMapping(path = "/example", method = RequestMethod.GET) public String example() { return "example-view-name"; }

con un InternalResourceViewResolver

@Bean public InternalResourceViewResolver resolver() { InternalResourceViewResolver vr = new InternalResourceViewResolver(); vr.setPrefix("/WEB-INF/jsps/"); vr.setSuffix(".jsp"); return vr; }

puede esperar que la solicitud se forwarded a un recurso JSP en la ruta /WEB-INF/jsps/example-view-name.jsp . Esto no va a suceder. En cambio, suponiendo un nombre de contexto de Example , DisaptcherServlet informará

No se encontró ninguna asignación para la solicitud HTTP con URI [/Example/WEB-INF/jsps/example-view-name.jsp] en DispatcherServlet con el nombre ''dispatcher''

Debido a que DispatcherServlet se asigna a /* y /* coincide con todo (excepto las coincidencias exactas, que tienen mayor prioridad), DispatcherServlet se elegiría para manejar el forward desde JstlView (devuelto por InternalResourceViewResolver ). En casi todos los casos, DispatcherServlet no se configurará para manejar dicha solicitud .

En su lugar, en este caso simplista, debe registrar el DispatcherServlet en / , marcándolo como el servlet predeterminado. El servlet predeterminado es la última coincidencia para una solicitud. Esto permitirá que su contenedor de servlet típico elija una implementación de Servlet interna, asignada a *.jsp , para manejar el recurso JSP (por ejemplo, Tomcat tiene JspServlet ), antes de intentar con el servlet predeterminado.

Eso es lo que estás viendo en tu ejemplo.