Seu aplicativo Spring MVC padrão atenderá a todas as solicitações por meio de um DispatcherServletque você registrou com seu contêiner Servlet.
O DispatcherServletolha para ele ApplicationContexte, se disponível, o ApplicationContextregistrado com um ContextLoaderListenerpara beans especiais, ele precisa configurar sua lógica de atendimento de solicitação. Esses beans são descritos na documentação .
Provavelmente o mais importante, feijão do tipo HandlerMappingmapa
solicitações de entrada para manipuladores e uma lista de pré e pós-processadores (interceptores de manipuladores) com base em alguns critérios cujos detalhes variam por HandlerMapping implementação. A implementação mais popular suporta controladores anotados, mas também existem outras implementações.
O javadoc deHandlerMapping descreve melhor como as implementações devem se comportar.
O DispatcherServletencontra todos os beans desse tipo e os registra em alguma ordem (pode ser personalizado). Enquanto atende a uma solicitação, o DispatcherServletloop atravessa esses HandlerMappingobjetos e testa cada um deles getHandlerpara encontrar um que possa lidar com a solicitação recebida, representada como o padrão HttpServletRequest. A partir de 4.3.x, se não encontrar nenhum , ele registra o aviso que você vê
Nenhum mapeamento encontrado para solicitação HTTP com URI [/some/path] emDispatcherServlet com o nome SomeName
e qualquer um um lança umNoHandlerFoundException ou imediatamente compromete a resposta com um código de status 404 Not Found.
Por que não DispatcherServlet encontrou umHandlerMapping que pudesse atender ao meu pedido?
A HandlerMappingimplementação mais comum é RequestMappingHandlerMapping, que lida com o registro de @Controllerbeans como manipuladores (na verdade, seus @RequestMappingmétodos anotados). Você pode declarar um bean deste tipo sozinho (com @Beanou <bean>ou outro mecanismo) ou pode usar as opções integradas . Esses são:
- Anote o seu
@Configuration classe com @EnableWebMvc.
- Declare um
<mvc:annotation-driven /> membro em sua configuração XML.
Como o link acima descreve, ambos registrarão um RequestMappingHandlerMappingbean (e um monte de outras coisas). No entanto, um HandlerMappingnão é muito útil sem um manipulador. RequestMappingHandlerMappingespera alguns @Controllerbeans, então você precisa declará-los também, por meio de @Beanmétodos em uma configuração Java ou <bean>declarações em uma configuração XML ou por meio de varredura de componente de@Controller classes anotadas em qualquer um deles. Certifique-se de que esses grãos estejam presentes.
Se você está recebendo a mensagem de aviso e um 404 e configurou todos os itens acima corretamente, então você está enviando sua solicitação para o URI errado , um que não é tratado por um @RequestMappingmétodo de manipulador anotado detectado .
A spring-webmvcbiblioteca oferece outras HandlerMappingimplementações integradas . Por exemplo,BeanNameUrlHandlerMapping mapas
de URLs a beans com nomes que começam com uma barra ("/")
e você sempre pode escrever o seu próprio. Obviamente, você terá que garantir que a solicitação que está enviando corresponda a pelo menos um dosHandlerMapping manipuladores do objeto .
Se você não registrar implícita ou explicitamente nenhum HandlerMappingbean (ou se detectAllHandlerMappingsestiver true), o DispatcherServletregistrará alguns padrões . Eles são definidos no DispatcherServlet.propertiesmesmo pacote da DispatcherServletclasse. Eles são BeanNameUrlHandlerMappinge DefaultAnnotationHandlerMapping(que é semelhante a, RequestMappingHandlerMappingmas obsoleto).
Depurando
Spring MVC registrará os manipuladores registrados por meio de RequestMappingHandlerMapping. Por exemplo, um @Controllergosto
@Controller
public class ExampleController {
@RequestMapping(path = "/example", method = RequestMethod.GET, headers = "X-Custom")
public String example() {
return "example-view-name";
}
}
irá registrar o seguinte no nível de INFO
Mapped "{[/example],methods=[GET],headers=[X-Custom]}" onto public java.lang.String com.spring.servlet.ExampleController.example()
Isso descreve o mapeamento registrado. Ao ver o aviso de que nenhum manipulador foi encontrado, compare o URI na mensagem com o mapeamento listado aqui. Todas as restrições especificadas no@RequestMapping devem corresponder para que o Spring MVC selecione o manipulador.
De outros HandlerMapping implementações registram suas próprias instruções que devem sugerir seus mapeamentos e seus manipuladores correspondentes.
Da mesma forma, habilite o registro do Spring no nível DEBUG para ver quais beans o Spring registra. Ele deve relatar quais classes anotadas ele encontra, quais pacotes ele verifica e quais beans ele inicializa. Se os que você esperava não estiverem presentes, revise sua ApplicationContextconfiguração.
Outros erros comuns
A DispatcherServleté apenas um Java EE típico Servlet. Você o registra com sua declaração típica <web.xml> <servlet-class>e <servlet-mapping>, ou diretamente por meio ServletContext#addServletde um WebApplicationInitializer, ou com qualquer mecanismo que o Spring boot usa. Como tal, você deve confiar na lógica de mapeamento de url especificada na especificação do Servlet , consulte o Capítulo 12. Consulte também
Com isso em mente, um erro comum é registrar o DispatcherServletcom um mapeamento de url de /*, retornar um nome de visualização de um @RequestMappingmétodo manipulador e esperar que um JSP seja renderizado. Por exemplo, considere um método manipulador como
@RequestMapping(path = "/example", method = RequestMethod.GET)
public String example() {
return "example-view-name";
}
com um InternalResourceViewResolver
@Bean
public InternalResourceViewResolver resolver() {
InternalResourceViewResolver vr = new InternalResourceViewResolver();
vr.setPrefix("/WEB-INF/jsps/");
vr.setSuffix(".jsp");
return vr;
}
você pode esperar que a solicitação seja encaminhada para um recurso JSP no caminho /WEB-INF/jsps/example-view-name.jsp. Isso não vai acontecer. Em vez disso, assumindo um nome de contexto de Example, oDisaptcherServlet relatório
Nenhum mapeamento encontrados para solicitação HTTP com URI [/Example/WEB-INF/jsps/example-view-name.jsp]no DispatcherServletcom o nome 'expedidor'
Como o DispatcherServleté mapeado para /*e /*corresponde a tudo (exceto correspondências exatas, que têm maior prioridade), o DispatcherServletseria escolhido para lidar com o forwarddo JstlView(retornado pelo InternalResourceViewResolver). Em quase todos os casos, o DispatcherServletnão será configurado para lidar com essa solicitação .
Em vez disso, neste caso simplista, você deve registrar o DispatcherServletpara /, marcando-o como o servlet padrão. O servlet padrão é a última correspondência para uma solicitação. Isso permitirá que seu contêiner de servlet típico escolha uma implementação Servlet interna, mapeada para *.jsp, para lidar com o recurso JSP (por exemplo, Tomcat temJspServlet ), antes de tentar com o servlet padrão.
Isso é o que você está vendo em seu exemplo.