Guia de mapeamentos de manipulador de primavera
1. Introdução
No Spring MVC, oDispatcherServlet atua comofront controller - recebendo todas as solicitações HTTP de entrada e processando-as.
Simplificando, o processamento ocorre passando as solicitações para o componente relevantewith the help of handler mappings.
HandlerMapping é uma interface que define um mapeamento entre solicitações ehandler objects. Enquanto a estrutura Spring MVC fornece algumas implementações prontas, a interface pode ser implementada pelos desenvolvedores para fornecer uma estratégia de mapeamento personalizada.
Este artigo discute algumas das implementações fornecidas pelo Spring MVC, nomeadamenteBeanNameUrlHandlerMapping,SimpleUrlHandlerMapping,ControllerClassNameHandlerMapping, sua configuração e as diferenças entre eles.
2. BeanNameUrlHandlerMapping
BeanNameUrlHandlerMapping é a implementação padrão deHandlerMapping. BeanNameUrlHandlerMapping mapas solicitam URLs para beans com o mesmo nome.
Esse mapeamento específico tem suporte para correspondência direta de nomes e também para correspondência de padrões usando o padrão "*".
Por exemplo, uma URL de entrada“/foo” mapeia para um bean chamado“/foo”. Um exemplo de mapeamento de padrão é mapear solicitações para“/foo*” para beans com nomes começando com“/foo” como“/foo2/” ou“/fooOne/”.
Vamos configurar este exemplo aqui e registrar um controlador de bean que lida com solicitações para“/beanNameUrl”:
@Configuration
public class BeanNameUrlHandlerMappingConfig {
@Bean
BeanNameUrlHandlerMapping beanNameUrlHandlerMapping() {
return new BeanNameUrlHandlerMapping();
}
@Bean("/beanNameUrl")
public WelcomeController welcome() {
return new WelcomeController();
}
}
Este é o equivalente XML da configuração baseada em Java acima:
É importante observar que em ambas as configurações,defining a bean for BeanNameUrlHandlerMapping is not required, pois é fornecido pelo Spring MVC. A remoção dessa definição de bean não causará problemas e as solicitações ainda serão mapeadas para seus beans manipuladores registrados.
Agora todos os pedidos para“/beanNameUrl” serão encaminhados porDispatcherServlet para “WelcomeController“. WelcomeController retorna um nome de visualização chamado “welcome“.
O código a seguir testa essa configuração e garante que o nome de exibição correto seja retornado:
public class BeanNameMappingConfigTest {
// ...
@Test
public void whenBeanNameMapping_thenMappedOK() {
mockMvc.perform(get("/beanNameUrl"))
.andExpect(status().isOk())
.andExpect(view().name("welcome"));
}
}
3. SimpleUrlHandlerMapping
Em seguida,SimpleUrlHandlerMapping é a implementação deHandlerMapping mais flexível. Ele permite o mapeamento direto e declarativo entre instâncias e URLs de bean ou entre nomes e URLs de bean.
Vamos mapear as solicitações“/simpleUrlWelcome”e“/*/simpleUrlWelcome” para o bean“welcome”:
@Configuration
public class SimpleUrlHandlerMappingConfig {
@Bean
public SimpleUrlHandlerMapping simpleUrlHandlerMapping() {
SimpleUrlHandlerMapping simpleUrlHandlerMapping
= new SimpleUrlHandlerMapping();
Map urlMap = new HashMap<>();
urlMap.put("/simpleUrlWelcome", welcome());
simpleUrlHandlerMapping.setUrlMap(urlMap);
return simpleUrlHandlerMapping;
}
@Bean
public WelcomeController welcome() {
return new WelcomeController();
}
}
Como alternativa, aqui está a configuração XML equivalente:
/simpleUrlWelcome=welcome
/*/simpleUrlWelcome=welcome
É importante observar que na configuração XML, um mapeamento entre a tag“<value>” deve ser feito de forma aceita pela classejava.util.Properties e deve seguir a sintaxe:path= Handler_Bean_Name.
A URL normalmente deve estar com uma barra inicial, no entanto, se o caminho não começar com uma, Spring MVC o adiciona automaticamente.
Uma maneira diferente de configurar o exemplo acima em XML é usar a propriedade“props” em vez de“value”. Props tem uma lista de tags“prop”, onde cada uma define um mapeamento onde“key” se refere ao URL mapeado e o valor da tag é o nome do bean.
welcome
welcome
O caso de teste a seguir garante que as solicitações para “/simpleUrlWelcome” sejam tratadas por “WelcomeController”, que retorna um nome de visualização chamado“welcome”:
public class SimpleUrlMappingConfigTest {
// ...
@Test
public void whenSimpleUrlMapping_thenMappedOK() {
mockMvc.perform(get("/simpleUrlWelcome"))
.andExpect(status().isOk())
.andExpect(view().name("welcome"));
}
}
4. ControllerClassNameHandlerMapping (removido na primavera 5)
OControllerClassNameHandlerMapping mapeia a URL para um bean de controlador registrado (ou um controlador anotado com a anotação@Controller) que tem, ou começa com, o mesmo nome.
Pode ser mais conveniente em muitos cenários, especialmente para implementações simples de controladores que lidam com um único tipo de solicitação. A convenção usada pelo Spring MVC é usar o nome da classe e remover o sufixo“Controller”, em seguida, alterar o nome para minúsculas e retorná-lo como o mapeamento com um“/” inicial.
Por exemplo,“WelcomeController” retornaria como mapeamento para“/welcome*”, ou seja, para qualquer URL que comece com“welcome”.
Vamos configurarControllerClassNameHandlerMapping:
@Configuration
public class ControllerClassNameHandlerMappingConfig {
@Bean
public ControllerClassNameHandlerMapping controllerClassNameHandlerMapping() {
return new ControllerClassNameHandlerMapping();
}
@Bean
public WelcomeController welcome() {
return new WelcomeController();
}
}
Observe queControllerClassNameHandlerMapping édeprecated from Spring 4.3 a favor dos métodos de tratamento orientados por anotação.
Outra observação importante é que os nomes dos controladores sempre serão retornados em letras minúsculas (menos o sufixo “Controller”). Portanto, se tivermos um controlador chamado “WelcomeexampleController“, ele apenas tratará as solicitações para“/welcomeexample”e não para“/welcomeexample”.
Na configuração Java e na configuração XML abaixo, definimos o beanControllerClassNameHandlerMapping e registramos os beans para os controladores que usaremos para lidar com as solicitações. Também registramos um bean do tipo“WelcomeController”e esse bean tratará todas as solicitações que começam com“/welcome”.
Esta é a configuração XML equivalente:
Ao usar a configuração acima, as solicitações para “/welcome” serão tratadas pelo “WelcomeController“.
O código a seguir garantirá que as solicitações para “/welcome *” como “/welcometest” sejam tratadas por “WelcomeController”, que retorna um nome de visualização chamado “welcome“:
public class ControllerClassNameHandlerMappingTest {
// ...
@Test
public void whenControllerClassNameMapping_thenMappedOK() {
mockMvc.perform(get("/welcometest"))
.andExpect(status().isOk())
.andExpect(view().name("welcome"));
}
}
5. Configurando Prioridades
O framework Spring MVC permite mais de uma implementação da interfaceHandlerMapping ao mesmo tempo.
Vamos criar uma configuração e registrar dois controladores, ambos mapeados para a URL “/ welcome”, usando apenas mapeamento diferente e retornando nomes de exibição diferentes:
@Configuration
public class HandlerMappingDefaultConfig {
@Bean("/welcome")
public BeanNameHandlerMappingController beanNameHandlerMapping() {
return new BeanNameHandlerMappingController();
}
@Bean
public WelcomeController welcome() {
return new WelcomeController();
}
}
Sem nenhum mapeador de manipulador explícito registrado, umBeanNameHandlerMapping padrão será usado. Vamos afirmar esse comportamento com o teste:
@Test
public void whenConfiguringPriorities_thenMappedOK() {
mockMvc.perform(get("/welcome"))
.andExpect(status().isOk())
.andExpect(view().name("bean-name-handler-mapping"));
}
Se registrarmos explicitamente um mapeador de manipulador diferente, o mapeador padrão será substituído. No entanto, é interessante ver o que acontece quando dois mapeadores são registrados explicitamente:
@Configuration
public class HandlerMappingPrioritiesConfig {
@Bean
BeanNameUrlHandlerMapping beanNameUrlHandlerMapping() {
BeanNameUrlHandlerMapping beanNameUrlHandlerMapping
= new BeanNameUrlHandlerMapping();
return beanNameUrlHandlerMapping;
}
@Bean
public SimpleUrlHandlerMapping simpleUrlHandlerMapping() {
SimpleUrlHandlerMapping simpleUrlHandlerMapping
= new SimpleUrlHandlerMapping();
Map urlMap = new HashMap<>();
urlMap.put("/welcome", simpleUrlMapping());
simpleUrlHandlerMapping.setUrlMap(urlMap);
return simpleUrlHandlerMapping;
}
@Bean
public SimpleUrlMappingController simpleUrlMapping() {
return new SimpleUrlMappingController();
}
@Bean("/welcome")
public BeanNameHandlerMappingController beanNameHandlerMapping() {
return new BeanNameHandlerMappingController();
}
}
Para obter o controle sobre qual mapeamento é usado, as prioridades são definidas usando o métodosetOrder(int order). Este método usa um parâmetroint em que o valor mais baixo significa prioridade mais alta.
Na configuração XML, você pode definir prioridades usando uma propriedade chamada“order”:
Vamos adicionar as propriedadesorder aos beans de mapeamento do manipulador, seguindobeanNameUrlHandlerMapping.setOrder(1)esimpleUrlHandlerMapping.setOrder(0). O valor mais baixo da propriedadeorder reflete a precedência mais alta. Vamos afirmar um novo comportamento com o teste:
@Test
public void whenConfiguringPriorities_thenMappedOK() {
mockMvc.perform(get("/welcome"))
.andExpect(status().isOk())
.andExpect(view().name("simple-url-handler-mapping"));
}
Ao testar a configuração acima, você vê que as solicitações para“/welcome” serão tratadas pelo beanSimpleUrlHandlerMapping, que chama umSimpleUrlHandlerControllere retorna a visualizaçãosimple-url-handler-mapping. Podemos facilmente configurarBeanNameHandlerMapping para ter precedência, ajustando de acordo os valores da propriedadeorder.
6. Conclusão
Neste artigo, discutimos como o mapeamento de URL é tratado na estrutura do Spring MVC, explorando as diferentes implementações na estrutura.
O código que acompanha este artigo pode ser encontradoover on GitHub.