Guia de mapeamentos de manipulador de primavera

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.