Su aplicación Spring MVC estándar atenderá todas las solicitudes a través de una DispatcherServletque haya registrado con su contenedor Servlet.
El DispatcherServletmira su ApplicationContexty, si está disponible, el ApplicationContextregistrado con un ContextLoaderListenerpara beans especiales que necesita para configurar su lógica de servicio de solicitudes. Estos beans se describen en la documentación .
Posiblemente el HandlerMappingmapa de beans de tipo más importante
solicitudes entrantes a los manejadores y una lista de pre y posprocesadores (interceptores de manejadores) basada en algunos criterios cuyos detalles varían según la HandlerMappingimplementación. La implementación más popular admite controladores anotados, pero también existen otras implementaciones.
El javadoc deHandlerMapping describe además cómo deben comportarse las implementaciones.
El DispatcherServletbusca todos los beans de este tipo y los registra en algún orden (se puede personalizar). Mientras atiende una solicitud, el DispatcherServletbucle recorre estos HandlerMappingobjetos y prueba cada uno de ellos getHandlerpara encontrar uno que pueda manejar la solicitud entrante, representada como estándar HttpServletRequest. A partir de 4.3.x, si no encuentra ninguno , registra la advertencia que ve
No se encontró el mapeo para la petición HTTP con URI [/some/path]en DispatcherServletcon el nombre somename
y ya sea tiros una NoHandlerFoundExceptiono inmediatamente compromete la respuesta con un código de estado 404 no encontrado.
¿Por qué no DispatcherServletencontré un HandlerMappingque pudiera manejar mi solicitud?
La HandlerMappingimplementación más común es RequestMappingHandlerMapping, que maneja el registro de @Controllerbeans como manejadores (realmente sus @RequestMappingmétodos anotados). Se puede declarar ya sea un grano de este tipo a sí mismo (con @Beano <bean>u otro mecanismo) o puede utilizar el incorporado en las opciones . Estos son:
- Anote su
@Configurationclase con @EnableWebMvc.
- Declare un
<mvc:annotation-driven />miembro en su configuración XML.
Como se describe en el enlace anterior, ambos registrarán un RequestMappingHandlerMappingbean (y muchas otras cosas). Sin embargo, a HandlerMappingno es muy útil sin un controlador. RequestMappingHandlerMappingespera algunos @Controllerbeans, por lo que debe declararlos también, a través de @Beanmétodos en una configuración Java o <bean>declaraciones en una configuración XML o mediante el escaneo de componentes de @Controllerclases anotadas en cualquiera de los dos. 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 @RequestMappingmétodo de controlador anotado detectado .
La spring-webmvcbiblioteca ofrece otras HandlerMappingimplementaciones integradas . Por ejemplo, BeanNameUrlHandlerMappingmapas
de URL a beans con nombres que comienzan con una barra ("/")
y siempre puedes escribir el tuyo. Obviamente, tendrá que asegurarse de que la solicitud que envía coincida con al menos uno de los HandlerMappingcontroladores del objeto registrado .
Si no registra implícita o explícitamente ningún HandlerMappingbean (o si lo detectAllHandlerMappingses true), el DispatcherServletregistra algunos valores predeterminados . Estos se definen en DispatcherServlet.propertiesel mismo paquete que la DispatcherServletclase. Son BeanNameUrlHandlerMappingy DefaultAnnotationHandlerMapping(que es similar RequestMappingHandlerMappingpero obsoleto).
Depuración
Spring MVC registrará los controladores registrados a través de RequestMappingHandlerMapping. Por ejemplo, un me @Controllergusta
@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 @RequestMappingdeben coincidir para que Spring MVC seleccione el controlador.
Otras HandlerMappingimplementaciones registran sus propias declaraciones que deberían indicar sus asignaciones y sus correspondientes controladores.
De manera similar, habilite el registro de Spring en el nivel DEBUG para ver qué beans registra Spring. Debería informar qué clases anotadas encuentra, qué paquetes escanea y qué beans inicializa. Si los que esperaba no están presentes, revise su ApplicationContextconfiguración.
Otros errores comunes
A DispatcherServletes solo un Java EE típico Servlet. Lo registra con su declaración típica <web.xml> <servlet-class>y <servlet-mapping>, o directamente a través ServletContext#addServletde a 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
Teniendo esto en cuenta, un error común es registrar el DispatcherServletcon una asignación de URL de /*, devolver un nombre de vista de un @RequestMappingmétodo de controlador y esperar que se procese 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 reenvíe a un recurso JSP en la ruta /WEB-INF/jsps/example-view-name.jsp. Esto no sucederá. En cambio, asumiendo un nombre de contexto de Example, DisaptcherServletinformará
No se encontró el mapeo para la petición HTTP con URI [/Example/WEB-INF/jsps/example-view-name.jsp]en DispatcherServletcon el nombre 'despachador'
Debido a que DispatcherServletse asigna /*y /*coincide con todo (excepto las coincidencias exactas, que tienen una prioridad más alta), DispatcherServletse elegiría para manejar el forwardde JstlView(devuelto por InternalResourceViewResolver). En casi todos los casos, DispatcherServletno se configurará para manejar dicha solicitud .
En cambio, en este caso simplista, debe registrar el DispatcherServletto /, marcándolo como el servlet predeterminado. El servlet predeterminado es la última coincidencia de 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á viendo en su ejemplo.