Simplificando - Spring MVC

Por Juliano Alves em 03/03/2011, atualizado em 01/08/2012

O Spring MVC é uma ótima ferramenta. É bem mais avançado que o Sruts 2 e supre quase todas as suas falhas de forma simples. Não se encontra muito material sobre o Spring MVC 3, mas há muito sobre a versão 2.5. Aqui será mostrado como trabalhar com a versão 3 adotando a maior parte de seus recursos.

A configuração primeiro. Abaixo, o build.gradle do exemplo.

Também temos de configurar o web.xml.

DispatcherServlet é a classe que habilita o uso Spring MVC, a qual vai trabalhar as requisições recebidas. HiddenHttpMethodFilter é usado para habilitar o suporte RESTful do Spring. Mais sobre isso mais tarde.

Por padrão, o Spring vai buscar o arquivo de configurações na pasta WEB-INF, sendo o nome do arquivo o mesmo nome da DispatcherServlet (no exemplo esse nome é context), acrescentando –servlet.xml, então vamos ver a configuração do arquivo context-servlet.xml:

Neste arquivo estão alguns itens de configuração importantes, context:component-scan vai buscar todas as classes anotadas no local indicado por base-package, procurando em todos os seus pacotes e subpacotes.

A tag mvc:annotation-driven ativa os beans do Spring necessários para direcionar as requisições recebidas para os Controllers, além de configurar esses beans para que forneçam alguns serviços padrões, entre eles:

  • Serviço de conversão de dados, quando for informado, por exemplo, um número (que é na verdade enviado como String), ele já faz a conversão automaticamente;
  • Formatação de números e datas (esse último, caso o Joda Time esteja no classpath);
  • Validação (caso uma implementação da JSR-303 esteja no classpath, como Hibernate Validator);
  • Suporte a XML (caso JAXB esteja no classpath);
  • Suporte a JSON (caso Jackson esteja no classpath).

A classe InternalResourceViewResolver é usada para estabelecer alguns padrões: a propriedade prefix indica que as views vão ficar em /WEB-INF/jsp/ (uma boa prática recomendada, já que assim as jsps não podem ser acessadas diretamente), e a propriedade suffix indica que todas terão .jsp no fim de seu nome, de forma que quando essa classe recebe a String “lista”, ela faz redirecionamento para /WEB-INF/jsp/lista.jsp.

Finalizada a configuração, hora de mostrar as classes. Abaixo, o CarroController:

Trabalhando com Spring MVC é muito simples manter as operações referentes ao Carro na mesma classe. Vamos por partes:

@Controller
@RequestMapping("/carro")
public class CarroController {

    private final CarroDao dao;

    @Autowired
    public CarroController(final CarroDao dao) {
        this.dao = dao;
    }

A anotação @Controller é usada para dizer ao Spring que a classe é um Controller, e @RequestMapping indica que ele vai atender à requisições que contenham /carro na url, o qual é usado aqui da mesma forma que o @Namespace do Struts 2. O construtor recebe o dao por injeção do próprio Spring (de forma muito parecida com o que é descrito aqui).

Quem efetivamente atende a requisição são os métodos:

@RequestMapping(value = "/lista", method = GET)
public List<Carro> lista() {
    return dao.lista();
}

Combinando o value desse @RequestMapping com o existente no nome da classe, esse método vai atender a url .../carro/lista. Todas as demais são feitas dessa mesma forma.

Aqui é feito uso do suporte ao RESTful do Spring, através do parâmetro method é informado o método HTTP utilizado, de forma que o método lista atenderá apenas um método GET. Ele vai retornar uma lista com todos os carros existentes no banco e enviá-la para a jsp. Para qual jsp? Por convenção, caso não seja explicitamente informado para onde ir, o Spring vai considerar a url usada para definir isso; /carro/lista fará com que ele procure pela jsp /WEB-INF/jsp/carro/lista.jsp

E para exibir a lista na jsp, por padrão o Spring vai nomeá-la como “conteúdo da lista" + List, nesse caso a lista será chamada de carroList, que pode ser acessado com jstl:

O Spring permite que os métodos devolvam diferentes tipos de retorno, e uma pequena variação deles será mostrada nesse exemplo. Todos os tipos de retorno permitidos podem ser vistos na documentação.

Abaixo, os métodos para inserção de um carro:

@RequestMapping(value = "/novo", method = GET)
public ModelAndView novo() {
    return new ModelAndView("carro/novo", "carro", new Carro());
}

Esse método leva para a página com o formulário de cadastro de um novo carro. Aqui faço uso da classe ModelAndView para informar para o Spring para onde ir (carro/novo), o nome que será usado para referenciar o objeto na página (“carro”, que se não for informado, por padrão será “command”), e o objeto propriamente dito. Com isso, o jsp saberá com qual classe está lidando, o que facilita para o próximo método:

@RequestMapping(value = "/novo", method = POST)
public String novo(final Carro carro) {
    dao.adiciona(carro);
    return "redirect:lista";
}

Os métodos da classe possuem o mesmo nome, mas devido aos métodos HTTP para acesso a cada um deles, o Spring sabe exatamente qual chamar. O método recebe um Carro, já que no método anterior foi informado para o Spring que era com esse objeto que ele deveria trabalhar. Assim ele já faz as conversões necessárias e seta os valores no objeto. Isso torna a forma de trabalhar com a ferramenta muito agradável.

A String de retorno diz ao Spring que ele deve redirecionar para o controller indicado após a palavra redirect, assim ele vai chamar o controller que lista todos os carros.

Por fim, os métodos de edição:

@RequestMapping(value = "/editar/{id}", method = GET)
public ModelAndView editar(@PathVariable Long id) {
    Carro carro = dao.busca(id);
    return new ModelAndView("carro/editar", "carro", carro);
}

Esse método busca o Carro para edição através do id, o qual é informado na url. /editar/{id} indica o formato da url, de forma que uma chamada válida seria /editar/2. O parâmetro id recebido no método deve ser anotado com @PathVariable para que o Spring saiba que o valor informado na url deve ser associado a esse método. O uso do ModelAndView é feito da mesma forma do método de inserção.

@RequestMapping(value = "/editar", method = PUT)
public String editar(final Carro carro) {
    dao.atualiza(carro);
    return "redirect:lista";
}

Esse é o método que vai salvar as alterações feitas no objeto. Aqui é usado o método HTTP PUT. O DispatcherServlet do Spring suporta os seguintes métodos HTTP: GET, POST, HEAD, PUT e DELETE, onde por convenção, GET é usado para buscar informações, POST para enviar informações, PUT para alterar informações e DELETE para removê-las. É semelhante às operações de um CRUD.

Voltando ao método, PUT é usado para alterar os dados do carro, o que quando é feito, é redirecionado com a String informada.

Aqui vale citar que os Browsers compreendem apenas os métodos GET e POST, então para indicar que o método é PUT é necessário declará-lo como POST e criar um campo oculto de nome _method com o valor PUT (o processo é o mesmo para o caso do método DELETE). Felizmente, não é necessário fazer isso na mão, pois o Spring possui a tag form que já faz esse trabalho:

Essa tag, ao gerar o HTML final vai criar o campo oculto. As demais tags que o Spring proporciona podem ser vistas aqui.

Apenas fazer uso da tag não é o suficiente para que o Spring interprete o método que deve ser utilizado, e é aí que entra o HiddenHttpMethodFilter, o qual foi incluído no web.xml no começo da configuração, que é quem faz esse trabalho de encaminhar a requisição com o método HTTP adequado.

Aqui foi mostrada uma forma simples que de trabalhar com Spring MVC 3, o qual é um framework muito poderoso, simples, que possui inúmeras ferramentas para ajudar no desenvolvimento. Recomendo!


Código do exemplo.



blog comments powered by Disqus