Recentemente me foi proposto encontrar uma ferramenta para usarmos no lugar do Struts 2 nos novos projetos, a qual deveria substituí-lo suprindo as suas falhas. Até aqui, sem problemas, o que complicou foi o seguinte requerimento: deve rodar no JBoss 4.0.3, o que matou a possibilidade de adotar o JSF2. A próxima opção foi o Spring MVC, e descobri nela uma ótima ferramenta! Muito completa e fazendo o que deve fazer de forma bem simples!
Durante os estudos, não encontrei muito material sobre o Spring MVC 3, mas encontrei muito sobre a versão 2.5. Aqui vou mostrar como trabalhar com a versão 3 adotando todos os seus recursos .
Como sempre, começo pela configuração. E dessa vez, tem um pouco mais do que de costume. As libs primeiro:

Libs do Spring MVC
Com as libs no local, vamos à configuração que deve ser incluída no web.xml:
<servlet>
<servlet-name>springMvcSimples</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springMvcSimples</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>hiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hiddenHttpMethodFilter</filter-name>
<servlet-name>springMvcSimples</servlet-name>
</filter-mapping>
DispatcherServlet é a classe que habilita o uso Spring MVC, a qual vai lidar com as requisições. HiddenHttpMethodFilter é usado para habilitar o suporte RESTful do Spring. Falarei sobre isso mais tarde.
Por padrão, o Spring vai buscar o arquivo de configurações na pasta WEB-INF, com o nome do arquivo baseado no nome da DispatcherServlet, acrescentando –servlet.xml, então vamos ver a configuração do arquivo springMvcSimples-servlet.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<context:component-scan base-package="br.com.vonjuliano.springmvcsimples" />
<mvc:annotation-driven />
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
Aqui estão alguns itens de configuração muito 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 “lista”, ela faz redirecionamento para /WEB-INF/jsp/lista.jsp.
Ao trabalhar com Spring, é comum a utilização de Controllers, Services e Daos, onde nos Controllers fica a lógica de manipulação de dados para exibição, no Services a lógica de negócio que não podem ficar no próprio modelo de domínio e nos Daos a lógica para acesso ao banco de dados. Aqui o Controller vai receber um Service, e vou parar por aí, pois a interação entre o Service e o Dao será mostrado em outro post.
Abaixo, o CarroController:
package br.com.vonjuliano.springmvcsimples.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import br.com.vonjuliano.springmvcsimples.model.Carro;
import br.com.vonjuliano.springmvcsimples.service.CarroService;
@Controller
@RequestMapping("/carro")
public class CarroController {
private final CarroService service;
@Autowired
public CarroController(CarroService service) {
this.service = service;
}
@RequestMapping(value = "/lista", method = RequestMethod.GET)
public List<Carro> lista() {
return service.lista();
}
@RequestMapping(value = "/novo", method = RequestMethod.GET)
public ModelAndView novo() {
return new ModelAndView("carro/novo", "carro", new Carro());
}
@RequestMapping(value = "/novo", method = RequestMethod.POST)
public String novo(Carro carro) {
service.adiciona(carro);
return "redirect:lista";
}
@RequestMapping(value = "/editar/{id}", method = RequestMethod.GET)
public ModelAndView editar(@PathVariable Long id) {
Carro carro = service.busca(id);
return new ModelAndView("carro/editar", "carro", carro);
}
@RequestMapping(value = "/editar", method = RequestMethod.PUT)
public String editar(Carro carro) {
service.atualiza(carro);
return "redirect:lista";
}
}
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 {
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 que aqui é usado da mesma forma que o @Namespace do Struts 2. Mas quem efetivamente atende a requisição são os métodos:
@RequestMapping(value = "/lista", method = RequestMethod.GET)
public List<Carro> lista() {
return service.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 por /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:
<c:forEach items="${carroList}" var="carro">
O Spring permite que os métodos devolvam diferentes tipos de retorno, e uma pequena variação deles será mostrada aqui. 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 = RequestMethod.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 = RequestMethod.POST)
public String novo(Carro carro) {
service.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. Simples não?
O retorno da String 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 = RequestMethod.GET)
public ModelAndView editar(@PathVariable Long id) {
Carro carro = service.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. As novidades nesse método acabam aqui, já que o uso do ModelAndView é feito da mesma forma do método de inserção.
@RequestMapping(value = "/editar", method = RequestMethod.PUT)
public String editar(Carro carro) {
service.atualiza(carro);
return "redirect:lista";
}
Esse é o método que vai salvar as alterações na base de dados. Aqui faço uso do 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, uso o PUT 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 uma tag que já faz esse trabalho:
<form:form action="../editar" method="put" commandName="carro">
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 entre 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.
Abaixo, os códigos das jsps, para completar o que foi apresentado.
lista.jsp
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<html>
<head>
<title>Spring MVC 3 Simples</title>
</head>
<body>
<h3>Lista de carros</h3>
<table border="1">
<tr>
<td>Id</td>
<td>Nome</td>
<td>Ano de fabricação</td>
</tr>
<c:forEach items="${carroList}" var="carro">
<tr>
<td>${carro.id}</td>
<td>${carro.nome}</td>
<td>${carro.ano}</td>
<td><a href="editar/${carro.id}">Editar</a></td>
</tr>
</c:forEach>
</table>
<br>
<h5><a href="novo">Novo</a></h5>
</body>
</html>
novo.jsp
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<html>
<head>
<title>Spring MVC 3 Simples</title>
</head>
<body>
<h3>Novo Carro</h3>
<form:form action="novo" method="post" commandName="carro">
<table>
<tr>
<td>Nome: <form:input path="nome" /></td>
<td>Ano: <form:input path="ano" /></td>
<td><input type="submit"></td>
</tr>
</table>
</form:form>
</body>
</html>
editar.jsp
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<html>
<head>
<title>Spring MVC 3 Simples</title>
</head>
<body>
<h3>Editar Carro</h3>
<form:form action="../editar" method="put" commandName="carro">
<form:hidden path="id" />
<table>
<tr>
<td>Nome: <form:input path="nome" /></td>
<td>Ano: <form:input path="ano" /></td>
<td><input type="submit"></td>
</tr>
</table>
</form:form>
</body>
</html>
E a classe Carro.
public class Carro {
private Long id;
private String nome;
private int ano;
// gets e sets
}
Aqui foi apresentada uma forma simples que encontrei de trabalhar com Spring MVC 3, o qual é um framework muito poderoso, simples, que possuí inúmeras ferramentas para ajudar no desenvolvimento, e que funciona muito bem em servidores mais antigos, como o JBoss 4.