1. Introdução
O PDF deste documento está disponível |AQUI|.
Os exemplos deste documento estão disponíveis |AQUI|.
Propomos aqui apresentar, por meio de exemplos, os conceitos importantes do Spring MVC, um framework Java para a Web que fornece uma estrutura para o desenvolvimento de aplicativos web de acordo com o modelo MVC (Modelo – Visão – Controlador). O Spring MVC é um ramo do ecossistema Spring [http://projects.spring.io/spring-framework/]. Apresentamos também o mecanismo de visualização Thymeleaf [http://www.thymeleaf.org/].
Este curso é destinado a leitores com domínio sólido da linguagem Java. Não é necessário ter conhecimento de programação web.
Embora detalhado, este documento provavelmente está incompleto. O Spring é um framework imenso, com inúmeras ramificações. Para se aprofundar no Spring MVC, pode-se utilizar as seguintes referências:
- o documento de referência do framework Spring [http://docs.spring.io/spring/docs/current/spring-framework-reference/pdf/spring-framework-reference.pdf];
- inúmeros tutoriais sobre o Spring podem ser encontrados no URL [http://spring.io/guides]
- o site do [developpez.com] dedicado ao Spring [http://spring.developpez.com/].
O documento foi escrito de forma a poder ser lido sem a necessidade de um computador à mão. Por isso, são apresentadas muitas capturas de tela.
1.1. Sources
Este documento tem duas fontes principais:
- [Introdução ao framework ASP.NET MVC por meio de exemplos (2013)]. O Spring MVC e o ASP.NET MVC são dois frameworks semelhantes, sendo que o segundo foi desenvolvido bem depois do primeiro. Para poder comparar as duas estruturas, segui a mesma linha de raciocínio do documento sobre ASP.NET e MVC;
- o documento sobre ASP.NET MVC não contém, por enquanto (dezembro de 2014), nenhum estudo de caso com sua solução. Retomei aqui o estudo de caso do documento [Um exemplo de cliente/servidor — AngularJS 1.x / Spring 4 (2014)], que modifiquei da seguinte forma:
- o estudo de caso no [Tutoriel AngularJS / Spring 4] trata de uma aplicação cliente/servidor em que o servidor é um serviço web / jSON desenvolvido com Spring MVC e o cliente, um cliente AngularJS;
- neste documento, retoma-se o mesmo serviço web / jSON, mas o cliente é uma aplicação web de duas camadas [client jQuery] / [service web / jSON];
Além dessas fontes, procurei na Internet as respostas para minhas dúvidas. Foi principalmente o site [http://stackoverflow.com/] que me foi útil.
1.2. As ferramentas utilizadas
Os exemplos a seguir foram testados no seguinte ambiente:
- computador com Windows 8.1 Pro de 64 bits;
- JDK 1.8;
- IDE Spring Tool Suite 3.6.3 (ver parágrafo 9.3);
- navegador Chrome (outros navegadores não foram utilizados);
- extensão do Chrome [Advanced Rest Client] (ver parágrafo 9.6);
Atenção ao JDK 1.8. Um dos métodos do estudo de caso utiliza um método do pacote [java.lang] do Java 8.
Todos os exemplos são projetos Maven que podem ser abertos tanto no Eclipse (IDE) quanto no NetBeans (IntellijIDEA). A seguir, as capturas de tela são do Spring Tool Suite (IDE), uma variante do Eclipse.
1.3. Os exemplos
Os exemplos estão disponíveis no URL [AQUI] na forma de um arquivo zip para download.
![]() |
Para carregar todos os projetos no STS, proceda da seguinte maneira:
![]() |
![]() |
- no [1-3], importe projetos Maven;
![]() |
- em [4], indique a pasta dos exemplos;
- em [5], selecione todos os projetos da pasta;
- em [6], confirme;
- em [7], os projetos importados;
1.4. 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 da camada 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. Aqui, utilizaremos o Hibernate ORM. Uma especificação chamada JPA (Java Persistence API) permite abstrair-se do ORM utilizado, caso este implemente essas especificações. Esse é o caso do Hibernate e de outros ORM Java. Portanto, doravante chamaremos a camada ORM de camada JPA;
- a integração das camadas é feita pelo framework Spring;
A maioria dos exemplos apresentados a seguir utilizará apenas uma camada, a camada [Web]:
![]() |
Este documento terminará, no entanto, com a construção de uma aplicação web multicamadas:
![]() |
O navegador se conectará a uma aplicação [Web1] implementada pelo Spring MVC / Thymeleaf, que irá buscar seus dados de um serviço web [Web2], também implementado com Spring MVC. Essa segunda aplicação web acessará um banco de dados.
1.5. O modelo de desenvolvimento do Spring MVC
O Spring MVC implementa o modelo de arquitetura conhecido como 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 e do [/param1/param2/...] é composto por parâmetros opcionais que serão transmitidos à ação. O C de MVC é, neste caso, a sequência [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
- 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 visualização seja exibida: [3]. Essa visualização exibirá dados chamados de modelo da visualização. 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.
Agora, vamos esclarecer a relação entre a arquitetura web MVC e a arquitetura em camadas. Dependendo da definição que se dá ao modelo, esses dois conceitos podem estar ou não 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, consideremos 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.
1.6. Um primeiro projeto Spring MVC
A partir de agora, trabalharemos com o Spring Tool Suite (IDE), uma variante do Eclipse personalizada para o Spring. O site [http://spring.io/guides] oferece tutoriais introdutórios para conhecer o ecossistema Spring. Vamos seguir um deles para descobrir a configuração do Maven necessária para um projeto Spring MVC.
Observação: a compreensão dos detalhes do projeto ficará além do alcance da maioria dos iniciantes. Isso não é importante. Esses detalhes são explicados mais adiante neste documento. Limitar-nos-emos a reproduzir os passos.
1.6.1. O projeto de demonstração
![]() |
- no [1], importamos um dos guias do Spring;
![]() |
- em [2], selecionamos o exemplo [Serving Web Content];
- em [3], selecionamos o projeto Maven;
- em [4], selecionamos a versão final do guia;
- em [5], confirmamos;
- em [6], o projeto importado;
Vamos examinar o projeto, começando pela sua configuração do Maven.
1.6.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-serving-web-content</artifactId>
<version>0.1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.1.9.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</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-milestone</id>
<url>https://repo.spring.io/libs-release</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-milestone</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, cujo pacote seria, nesse caso, [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-thymeleaf] traz consigo as bibliotecas necessárias para um projeto Spring MVC, utilizado em conjunto com um mecanismo de visualização chamado [Thymeleaf]. Esse artefato traz consigo um grande conjunto 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 arquivos do servidor Tomcat.
O Spring Boot é um ramo do ecossistema Spring [http://projects.spring.io/spring-boot/]. Esse projeto tem como objetivo reduzir ao máximo a configuração dos projetos Spring. Para isso, o Spring Boot realiza a autoconfiguração a partir das dependências presentes no Classpath do projeto. O Spring Boot fornece diversas dependências prontas para uso. Assim, a dependência [spring-boot-starter-thymeleaf] encontrada no projeto Maven anterior traz todas as dependências necessárias para uma aplicação Spring MVC que utiliza o mecanismo de visualização [Thymeleaf]. Com essas duas características:
- dependências prontas para uso;
- autoconfiguração feita a partir dessas dependências e de valores padrão “razoáveis”, é possível ter rapidamente uma aplicação Spring MVC operacional. Esse é o caso do projeto analisado aqui;
1.6.3. A arquitetura de uma aplicação Spring MVC
O Spring MVC implementa o modelo de arquitetura conhecido como MVC (Modelo – Visão – Controlador):
![]() |
O processamento de uma solicitação de um cliente ocorre da seguinte maneira:
- solicitação — as URL solicitadas têm o formato http://machine:port/contexte/Action/param1/param2/....?p1=v1&p2=v2&... A [Dispatcher Servlet] é a classe do Spring que processa as URL recebidas. Ela “encaminha” o URL para a ação que deve processá-lo. Essas ações são métodos de classes específicas chamadas [Contrôleurs]. O C de MVC é, neste caso, a sequência [Dispatcher Servlet, Contrôleur, Action]. Se nenhuma ação tiver sido configurada para processar o URL recebido, o servlet [Dispatcher Servlet] responderá que o URL solicitado não foi encontrado (erro 404 NOT FOUND);
- processamento
- a ação selecionada pode utilizar os parâmetros parami que o servlet [Dispatcher Servlet] 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 da camada [metier] [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 chamados 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.
Vamos examinar esses diferentes elementos no projeto em análise.
1.6.4. O controlador C
![]() |
O aplicativo importado possui o seguinte controlador:
package hello;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class GreetingController {
@RequestMapping("/greeting")
public String greeting(@RequestParam(value="name", required=false, defaultValue="World") String name, Model model) {
model.addAttribute("name", name);
return "greeting";
}
}
- linha 8: a anotação [@Controller] transforma a classe [GreetingController] em um controlador Spring, ou seja, seus métodos são registrados para processar URL. Um controlador Spring é um singleton. Ele é criado em uma única instância;
- linha 11: a anotação [@RequestMapping] indica o URL que o método processa, neste caso, o URL [/greeting]. Veremos mais adiante que esse URL pode ser configurado e que é possível recuperar esses parâmetros;
- linha 12: o método aceita dois parâmetros:
- [String name]: esse parâmetro é inicializado por um parâmetro chamado [name] na consulta processada, por exemplo, [/greeting?name=alfonse]. Esse parâmetro é opcional ([required=false]) e, quando não estiver presente, o parâmetro [name] assumirá o valor 'World' ([defaultValue="World"]),
- [Model model] é um modelo de visualização. Ele é passado vazio, e cabe à ação (o método greeting) preenchê-lo. É esse modelo que será transmitido à visualização que a ação irá exibir. Trata-se, portanto, de um modelo de visualização;
- linha 13: o valor de [name] é inserido no modelo da visualização. A classe [Model] funciona como um dicionário;
- linha 14: o método retorna o nome da visualização que deve exibir o modelo construído. O nome exato da visualização depende da configuração de [Thymeleaf]. Na ausência dessa configuração, a vista exibida aqui será a vista [/templates/greeting.html], ou a pasta [templates] deve estar na raiz do Classpath do projeto;
Vamos examinar nosso projeto no Eclipse:
![]() |
As pastas [src/main/java] e [src/main/resources] são ambas pastas cujo conteúdo será incluído no Classpath do projeto. No caso de [src/main/java], serão as versões compiladas dos códigos-fonte Java que serão incluídas. O conteúdo da pasta [src/main/resources], por sua vez, é inserido no Classpath sem alterações. Vemos, portanto, que a pasta [templates] estará no Classpath do projeto [1].
É possível verificar isso na janela [Navigator] do Eclipse, na pasta [2-3]. A pasta [target] é gerada pela compilação (denominada build) do projeto. A pasta [classes] representa a raiz do Classpath. Percebe-se que a pasta [templates] está presente nela.
1.6.5. A vista V
No MVC, acabamos de ver o controlador C e o modelo de visualização M. A visualização V é representada aqui pelo seguinte arquivo [greeting.html]:
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Getting Started: Serving Web Content</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p th:text="'Hello, ' + ${name} + '!'" />
</body>
</html>
- linha 2: o namespace das tags Thymeleaf;
- linha 8: uma tag <p> (parágrafo) com um atributo Thymeleaf. O atributo [th:text] define o conteúdo do parágrafo. Dentro da sequência de caracteres, temos a expressão [${name}]. Isso significa que queremos o valor do atributo [name] do modelo da visualização. Ora, lembramos que esse atributo foi inserido no modelo pela ação:
model.addAttribute("name", name);
O primeiro parâmetro define o nome do atributo, o segundo, seu valor.
1.6.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);
}
}
- linha 11: a classe é executável com um método [main] específico para aplicativos de console. A classe [SpringApplication] da linha 12 iniciará o servidor Tomcat presente nas dependências e implantará o serviço web nele;
- linha 4: vemos que a classe [SpringApplication] pertence ao projeto [Spring Boot];
- linha 12: o primeiro parâmetro é a classe que configura o projeto; o segundo, eventuais parâmetros;
- linha 8: a anotação [@EnableAutoConfiguration] solicita que o Spring Boot configure o projeto;
- linha 7: a anotação [@ComponentScan] faz com que a pasta que contém a classe [Application] seja explorada para localizar os componentes do Spring. Será encontrado um, a classe [GreetingController], que possui a anotação [@Controller], o que a torna um componente Spring;
Vamos executar o projeto:
![]() |
Obtemos os seguintes logs 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 [hello.GreetingController.greeting] foi detectado, assim como o URL, que processa o [/greeting];
Para testar a aplicação web, solicitamos o URL e o [http://localhost:8080/greeting]:
![]() | ![]() |
Pode ser interessante verificar os cabeçalhos HTTP enviados pelo servidor. Para isso, vamos usar o plugin do Chrome chamado [Advanced Rest Client] (ver parágrafo 9.6):
![]() |
- em [1], o URL solicitado;
- em [2], o método GET é utilizado;
- em [3], o servidor indicou que estava enviando uma resposta no formato HTML;
- em [4], a resposta HTML;
- em [5], solicita-se o mesmo URL, mas desta vez com um POST;
- em [7], as informações são enviadas ao servidor na forma [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 HTML do servidor;
Para encerrar o aplicativo:
![]() | ![]() | ![]() |
1.6.7. Criação de um arquivo executável
É possível criar um arquivo executável fora do Eclipse. A configuração necessária está no arquivo [pom.xml]:
<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>
- as linhas 7 a 10 definem o plug-in que criará o arquivo executável;
- a linha 2 define a classe executável do projeto;
O procedimento é o seguinte:
![]() |
- em [1]: executa-se um alvo do Maven;
![]() |
- em [2]: há dois objetivos (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;
Observação: para que a geração seja bem-sucedida, é necessário que o JVM utilizado pelo STS seja um JDK [Window / Preferences / Java / Installed JREs]:
![]() |
Nos logs exibidos no console, é importante que o plugin [spring-boot-maven-plugin] apareça. É ele que gera o arquivo executável.
Usando um terminal, acesse a pasta gerada:
gs-serving-web-content-complete\target>dir
...
Répertoire de D:\data\istia-1415\spring mvc\dvp\gs-serving-web-content-complete
\target
27/11/2014 17:07 <DIR> .
27/11/2014 17:07 <DIR> ..
27/11/2014 17:07 <DIR> classes
27/11/2014 17:07 <DIR> generated-sources
27/11/2014 17:07 13 419 551 gs-serving-web-content-0.1.0.jar
27/11/2014 17:07 3 522 gs-serving-web-content-0.1.0.jar.original
27/11/2014 17:07 <DIR> maven-archiver
27/11/2014 17:07 <DIR> maven-status
- linha 12: o arquivo gerado;
Esse arquivo é executado da seguinte maneira:
gs-serving-web-content-complete\target>java -jar gs-serving-web-content-0.1.0.jar
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.1.9.RELEASE)
2014-11-27 17:14:50.439 INFO 8172 --- [ main] hello.Application : Starting Application on Gportpers3 with PID 8172 (D:\data\istia-1415\spring mvc\dvp\gs-serving-web-content-complete\target\gs-serving-web-content-0.1.0.jar started by ST in D:\data\istia-1415\spring mvc\dvp\gs-serving-web-content-complete\target)
2014-11-27 17:14:50.491 INFO 8172 --- [ main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@12f4ec3a: startup date [Thu Nov 27 17:14:50 CET 2014]; root of context hierarchy
Observação: é necessário, antes disso, encerrar o serviço web que possa ter sido iniciado no Eclipse (ver página 17).
Agora que o aplicativo web está em execução, é possível acessá-lo por meio de um navegador:
![]() |
1.6.8. Implantar a aplicação em um servidor Tomcat
Embora o Spring Boot seja muito prático no modo de desenvolvimento, uma aplicação em produção será implantada em um servidor Tomcat real. Veja como proceder:
Altere 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-serving-web-content</artifactId>
<version>0.1.0</version>
<packaging>war</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.1.9.RELEASE</version>
</parent>
<dependencies>
<!-- ambiente Thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- geração do WAR -->
<!-- <dependência>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</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-milestone</id>
<url>https://repo.spring.io/libs-release</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-milestone</id>
<url>https://repo.spring.io/libs-release</url>
</pluginRepository>
</pluginRepositories>
</project>
As alterações devem ser feitas em dois locais:
- linha 9: é preciso indicar que será gerado um arquivo WAR (Web ARchive);
- linhas 24-28: é preciso adicionar uma dependência do artefato [spring-boot-starter-tomcat]. Esse artefato inclui todas as classes do Tomcat nas dependências do projeto;
- linha 27: esse artefato é o [provided], ou seja, os arquivos correspondentes não serão incluídos no WAR gerado. Na verdade, esses arquivos estarão no servidor Tomcat no qual a aplicação será executada;
Na verdade, se observarmos as dependências atuais do projeto, percebemos que a dependência [spring-boot-starter-tomcat] já está presente:
![]() |
Portanto, não há necessidade de adicioná-la ao arquivo [pom.xml]. Colocamos essa dependência entre comentários apenas para registro.
Além disso, é preciso 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:
![]() |
- em [1], execute o projeto em um dos servidores registrados no Eclipse IDE;
- no [2], seleciona-se acima o [Tomcat v8.0];
Feito isso, é possível acessar o URL [http://localhost:8080/gs-rest-service/greeting/?name=Mitchell] em um navegador:
![]() |
Observação: dependendo das versões do [tomcat] e do [tc Server Developer], essa execução pode falhar. Esse foi o caso, por exemplo, com o [Apache Tomcat 8.0.3 et 8.0.15]. No exemplo acima, a versão do Tomcat utilizada foi o [8.0.9].
Agora sabemos como gerar um arquivo WAR. A partir daqui, continuaremos trabalhando com o Spring Boot e seu arquivo JAR executável.
1.7. Um segundo projeto Spring: MVC
1.7.1. O projeto de demonstração
![]() |
- em [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). Neste documento, vou me limitar a chamar o serviço que vamos construir de serviço web / jSON. Um serviço é considerado Restful se respeitar certas regras. Não procurei respeitar essas regras.
Vamos agora examinar o projeto importado, começando pela sua configuração do Maven.
1.7.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.1.9.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.
1.7.3. A arquitetura de um serviço Spring [web / jSON]
Vamos relembrar como o Spring MVC implementa o modelo MVC:
![]() |
O processamento de uma solicitação de um cliente ocorre da seguinte maneira:
- solicitação — os URL solicitados têm o formato http://machine:port/contexte/Action/param1/param2/....?p1=v1&p2=v2&... O [Dispatcher Servlet] é a classe do Spring que processa os URL recebidos. Ela “encaminha” o URL para a ação que deve processá-lo. Essas ações são métodos de classes específicas chamadas [Contrôleurs]. O C de MVC é, neste caso, a string [Dispatcher Servlet, Contrôleur, Action]. Se nenhuma ação tiver sido configurada para processar o URL recebido, o servlet [Dispatcher Servlet] responderá que o URL solicitado não foi encontrado (erro 404 NOT FOUND);
- processamento
- a ação selecionada pode utilizar os parâmetros parami que o servlet [Dispatcher Servlet] 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,
- de parâmetros enviados pelo navegador junto com sua solicitação;
- no processamento da solicitação do usuário, a ação pode precisar da camada [metier] [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 na string jSON por uma biblioteca jSON;
- em [4b], essa string jSON é enviada ao navegador;
1.7.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.
1.7.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:
{"id":2,"content":"Hello, World!"}
ou
{"id":2,"content":"Hello, John!"}
1.7.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á abordamos e explicamos esse código no exemplo anterior.
1.7.7. Execução do projeto
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, de fato, a sequência esperada jSON.
Observação: este exemplo não funcionou com o navegador integrado do Eclipse.
Pode ser interessante verificar os cabeçalhos HTTP enviados pelo servidor. Para isso, vamos usar o plugin do Chrome chamado [Advanced Rest Client] (ver Anexos, parágrafo 9.6):
![]() |
- 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;
1.7.8. Criação de um arquivo executável
Assim como fizemos no projeto anterior, 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.
Usando um terminal, 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)
...
Observação: é necessário, antes disso, encerrar o serviço web que possa ter sido iniciado no Eclipse (ver parágrafo 1.6.6).
Agora que o aplicativo web foi iniciado, é possível acessá-lo por meio de um navegador:
![]() |
1.7.9. Implantar o aplicativo em um servidor Tomcat
Assim como fizemos 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 por meio de 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:
![]() |
1.8. Conclusion
Introduzimos dois tipos de projetos Spring MVC:
- um projeto em que a aplicação web envia um fluxo HTML para o navegador. Esse fluxo é gerado pelo mecanismo de visualização [Thymeleaf];
- um projeto em que a aplicação web envia um fluxo jSON para o navegador;
No primeiro caso, o projeto requer duas dependências do Maven:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.1.9.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>
No segundo caso, as dependências do Maven são as seguintes:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.1.9.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
As dependências geradas em cascata por essas configurações são muito numerosas e muitas delas são desnecessárias. Para a implantação da aplicação, utilizaremos uma configuração manual do Maven, na qual estarão presentes apenas as dependências necessárias ao projeto.
Vamos agora voltar aos fundamentos da programação web, apresentando dois conceitos básicos:
- o diálogo HTTP (HyperText Transfer Protocol) entre um navegador e uma aplicação web;
- a linguagem HTML (HyperText Markup Language), que o navegador interpreta para exibir uma página que recebeu;


















































