1. Introdução
O PDF deste documento está disponível |AQUI|.
Os exemplos deste documento estão disponíveis |AQUI|.
O objetivo deste documento é apresentar, através de exemplos, os conceitos-chave do Spring MVC, um framework web Java que fornece uma estrutura para o desenvolvimento de aplicações web de acordo com o padrão MVC (Model–View–Controller). O Spring MVC é um ramo do ecossistema Spring [http://projects.spring.io/spring-framework/]. Apresentamos também o motor de visualização Thymeleaf [http://www.thymeleaf.org/].
Este curso destina-se a leitores com um domínio sólido da linguagem Java. Não é necessário ter conhecimentos prévios de programação web.
Embora detalhado, este documento provavelmente está incompleto. O Spring é uma estrutura vasta com muitos ramos. Para saber mais sobre o Spring MVC, pode consultar os seguintes recursos:
- 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 em [http://spring.io/guides]
- o site [developpez.com] dedicado ao Spring [http://spring.developpez.com/].
Este documento foi escrito de forma a poder ser lido sem um computador à mão. Por isso, estão incluídas muitas capturas de ecrã.
1.1. Fontes
Este documento tem duas fontes principais:
- [Introdução ao ASP.NET MVC por meio de exemplos]. O Spring MVC e o ASP.NET MVC são duas estruturas semelhantes, tendo a última sido desenvolvida muito depois da primeira. Para comparar as duas estruturas, segui a mesma progressão do documento sobre o ASP.NET MVC;
- o documento sobre ASP.NET MVC não contém atualmente (dezembro de 2014) um estudo de caso com a sua solução. Utilizei aqui o do documento [Tutorial AngularJS / Spring 4], que modifiquei da seguinte forma:
- O estudo de caso em [Tutorial AngularJS / Spring 4] é o de uma aplicação cliente/servidor em que o servidor é um serviço web / JSON construído com Spring MVC e o cliente é um cliente AngularJS;
- neste documento, utilizamos o mesmo serviço web/JSON, mas o cliente é uma aplicação web de duas camadas [cliente jQuery] / [serviço web/JSON];
Para além destas fontes, pesquisei na Internet respostas às minhas perguntas. O site [http://stackoverflow.com/] foi particularmente útil para mim.
1.2. Ferramentas utilizadas
Os exemplos seguintes foram testados no ambiente a seguir:
- Máquina com Windows 8.1 Pro de 64 bits;
- JDK 1.8;
- IDE Spring Tool Suite 3.6.3 (ver Secção 9.3);
- Navegador Chrome (não foram utilizados outros navegadores);
- Extensão do Chrome [Advanced Rest Client] (ver secção 9.6);
Nota relativa 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 no Eclipse, IntelliJ IDEA ou NetBeans. A seguir, as capturas de ecrã são do IDE Spring Tool Suite, uma variante do Eclipse.
1.3. Os exemplos
Os exemplos estão disponíveis |AQUI| como um ficheiro ZIP para download.
![]() |
Para carregar todos os projetos no STS, proceda da seguinte forma:
![]() |
![]() |
- Em [1-3], importe os projetos Maven;
![]() |
- em [4], especifique a pasta de exemplos;
- Em [5], selecione todos os projetos na pasta;
- em [6], confirme;
- em [7], os projetos importados;
1.4. O papel do Spring MVC numa aplicação web
Vamos situar o Spring MVC no contexto do desenvolvimento de uma aplicação web. Na maioria das vezes, esta será construída numa arquitetura multicamadas, como a seguinte:
![]() |
- a camada [Web] é a camada em contacto com o utilizador da aplicação web. O utilizador interage com a aplicação web através de páginas web visualizadas num navegador. O Spring MVC está localizado nesta camada e apenas nesta camada;
- a camada [business] implementa a lógica de negócio da aplicação, como o cálculo de um salário ou de uma fatura. Esta camada utiliza dados do utilizador através da camada [Web] e do SGBD através da camada [DAO];
- a camada [DAO] (Data Access Objects), a camada [ORM] (Object Relational Mapper) e o controlador JDBC gerem o acesso aos dados no SGBD. A camada [ORM] atua como uma ponte entre os objetos tratados pela camada [DAO] e as linhas e colunas das tabelas numa base de dados relacional. Aqui iremos utilizar o ORM Hibernate. Uma especificação denominada JPA (Java Persistence API) permite-nos abstrair-nos do ORM específico utilizado, desde que este implemente estas especificações. É o caso do Hibernate e de outros ORMs Java. Por conseguinte, doravante referir-nos-emos à camada ORM como a camada JPA;
- a integração das camadas é gerida pela estrutura Spring;
A maioria dos exemplos apresentados abaixo utilizará apenas uma única camada, a camada [Web]:
![]() |
No entanto, este documento terminará com a construção de uma aplicação web de várias camadas:
![]() |
O navegador irá ligar-se a uma aplicação [Web1] implementada utilizando Spring MVC / Thymeleaf, que irá recuperar os seus dados de um serviço web [Web2] também implementado com Spring MVC. Esta segunda aplicação web irá aceder a uma base de dados.
1.5. O Modelo de Desenvolvimento Spring MVC
O Spring MVC implementa o padrão arquitetónico MVC (Modelo–Visão–Controlador) da seguinte forma:
![]() |
O processamento de um pedido do cliente decorre da seguinte forma:
- solicitação - os URLs solicitados têm o formato http://machine:port/contexte/Action/param1/param2/....?p1=v1&p2=v2&... O [Front Controller] utiliza um ficheiro de configuração ou anotações Java para «encaminhar» a solicitação para o controlador correto e para a ação correta dentro desse controlador. Para tal, utiliza o campo [Action] do URL. O resto da URL [/param1/param2/...] consiste em parâmetros opcionais que serão passados para a ação. O C em MVC aqui refere-se à cadeia [Front Controller, Controller, Action]. Se nenhum controlador puder lidar com a ação solicitada, o servidor web responderá que a URL solicitada não foi encontrada.
- processamento
- A ação selecionada pode utilizar os parâmetros que o [Front Controller] lhe passou. Estes podem provir de várias fontes:
- o caminho [/param1/param2/...] da URL,
- os parâmetros [p1=v1&p2=v2] da URL,
- dos parâmetros enviados pelo navegador com o seu pedido;
- ao processar a solicitação do utilizador, a ação pode necessitar da camada [business] [2b]. Uma vez processada a solicitação do cliente, ela pode desencadear várias respostas. Um exemplo clássico é:
- uma página de erro, se a solicitação não puder ser processada corretamente
- uma página de confirmação, caso contrário
- A ação instrui uma vista específica a renderizar [3]. Esta vista irá apresentar dados conhecidos como o modelo de vista. Este é o «M» em MVC. A ação irá criar este modelo de vista [2c] e instruir uma vista a renderizar [3];
- Resposta - a vista selecionada V utiliza o modelo M construído pela ação para inicializar as partes dinâmicas da resposta HTML que 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 de como definimos o modelo, estes dois conceitos podem ou não estar relacionados. Consideremos uma aplicação web Spring MVC de camada única:
![]() |
Se implementarmos a camada [Web] com Spring MVC, teremos, de facto, uma arquitetura web MVC, mas não uma arquitetura em camadas. Aqui, a camada [Web] tratará de tudo: apresentação, lógica de negócio e acesso aos dados. São as ações que realizarão este trabalho.
Agora, vamos considerar uma arquitetura web multicamadas:
![]() |
A camada [Web] pode ser implementada sem um framework e sem seguir o modelo MVC. Temos, então, uma arquitetura multicamadas, mas a camada Web não implementa o modelo MVC.
Por exemplo, no mundo .NET, a camada [Web] acima pode ser implementada com ASP.NET MVC, resultando numa arquitetura em camadas com uma camada [Web] de estilo MVC. Uma vez feito isto, podemos substituir esta camada ASP.NET MVC por uma camada ASP.NET clássica (WebForms), mantendo o resto (lógica de negócio, DAO, ORM) inalterado. Temos então uma arquitetura em camadas com uma camada [Web] que já não é baseada em MVC.
No MVC, dissemos que o modelo M era o da vista V, ou seja, o conjunto de dados exibidos pela vista V. É apresentada outra definição do modelo M no MVC:
![]() |
Muitos autores consideram que o que se encontra à direita da camada [Web] constitui o modelo M do MVC. Para evitar ambiguidades, podemos referir-nos a:
- o modelo de domínio quando nos referimos a tudo à direita da camada [Web]
- o modelo de vista quando nos referimos aos dados apresentados por uma vista V
Daqui em diante, o termo «modelo M» referir-se-á exclusivamente ao modelo de uma vista V.
1.6. Um primeiro projeto Spring MVC
A partir de agora, iremos trabalhar com o IDE Spring Tool Suite (STS), uma versão do Eclipse personalizada para o Spring. O site [http://spring.io/guides] oferece tutoriais de introdução para explorar o ecossistema Spring. Iremos seguir um deles para aprender a configuração do Maven necessária para um projeto Spring MVC.
Nota: A maioria dos principiantes não compreenderá totalmente os detalhes do projeto. Isso não é importante. Estes detalhes são explicados mais adiante neste documento. Vamos simplesmente seguir os passos.
1.6.1. O projeto de demonstração
![]() |
- Em [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 ficheiro [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>] que especifique o tipo de ficheiro produzido pela compilação do Maven. Na sua ausência, é utilizado o tipo [jar]. A aplicação é, portanto, uma aplicação executável baseada em consola, e não uma aplicação web, em que o tipo de empacotamento seria [war];
- linhas 10–14: O projeto Maven tem um projeto pai [spring-boot-starter-parent]. Este define a maioria das dependências do projeto. Estas podem ser suficientes, caso em que não são adicionadas dependências adicionais, ou podem não ser, caso em que as dependências em falta são adicionadas;
- Linhas 17–20: O artefacto [spring-boot-starter-thymeleaf] inclui as bibliotecas necessárias para um projeto Spring MVC utilizado em conjunto com um motor de visualização chamado [Thymeleaf]. Este artefacto inclui um número muito grande de bibliotecas, incluindo as destinadas a um servidor Tomcat incorporado. A aplicação será executada neste servidor;
As bibliotecas incluídas nesta configuração são numerosas:
![]() | ![]() |
Acima, vemos os arquivos do servidor Tomcat.
O Spring Boot é um ramo do ecossistema Spring [http://projects.spring.io/spring-boot/]. Este projeto tem como objetivo minimizar a configuração necessária para projetos Spring. Para tal, o Spring Boot realiza uma configuração automática com base nas dependências presentes no classpath do projeto. O Spring Boot fornece muitas dependências prontas a usar. Por exemplo, a dependência [spring-boot-starter-thymeleaf] encontrada no projeto Maven anterior inclui todas as dependências necessárias para uma aplicação Spring MVC que utilize o motor de visualização [Thymeleaf]. Com estas duas funcionalidades:
- dependências prontas a usar;
- configuração automática com base nessas dependências e valores padrão «razoáveis», é possível ter muito rapidamente uma aplicação Spring MVC funcional. É o caso do projeto aqui estudado;
1.6.3. A arquitetura de uma aplicação Spring MVC
O Spring MVC implementa o padrão arquitetónico MVC (Modelo–Visão–Controlador):
![]() |
O processamento de um pedido do cliente decorre da seguinte forma:
- solicitação - os URLs solicitados têm o formato http://machine:port/contexte/Action/param1/param2/....?p1=v1&p2=v2&... O [Dispatcher Servlet] é a classe Spring que lida com os URLs recebidos. Ele «encaminha» o URL para a ação que deve tratá-lo. Estas ações são métodos de classes específicas chamadas [Controllers]. O C em MVC aqui é a cadeia [Dispatcher Servlet, Controller, Action]. Se nenhuma ação tiver sido configurada para tratar a URL recebida, o [Dispatcher Servlet] responderá que a URL solicitada não foi encontrada (erro 404 NOT FOUND);
- o processamento
- a ação selecionada pode utilizar os parâmetros que o [Servlet Dispatcher] lhe passou. Estes podem provir de várias fontes:
- o caminho [/param1/param2/...] da URL,
- os parâmetros da URL [p1=v1&p2=v2],
- dos parâmetros enviados pelo navegador com o seu pedido;
- ao processar a solicitação do utilizador, a ação pode necessitar da camada [de negócios] [2b]. Uma vez processada a solicitação do cliente, ela pode desencadear várias respostas. Um exemplo clássico é:
- uma página de erro, se a solicitação não puder ser processada corretamente
- uma página de confirmação, caso contrário
- a ação instrui que uma vista específica seja exibida [3]. Esta vista exibirá dados conhecidos como o modelo de vista. Este é o M em MVC. A ação criará este modelo M [2c] e instruirá que uma vista V seja exibida [3];
- resposta - a vista V selecionada utiliza o modelo M construído pela ação para inicializar as partes dinâmicas da resposta HTML que deve enviar ao cliente e, em seguida, envia essa resposta.
Iremos examinar estes diferentes elementos no projeto em estudo.
1.6.4. O controlador C
![]() |
A aplicação importada tem 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] torna a classe [GreetingController] um controlador Spring, o que significa que os seus métodos são registados para tratar URLs. Um controlador Spring é um singleton. Apenas é criada uma única instância;
- linha 11: a anotação [@RequestMapping] especifica a URL tratada pelo método, neste caso a URL [/greeting]. Veremos mais adiante que esta URL pode ser parametrizada e que é possível recuperar esses parâmetros;
- linha 12: o método aceita dois parâmetros:
- [String name]: este parâmetro é inicializado por um parâmetro chamado [name] na solicitação processada, por exemplo [/greeting?name=alfonse]. Este parâmetro é opcional [required=false] e, quando não está presente, o parâmetro [name] assumirá o valor 'World' [defaultValue="World"],
- [Model model] é um modelo de visualização. É passado vazio, e cabe à ação (ao método greeting) preenchê-lo. Este modelo será passado para a visualização que a ação irá renderizar. É, portanto, um modelo de visualização;
- linha 13: o valor de [name] é colocado no modelo de visualização. A classe [Model] comporta-se como um dicionário;
- linha 14: o método devolve o nome da vista que deve apresentar o modelo construído. O nome exato da vista depende da configuração [Thymeleaf]. Na ausência dessa configuração, a vista apresentada aqui será [/templates/greeting.html], onde a pasta [templates] deve estar na raiz do classpath do projeto;
Vamos examinar o nosso projeto Eclipse:
![]() |
As pastas [src/main/java] e [src/main/resources] são ambas pastas cujo conteúdo será adicionado ao Classpath do projeto. No caso de [src/main/java], as versões compiladas do código-fonte Java serão colocadas aí. O conteúdo da pasta [src/main/resources] é adicionado ao Classpath sem modificações. Podemos, portanto, ver que a pasta [templates] estará no Classpath do projeto [1].
Pode verificar isto [2-3] na janela [Navigator] do Eclipse [Window / Show view / Other / General / Navigator]. A pasta [target] é criada ao compilar (ou «construir») o projeto. A pasta [classes] representa a raiz do Classpath. Pode ver que a pasta [templates] está presente aí.
1.6.5. A Vista V
No MVC, acabámos de ver o controlador C e o modelo M. A vista V é aqui representada pelo seguinte ficheiro [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 da tag 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 string, temos a expressão [${name}]. Isto significa que queremos o valor do atributo [name] do modelo de visualização. Agora, lembre-se de que este atributo foi adicionado ao modelo pela ação:
model.addAttribute("name", name);
O primeiro parâmetro define o nome do atributo e o segundo define o seu valor.
1.6.6. Execução
![]() |
A classe [Application.java] é a classe executável do projeto. O 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 aplicações de consola. A classe [SpringApplication] na linha 12 irá iniciar o servidor Tomcat presente nas dependências e implementar o serviço web nele;
- linha 4: podemos ver que a classe [SpringApplication] pertence ao projeto [Spring Boot];
- linha 12: o primeiro parâmetro é a classe que configura o projeto, o segundo contém quaisquer parâmetros adicionais;
- linha 8: a anotação [@EnableAutoConfiguration] instrui o Spring Boot a configurar o projeto;
- linha 7: a anotação [@ComponentScan] faz com que o diretório que contém a classe [Application] seja verificado em busca de componentes Spring. Será encontrado um: a classe [GreetingController], que possui a anotação [@Controller], tornando-a um componente Spring;
Vamos executar o projeto:
![]() |
Recebemos os seguintes registos da consola:
- linha 13: o servidor Tomcat inicia na porta 8080 (linha 12);
- linha 17: o servlet [DispatcherServlet] está presente;
- linha 20: o método [hello.GreetingController.greeting] foi detetado, juntamente com o URL que ele processa [/greeting];
Para testar a aplicação web, solicitamos a URL [http://localhost:8080/greeting]:
![]() | ![]() |
Pode ser interessante ver os cabeçalhos HTTP enviados pelo servidor. Para tal, utilizaremos o plugin do Chrome chamado [Advanced Rest Client] (ver secção 9.6):
![]() |
- em [1], o URL solicitado;
- em [2], é utilizado o método GET;
- em [3], o servidor indicou que estava a enviar uma resposta em formato HTML;
- em [4], a resposta HTML;
- em [5], solicitamos a mesma URL, mas desta vez utilizando uma solicitação POST;
- em [7], a informação é enviada para o servidor no formato [urlencoded];
- em [6], o parâmetro name com o seu valor;
- em [8], o navegador informa ao servidor que está a enviar informações [urlencoded];
- em [9], a resposta HTML do servidor;
![]() | ![]() | ![]() |
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 encontra-se no ficheiro [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–10 definem o plugin que irá criar o arquivo executável;
- A linha 2 define a classe executável do projeto;
Eis como proceder:
![]() |
- em [1]: executamos uma meta do Maven;
![]() |
- em [2]: existem dois objetivos: [clean] para eliminar a pasta [target] do projeto Maven, [package] para a regenerar;
- em [3]: a pasta [target] gerada será criada nesta pasta;
- em [4]: o alvo é gerado;
Nota: para que a geração seja bem-sucedida, a JVM utilizada pelo STS deve ser um JDK [Janela / Preferências / Java / JREs instalados]:
![]() |
Nos registos que aparecem na consola, é importante verificar se o plugin [spring-boot-maven-plugin] está presente. Este é o plugin que gera o arquivo executável.
Utilizando um console, navegue até à 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;
Este arquivo é executado da seguinte forma:
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
Nota: Deve primeiro parar qualquer serviço web que possa ter sido iniciado no Eclipse (ver página 17).
Agora que a aplicação web está em execução, pode aceder-lhe utilizando um navegador:
![]() |
1.6.8. Implantação da aplicação num servidor Tomcat
Embora o Spring Boot seja muito prático no modo de desenvolvimento, uma aplicação de produção será implementada num servidor Tomcat real. Eis como proceder:
Modifique o ficheiro [pom.xml] da seguinte forma:
<?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>
<!-- thymeleaf environment -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- war generation -->
<!-- <dependency>
<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>
É necessário efetuar alterações em dois locais:
- linha 9: deve especificar que vai gerar um ficheiro WAR (Web Archive);
- linhas 24–28: deve adicionar uma dependência do artefacto [spring-boot-starter-tomcat]. Este artefacto inclui todas as classes do Tomcat nas dependências do projeto;
- linha 27: este artefacto é [fornecido], o que significa que os arquivos correspondentes não serão incluídos no WAR gerado. Em vez disso, esses arquivos estarão localizados no servidor Tomcat onde a aplicação será executada;
De facto, se analisarmos as dependências atuais do projeto, verificamos que a dependência [spring-boot-starter-tomcat] já está presente:
![]() |
Não é, portanto, necessário adicioná-lo ao ficheiro [pom.xml]. Colocámo-lo entre comentários para referência.
Também precisamos de configurar a aplicação web. Na ausência de um ficheiro [web.xml], isto é feito utilizando uma classe que estende [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] é reescrito (linha 8);
- linha 10: é fornecida a classe que configura o projeto;
Para executar o projeto, proceda da seguinte forma:
![]() |
- em [1], execute o projeto num dos servidores registados no IDE Eclipse;
- em [2], selecione [Tomcat v8.0] acima;
Depois de fazer isso, pode introduzir o URL [http://localhost:8080/gs-rest-service/greeting/?name=Mitchell] num navegador:
![]() |
Nota: Dependendo das versões do [Tomcat] e do [TC Server Developer], esta execução pode falhar. Foi o que aconteceu com o [Apache Tomcat 8.0.3 e 8.0.15], por exemplo. No exemplo acima, a versão do Tomcat utilizada foi a [8.0.9].
Agora sabemos como gerar um arquivo WAR. A seguir, continuaremos a trabalhar com o Spring Boot e o 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 através de URLs padrão que devolvem dados JSON são frequentemente designados por serviços REST (REpresentational State Transfer). Neste documento, referir-me-ei simplesmente ao serviço que vamos construir como um serviço web/JSON. Diz-se que um serviço é RESTful se seguir determinadas regras. Não tentei cumprir essas regras.
Vamos agora examinar o projeto importado, começando pela sua configuração do Maven.
1.7.2. Configuração do Maven
O ficheiro [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>] que especifique o tipo de ficheiro produzido pela compilação do Maven. Na sua ausência, é utilizado o tipo [jar]. A aplicação é, portanto, uma aplicação executável baseada em consola, e não uma aplicação web, caso em que a embalagem seria [war];
- linhas 10–14: O projeto Maven tem um projeto pai [spring-boot-starter-parent]. Este define a maioria das dependências do projeto. Estas podem ser suficientes, caso em que não são adicionadas dependências adicionais, ou podem não ser, caso em que as dependências em falta são adicionadas;
- linhas 17–20: O artefacto [spring-boot-starter-web] inclui as bibliotecas necessárias para um projeto de serviço web Spring MVC onde não são geradas vistas. Este artefacto inclui um número muito grande de bibliotecas, incluindo as destinadas a um servidor Tomcat incorporado. A aplicação será executada neste servidor;
As bibliotecas incluídas nesta configuração são numerosas:
![]() | ![]() |
Acima, vemos os três arquivos do servidor Tomcat.
1.7.3. A arquitetura de um serviço Spring [web / JSON]
Vamos rever como o Spring MVC implementa o modelo MVC:
![]() |
O processamento de um pedido de um cliente decorre da seguinte forma:
- solicitação - as URLs solicitadas têm o formato http://machine:port/contexte/Action/param1/param2/....?p1=v1&p2=v2&... O [Dispatcher Servlet] é a classe Spring que lida com as URLs recebidas. Ele «encaminha» a URL para a ação que deve processá-la. Estas ações são métodos de classes específicas chamadas [Controllers]. O C em MVC aqui é a cadeia [Dispatcher Servlet, Controller, Action]. Se nenhuma ação tiver sido configurada para lidar com a URL recebida, o [Dispatcher Servlet] responderá que a URL solicitada não foi encontrada (erro 404 NOT FOUND);
- o processamento
- a ação selecionada pode utilizar os parâmetros que o [Servlet Dispatcher] lhe passou. Estes podem provir de várias fontes:
- o caminho [/param1/param2/...] da URL,
- os parâmetros da URL [p1=v1&p2=v2],
- dos parâmetros enviados pelo navegador com o seu pedido;
- ao processar a solicitação do utilizador, a ação pode necessitar da camada [de negócios] [2b]. Uma vez processada a solicitação do cliente, ela pode desencadear várias respostas. Um exemplo clássico é:
- uma página de erro, se a solicitação não puder ser processada corretamente
- uma página de confirmação, caso contrário
- a ação instrui uma vista específica a renderizar [3]. Esta vista irá apresentar dados conhecidos como o modelo de vista. Este é o M em MVC. A ação irá criar este modelo M [2c] e instruir uma vista V a renderizar [3];
- Resposta - a vista V selecionada utiliza o modelo M criado pela ação para inicializar as partes dinâmicas da resposta HTML que 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, é convertido numa cadeia JSON por uma biblioteca JSON;
- em [4b], esta cadeia JSON é enviada para o navegador;
1.7.4. O controlador C
![]() |
A aplicação importada tem 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] torna a classe [GreetingController] um controlador Spring, o que significa que os seus métodos estão registados para tratar de URLs. Já vimos a anotação semelhante [@Controller]. O tipo de retorno dos métodos desse controlador era [String], que era o nome da vista a apresentar. Aqui, é diferente. Os métodos de um [@RestController] devolvem objetos que são serializados para serem enviados para o navegador. O tipo de serialização realizada depende da configuração do Spring MVC. Aqui, serão serializados para JSON. É a presença de uma biblioteca JSON nas dependências do projeto que faz com que o Spring Boot configure automaticamente o projeto desta forma;
- linha 14: a anotação [@RequestMapping] especifica a URL tratada pelo método, neste caso a URL [/greeting];
- linha 15: já explicámos a anotação [@RequestParam]. O resultado devolvido pelo método é um objeto do tipo [Greeting].
- linha 12: um inteiro longo de tipo atómico. Isto significa que suporta acesso simultâneo. Várias threads podem querer incrementar a variável [counter] ao mesmo tempo. Isto será tratado corretamente. Uma thread só pode ler o valor do contador depois de a thread que o está a modificar ter concluído a sua modificação.
1.7.5. O modelo M
O modelo M produzido 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 conversão deste objeto para JSON irá criar a string {"id":n,"content":"text"}. Por fim, a string JSON produzida pelo método do controlador terá o seguinte formato:
{"id":2,"content":"Hello, World!"}
ou
{"id":2,"content":"Olá, John!"}
1.7.6. Execução
![]() |
A classe [Application.java] é a classe executável do projeto. O 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á nos deparámos com este código e explicámo-lo no exemplo anterior.
1.7.7. Executar o projeto
![]() |
Recebemos os seguintes registos da consola:
- linha 13: o servidor Tomcat inicia na porta 8080 (linha 12);
- linha 17: o servlet [DispatcherServlet] está presente;
- linha 20: o método [GreetingController.greeting] foi descoberto;
Para testar a aplicação web, solicitamos a URL [http://localhost:8080/greeting]:
![]() | ![]() |
Recebemos a cadeia JSON esperada.
Nota: Este exemplo não funcionou com o navegador integrado do Eclipse.
Pode ser útil visualizar os cabeçalhos HTTP enviados pelo servidor. Para tal, utilizaremos o plugin do Chrome chamado [Advanced Rest Client] (ver Apêndices, secção 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 a enviar uma resposta no formato JSON;
- em [5], solicitamos a mesma URL, mas desta vez utilizando uma solicitação POST;
- em [7], a informação é enviada para o servidor no formato [urlencoded];
- em [6], o parâmetro name com o seu valor;
- em [8], o navegador informa ao servidor que está a enviar dados [urlencoded];
- em [9], a resposta JSON do servidor;
1.7.8. Criação de um arquivo executável
Tal como fizemos no projeto anterior, criamos um arquivo executável:
![]() |
![]() |
- em [1]: executamos um alvo do Maven;
- em [2]: existem dois objetivos: [clean] para eliminar a pasta [target] do projeto Maven, [package] para a regenerar;
- em [3]: a pasta [target] gerada ficará localizada nesta pasta;
- em [4]: geramos o alvo;
Nos registos que aparecem na consola, é importante verificar se o plugin [spring-boot-maven-plugin] está presente. Este é o plugin que gera o arquivo executável.
Utilizando um console, navegue até à 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;
Este arquivo é executado da seguinte forma:
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)
...
Nota: Deve primeiro parar qualquer serviço web que possa ter sido iniciado no Eclipse (consulte a secção 1.6.6).
Agora que a aplicação web está em execução, pode aceder-lhe utilizando um navegador:
![]() |
1.7.9. Implantação da aplicação num servidor Tomcat
Tal como fizemos no projeto anterior, modificamos o ficheiro [pom.xml] da seguinte forma:
<?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: Deve especificar que vai gerar um ficheiro WAR (Web Archive);
Também é necessário configurar a aplicação web. Se não existir um ficheiro [web.xml], isto é feito utilizando uma classe que estende [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] é reescrito (linha 8);
- linha 10: é fornecida a classe que configura o projeto;
Para executar o projeto, proceda da seguinte forma:
![]() |
- Em [1-2], execute o projeto num dos servidores registados no IDE Eclipse;
Depois de fazer isso, pode aceder ao URL [http://localhost:8080/gs-rest-service/greeting/?name=Mitchell] num navegador:
![]() |
1.8. Conclusão
Apresentámos dois tipos de projetos Spring MVC:
- um projeto em que a aplicação web envia um fluxo HTML para o navegador. Este fluxo é gerado pelo motor de visualização [Thymeleaf];
- um projeto em que a aplicação web envia um fluxo JSON para o navegador;
No primeiro caso, são necessárias duas dependências do Maven para o projeto:
<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>
Estas configurações introduzem um grande número de dependências em cascata, muitas das quais são desnecessárias. Para implementar a aplicação, utilizaremos uma configuração manual do Maven que inclui apenas as dependências necessárias para o projeto.
Vamos agora regressar aos conceitos básicos da programação web, apresentando dois conceitos fundamentais:
- a troca HTTP (HyperText Transfer Protocol) entre um navegador e uma aplicação web;
- a linguagem HTML (HyperText Markup Language) que o navegador interpreta para apresentar uma página que recebeu;


















































