16. Introdução ao Spring MVC
16.1. O papel do Spring MVC em uma aplicação web
Vamos contextualizar o Spring MVC no desenvolvimento de uma aplicação web. Na maioria das vezes, ela será construída sobre uma arquitetura multicamadas como a seguinte:
![]() |
- a camada [Web] é a camada que interage diretamente com o usuário da aplicação web. O usuário interage com a aplicação web por meio de páginas da web visualizadas em um navegador. É nessa camada que se situa o Spring MVC e exclusivamente nessa camada;
- a camada [métier] implementa as regras de gestão da aplicação, tais como o cálculo de um salário ou de uma fatura. Essa camada utiliza dados provenientes do usuário por meio da camada [Web] e da camada SGBD por meio da camada [DAO];
- A camada [DAO] (Data Access Objects), a camada [ORM] (Object Relational Mapper) e o driver JDBC gerenciam o acesso aos dados do SGBD. A camada [ORM] faz a ponte entre os objetos manipulados pela camada [DAO] e as linhas e colunas das tabelas de um banco de dados relacional. Uma especificação chamada JPA (Java Persistence API) permite abstrair-se do ORM utilizado, caso este implemente essas especificações. Esse será o caso neste tutorial e, portanto, passaremos a chamar a camada ORM de camada JPA;
- a integração das camadas é feita pelo framework Spring;
16.2. O modelo de desenvolvimento do Spring MVC
O Spring MVC implementa o modelo de arquitetura denominado MVC (Modelo – Visão – Controlador) da seguinte maneira:
![]() |
O processamento de uma solicitação de um cliente ocorre da seguinte maneira:
- solicitação — as solicitações URL têm o formato http://machine:port/contexte/Action/param1/param2/....?p1=v1&p2=v2&... O [Front Controller] utiliza um arquivo de configuração ou anotações Java para “rotear” a solicitação para o controlador correto e para a ação correta dentro desse controlador. Para isso, ele utiliza o campo [Action] do URL. O restante do URL [/param1/param2/...] é composto por parâmetros opcionais que serão transmitidos à ação. O C de MVC é, neste caso, a string [Front Controller, Contrôleur, Action]. Se nenhum controlador puder processar a ação solicitada, o servidor web responderá que a ação solicitada não foi encontrada.
- Processamento
- (continuação)
- A ação selecionada pode utilizar os parâmetros parami que o [Front Controller] lhe transmitiu. Esses parâmetros podem provir de várias fontes:
- do caminho [/param1/param2/...] do URL,
- dos parâmetros [p1=v1&p2=v2] do URL,
- dos parâmetros enviados pelo navegador junto com sua solicitação;
- no processamento da solicitação do usuário, a ação pode precisar das camadas [métier] e [2b]. Uma vez processada a solicitação do cliente, ela pode gerar diversas respostas. Um exemplo clássico é:
- uma página de erro, caso a solicitação não tenha sido processada corretamente
- uma página de confirmação, caso contrário
- a ação solicita que uma determinada vista seja exibida [3]. Essa vista exibirá dados que chamamos de modelo da vista. Esse é o M de MVC. A ação criará esse modelo M [2c] e solicitará que uma vista V seja exibida [3];
- resposta — a vista V selecionada utiliza o modelo M criado pela ação para inicializar as partes dinâmicas da resposta HTML que ela deve enviar ao cliente e, em seguida, envia essa resposta.
Para um serviço web / jSON, a arquitetura anterior é ligeiramente modificada:
![]() |
- em [4a], o modelo, que é uma classe Java, é transformado em uma string jSON por uma biblioteca jSON;
- em [4b], essa string jSON é enviada ao navegador;
Agora, vamos esclarecer a relação entre a arquitetura web MVC e a arquitetura em camadas. Dependendo da definição que se atribui ao modelo, esses dois conceitos podem ou não estar relacionados. Consideremos uma aplicação web Spring MVC de camada única:
![]() |
Se implementarmos a camada [Web] com o Spring MVC, teremos, de fato, uma arquitetura web MVC, mas não uma arquitetura multicamadas. Nesse caso, a camada [web] cuidará de tudo: apresentação, lógica de negócios e acesso aos dados. São as ações que realizarão esse trabalho.
Agora, vamos considerar uma arquitetura web multicamadas:
![]() |
A camada [Web] pode ser implementada sem framework e sem seguir o modelo MVC. Temos, portanto, uma arquitetura multicamadas, mas a camada Web não implementa o modelo MVC.
Por exemplo, no mundo .NET, a camada [Web] acimaacima pode ser implementada com ASP.NET e MVC, e temos, então, uma arquitetura em camadas com uma camada [Web] do tipo MVC. Feito isso, é possível substituir essa camada ASP.NET MVC por uma camada ASP.NET clássica (WebForms), mantendo o restante (de negócio, DAO, ORM) inalterado. Temos, então, uma arquitetura em camadas com uma camada [Web] que não é mais do tipo MVC.
Em MVC, afirmamos que o modelo M era o da vista V, c.a.d, ou seja, o conjunto de dados exibidos pela vista V. É fornecida outra definição do modelo M de MVC:
![]() |
Muitos autores consideram que o que está à direita da camada [Web] forma o modelo M do MVC. Para evitar ambiguidades, pode-se falar:
- do modelo do domínio ao se referir a tudo o que está à direita da camada [Web]
- do modelo da visualização, quando se refere aos dados exibidos por uma visualização V
Daqui em diante, o termo “modelo M” se referirá exclusivamente ao modelo de uma vista V.
16.3. Um projeto web / jSON com Spring MVC
O site [http://spring.io/guides] oferece tutoriais introdutórios para conhecer o ecossistema Spring. Seguiremos um deles para descobrir a configuração do Maven necessária para um projeto Spring MVC.
16.3.1. O projeto de demonstração
![]() |
- no [1], importamos um dos guias do Spring;
![]() |
- em [2], selecionamos o exemplo [Rest Service];
- em [3], selecionamos o projeto Maven;
- em [4], selecionamos a versão final do guia;
- em [5], confirmamos;
- em [6], o projeto importado;
Os serviços web acessíveis por meio de URL padrão e que fornecem texto jSON são frequentemente chamados de serviços REST (REpresentational State Transfer). Um serviço é considerado Restful se respeitar determinadas regras.
Vamos agora examinar o projeto importado, começando pela sua configuração do Maven.
16.3.2. Configuração do Maven
O arquivo [pom.xml] é o seguinte:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework</groupId>
<artifactId>gs-rest-service</artifactId>
<version>0.1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.2.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<properties>
<start-class>hello.Application</start-class>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-releases</id>
<url>https://repo.spring.io/libs-release</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-releases</id>
<url>https://repo.spring.io/libs-release</url>
</pluginRepository>
</pluginRepositories>
</project>
- linhas 6-8: as propriedades do projeto Maven. Falta uma tag [<packaging>] indicando o tipo do arquivo gerado pela compilação do Maven. Na ausência dela, é utilizado o tipo [jar]. O aplicativo é, portanto, um aplicativo executável do tipo console, e não um aplicativo web, caso em que o pacote seria [war];
- linhas 10-14: o projeto Maven possui um projeto pai [spring-boot-starter-parent]. É ele que define a maior parte das dependências do projeto. Elas podem ser suficientes, caso em que não se adicionam outras, ou não, caso em que se adicionam as dependências que faltam;
- linhas 17-20: o artefato [spring-boot-starter-web] traz consigo as bibliotecas necessárias para um projeto Spring MVC do tipo serviço web, no qual não há visualizações geradas. Esse artefato traz consigo um grande número de bibliotecas, incluindo as de um servidor Tomcat embutido. É nesse servidor que a aplicação será executada;
As bibliotecas incluídas nesta configuração são muito numerosas:
![]() | ![]() |
Acima, vemos os três arquivos do servidor Tomcat.
16.3.3. A arquitetura de um serviço Spring [web / jSON]
Para um serviço web / jSON, o Spring MVC implementa o modelo MVC da seguinte maneira:
![]() |
- em [4a], o modelo, que é uma classe Java, é transformado na string jSON por uma biblioteca jSON;
- em [4b], essa sequência jSON é enviada ao navegador;
16.3.4. O controlador C
![]() |
O aplicativo importado possui o seguinte controlador:
package hello;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class GreetingController {
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
@RequestMapping("/greeting")
public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
return new Greeting(counter.incrementAndGet(), String.format(template, name));
}
}
- linha 9: a anotação [@RestController] transforma a classe [GreetingController] em um controlador Spring, ou seja, seus métodos são registrados para processar URL. Já vimos a anotação semelhante [@Controller]. O resultado dos métodos desse controlador era um tipo [String], que correspondia ao nome da visualização a ser exibida. Aqui é diferente. Os métodos de um controlador do tipo [@RestController] retornam objetos que são serializados para serem enviados ao navegador. O tipo de serialização realizada depende da configuração do Spring MVC. Aqui, eles serão serializados como jSON. É a presença de uma biblioteca jSON nas dependências do projeto que faz com que o Spring Boot, por meio de autoconfiguração, configure o projeto dessa maneira;
- linha 14: a anotação [@RequestMapping] indica o URL que o método processa, neste caso, o URL [/greeting];
- linha 15: já explicamos a anotação [@RequestParam]. O resultado retornado pelo método é um objeto do tipo [Greeting].
- linha 12: um inteiro longo de tipo atômico. Isso significa que ele suporta concorrência de acesso. Várias threads podem querer incrementar a variável [counter] ao mesmo tempo. Isso ocorrerá de forma segura. Uma thread só pode ler o valor do contador se a thread que está modificando-o tiver concluído sua modificação.
16.3.5. O modelo M
O modelo M gerado pelo método anterior é o seguinte objeto [Greeting]:
![]() |
package hello;
public class Greeting {
private final long id;
private final String content;
public Greeting(long id, String content) {
this.id = id;
this.content = content;
}
public long getId() {
return id;
}
public String getContent() {
return content;
}
}
A transformação jSON desse objeto criará a sequência de caracteres {"id":n,"content":"texto"}. No final, a sequência jSON gerada pelo método do controlador terá o seguinte formato:
ou
16.3.6. Execução
![]() |
A classe [Application.java] é a classe executável do projeto. Seu código é o seguinte:
package hello;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.ComponentScan;
@ComponentScan
@EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Já vimos e explicamos esse código no exemplo anterior. Vamos executar o projeto:
![]() |
Obtemos os seguintes registros de console:
- linha 13: o servidor Tomcat é iniciado na porta 8080 (linha 12);
- linha 17: o servlet [DispatcherServlet] está presente;
- linha 20: o método [GreetingController.greeting] foi detectado;
Para testar a aplicação web, solicitamos o URL [http://localhost:8080/greeting]:
![]() | ![]() |
Recebemos corretamente a sequência jSON esperada. Pode ser interessante verificar os cabeçalhos HTTP enviados pelo servidor. Para isso, vamos usar a extensão do Chrome chamada [Advanced Rest Client] (Chrome / Ctrl-T / Menu [Applications] / [Advanced Rest Client] — ver Anexos, parágrafo 23.11):
![]() |
- em [1], o URL solicitado;
- em [2], é utilizado o método GET;
- em [3], a resposta jSON;
- em [4], o servidor indicou que estava enviando uma resposta no formato jSON;
- em [5], solicita-se o mesmo URL, mas desta vez com um POST;
- em [7], as informações são enviadas ao servidor no formato [urlencoded];
- em [6], o parâmetro name com seu valor;
- em [8], o navegador informa ao servidor que está enviando as informações [urlencoded];
- em [9], a resposta jSON do servidor;
16.3.7. Criação de um arquivo executável
Agora criamos um arquivo executável:
![]() |
![]() |
- em [1]: executamos um alvo do Maven;
- em [2]: há dois alvos (goals): [clean] para excluir a pasta [target] do projeto Maven e [package] para regenerá-la;
- em [3]: a pasta [target] gerada será criada nessa pasta;
- em [4]: gera-se o alvo;
Nos logs que aparecem no console, é importante verificar se o plugin [spring-boot-maven-plugin] está presente. É ele que gera o arquivo executável (veja [pom.xml] abaixo):
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
Na linha de comando, acesse a pasta gerada:
D:\Temp\wksSTS\gs-rest-service\target>dir
...
11/06/2014 15:30 <DIR> classes
11/06/2014 15:30 <DIR> generated-sources
11/06/2014 15:30 11 073 572 gs-rest-service-0.1.0.jar
11/06/2014 15:30 3 690 gs-rest-service-0.1.0.jar.original
11/06/2014 15:30 <DIR> maven-archiver
11/06/2014 15:30 <DIR> maven-status
...
- linha 5: o arquivo gerado;
Esse arquivo é executado da seguinte maneira:
D:\Temp\wksSTS\gs-rest-service-complete\target>java -jar gs-rest-service-0.1.0.jar
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.1.0.RELEASE)
2014-06-11 15:32:47.088 INFO 4972 --- [ main] hello.Application
: Starting Application on Gportpers3 with PID 4972 (D:\Temp\wk
sSTS\gs-rest-service-complete\target\gs-rest-service-0.1.0.jar started by ST in
D:\Temp\wksSTS\gs-rest-service-complete\target)
...
Agora que o aplicativo web foi iniciado, é possível acessá-lo com um navegador:
![]() |
16.3.8. Implantar o aplicativo em um servidor Tomcat
Assim como foi feito no projeto anterior, modificamos o arquivo [pom.xml] da seguinte maneira:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework</groupId>
<artifactId>gs-rest-service</artifactId>
<version>0.1.0</version>
<packaging>war</packaging>
...
</project>
- linha 9: é necessário indicar que será gerado um arquivo WAR (Web ARchive);
Além disso, é necessário configurar a aplicação web. Na ausência do arquivo [web.xml], isso é feito com uma classe que herda de [SpringBootServletInitializer]:
![]() |
A classe [ApplicationInitializer] é a seguinte:
package hello;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;
public class ApplicationInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
}
- linha 6: a classe [ApplicationInitializer] estende a classe [SpringBootServletInitializer];
- linha 9: o método [configure] é redefinido (linha 8);
- linha 10: é fornecida a classe que configura o projeto;
Para executar o projeto, pode-se proceder da seguinte forma:
![]() |
- no [1-2], execute o projeto em um dos servidores registrados no IDE Eclipse;
Feito isso, pode-se acessar o URL [http://localhost:8080/gs-rest-service/greeting/?name=Mitchell] em um navegador:
![]() |
16.4. Conclusion
Introduzimos um tipo de projeto Spring MVC em que a aplicação web envia um fluxo jSON para o navegador. Vamos agora desenvolver uma aplicação web / jSON para disponibilizar na web o banco de dados [dbproduitscategories] estudado nos capítulos anteriores.























