Seu aplicativo Spring MVC padrão atenderá a todas as solicitações por meio de um DispatcherServlet
que você registrou com seu contêiner Servlet.
O DispatcherServlet
olha para ele ApplicationContext
e, se disponível, o ApplicationContext
registrado com um ContextLoaderListener
para 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 HandlerMapping
mapa
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 DispatcherServlet
encontra todos os beans desse tipo e os registra em alguma ordem (pode ser personalizado). Enquanto atende a uma solicitação, o DispatcherServlet
loop atravessa esses HandlerMapping
objetos e testa cada um deles getHandler
para 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 HandlerMapping
implementação mais comum é RequestMappingHandlerMapping
, que lida com o registro de @Controller
beans como manipuladores (na verdade, seus @RequestMapping
métodos anotados). Você pode declarar um bean deste tipo sozinho (com @Bean
ou <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 RequestMappingHandlerMapping
bean (e um monte de outras coisas). No entanto, um HandlerMapping
não é muito útil sem um manipulador. RequestMappingHandlerMapping
espera alguns @Controller
beans, então você precisa declará-los também, por meio de @Bean
mé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 @RequestMapping
método de manipulador anotado detectado .
A spring-webmvc
biblioteca oferece outras HandlerMapping
implementaçõ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 HandlerMapping
bean (ou se detectAllHandlerMappings
estiver true
), o DispatcherServlet
registrará alguns padrões . Eles são definidos no DispatcherServlet.properties
mesmo pacote da DispatcherServlet
classe. Eles são BeanNameUrlHandlerMapping
e DefaultAnnotationHandlerMapping
(que é semelhante a, RequestMappingHandlerMapping
mas obsoleto).
Depurando
Spring MVC registrará os manipuladores registrados por meio de RequestMappingHandlerMapping
. Por exemplo, um @Controller
gosto
@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 ApplicationContext
configuraçã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#addServlet
de 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 DispatcherServlet
com um mapeamento de url de /*
, retornar um nome de visualização de um @RequestMapping
mé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 DispatcherServlet
com o nome 'expedidor'
Como o DispatcherServlet
é mapeado para /*
e /*
corresponde a tudo (exceto correspondências exatas, que têm maior prioridade), o DispatcherServlet
seria escolhido para lidar com o forward
do JstlView
(retornado pelo InternalResourceViewResolver
). Em quase todos os casos, o DispatcherServlet
não será configurado para lidar com essa solicitação .
Em vez disso, neste caso simplista, você deve registrar o DispatcherServlet
para /
, 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.