16. Introdução ao Spring MVC
16.1. O papel do Spring MVC numa aplicação Web
Vamos contextualizar o Spring MVC no desenvolvimento de uma aplicação Web. Na maioria das vezes, esta será construída com base numa arquitetura multicamadas, como a seguinte:
![]() |
- a camada [Web] é a camada em contacto com o utilizador da aplicação Web. Este interage com a aplicação Web através de páginas Web visualizadas por um navegador. É nesta camada que se situa o Spring MVC e apenas nesta 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. Esta camada utiliza dados provenientes do utilizador através da camada [Web] e da camada 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 do SGBD. A camada [ORM] faz a ponte entre os objetos manipulados pela camada [DAO] e as linhas e colunas das tabelas de uma base de dados relacional. Uma especificação denominada JPA (Java Persistence API) permite abstrair-se do ORM utilizado, caso este implemente essas especificações. Será esse o caso neste tutorial e, por isso, passaremos a designar a camada ORM como a 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 – Vista – Controlador) da seguinte forma:
![]() |
O processamento de um pedido de um cliente decorre da seguinte forma:
- pedido — os URL 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» o pedido para o controlador correto e para a ação correta dentro desse controlador. Para tal, utiliza o campo [Action] do URL. O restante do URL [/param1/param2/...] é constituído por parâmetros opcionais que serão transmitidos à ação. O C de MVC é, neste caso, a cadeia [Front Controller, Contrôleur, Action]. Se nenhum controlador puder processar a ação solicitada, o servidor Web responderá que a ação URL solicitada não foi encontrada.
- Processamento
- (continuação)
- A ação selecionada pode utilizar os parâmetros parami que o [Front Controller] lhe transmitiu. Estes 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 juntamente com o seu pedido;
- no processamento do pedido do utilizador, a ação pode necessitar da camada [métier] [2b]. Uma vez processado o pedido do cliente, este pode gerar várias respostas. Um exemplo clássico é:
- uma página de erro, caso a solicitação não tenha podido ser processada corretamente
- uma página de confirmação, caso contrário
- a ação solicita que uma determinada vista seja apresentada [3]. Esta vista irá apresentar dados a que se chama modelo da vista. É o M de MVC. A ação irá criar este modelo M [2c] e solicitar que uma vista V seja apresentada [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 alterada:
![]() |
- em [4a], o modelo, que é uma classe Java, é transformado numa cadeia jSON por uma biblioteca jSON;
- em [4b], esta cadeia jSON é enviada para o navegador;
Agora, vamos esclarecer a relação entre a arquitetura web MVC e a arquitetura em camadas. Dependendo da definição que se atribuir ao modelo, estes dois conceitos podem ou não estar relacionados. Consideremos uma aplicação web Spring MVC de uma camada:
![]() |
Se implementarmos a camada [Web] com o Spring MVC, teremos, de facto, uma arquitetura web MVC, mas não uma arquitetura multicamadas. Neste caso, a camada [web] encarregar-se-á de tudo: apresentação, lógica de negócio 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, então, 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 MVC, obtendo-se assim uma arquitetura em camadas com uma camada [Web] do tipo MVC. Feito isto, é possível substituir esta camada ASP.NET MVC por uma camada ASP.NET clássica (WebForms), mantendo o resto (de negócio, DAO, ORM) inalterado. Temos então uma arquitetura em camadas com uma camada [Web] que já não é do tipo MVC.
Em MVC, referimos que o modelo M era o da vista V, c.a.d, ou seja, o conjunto de dados apresentados pela vista V. É fornecida outra definição do modelo M de MVC:
![]() |
Muitos autores consideram que o que se encontra à direita da camada [Web] constitui o modelo M do MVC. Para evitar ambiguidades, pode-se referir-se:
- do modelo do domínio quando nos referimos a tudo o que está à direita da camada [Web]
- do modelo da vista, quando nos referimos aos dados apresentados por uma vista V
Daqui em diante, o termo «modelo M» designará exclusivamente o modelo de uma vista V.
16.3. Um projeto web / jSON com Spring MVC
O site [http://spring.io/guides] disponibiliza tutoriais de introdução para explorar o ecossistema Spring. Vamos seguir 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 através de URL padrão e que fornecem texto jSON são frequentemente designados por serviços REST (REpresentational State Transfer). Um serviço é considerado Restful se respeitar determinadas regras.
Vamos agora analisar o projeto importado, começando pela sua configuração Maven.
16.3.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.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 baliza [<packaging>] que indique o tipo do ficheiro produzido pela compilação do Maven. Na ausência desta, é utilizado o tipo [jar]. A aplicação é, portanto, uma aplicação executável do tipo consola, e não uma aplicação web, caso em que o pacote seria [war];
- linhas 10-14: o projeto Maven tem um projeto pai [spring-boot-starter-parent]. É este que define a maior parte das dependências do projeto. Estas podem ser suficientes, caso em que não se adicionam mais, ou não, caso em que se adicionam as dependências em falta;
- linhas 17-20: o artefacto [spring-boot-starter-web] traz consigo as bibliotecas necessárias para um projeto Spring MVC do tipo serviço web, onde não há vistas geradas. Este artefacto inclui um grande número de bibliotecas, incluindo as de um servidor Tomcat incorporado. É neste 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 forma:
![]() |
- em [4a], o modelo, que é uma classe Java, é transformado numa cadeia jSON por uma biblioteca jSON;
- em [4b], esta cadeia jSON é enviada para o navegador;
16.3.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] transforma a classe [GreetingController] num controlador Spring, ou seja, os seus métodos são registados 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 vista a apresentar. Aqui é diferente. Os métodos de um controlador do tipo [@RestController] devolvem objetos que são serializados para serem enviados ao navegador. O tipo de serialização realizada depende da configuração do Spring MVC. Aqui, 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 autoconfiguração, configure o projeto desta forma;
- linha 14: a anotação [@RequestMapping] indica o URL que o método processa, neste caso o 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 concorrente. Várias threads podem querer incrementar a variável [counter] ao mesmo tempo. Isto será feito de forma segura. Uma thread só pode ler o valor do contador se a thread que o está a modificar tiver concluído a sua modificação.
16.3.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 transformação jSON deste objeto criará a cadeia de caracteres {"id":n,"content":"texto"}. No final, a cadeia jSON produzida 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. 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. Vamos executar o projeto:
![]() |
Obtêm-se 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 detetado;
Para testar a aplicação web, solicitamos o URL [http://localhost:8080/greeting]:
![]() | ![]() |
Recebemos corretamente a cadeia jSON esperada. Pode ser interessante ver os cabeçalhos HTTP enviados pelo servidor. Para tal, vamos utilizar a extensão do Chrome denominada [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 a enviar 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 na forma [urlencoded];
- em [6], o parâmetro «name» com o seu valor;
- em [8], o navegador indica ao servidor que lhe está a enviar informações [urlencoded];
- em [9], a resposta jSON do servidor;
16.3.7. Criação de um arquivo executável
Vamos agora criar um arquivo executável:
![]() |
![]() |
- em [1]: executamos um alvo Maven;
- em [2]: existem dois objetivos (goals): [clean] para eliminar a pasta [target] do projeto Maven e [package] para a regenerar;
- em [3]: a pasta [target] gerada será criada nesta pasta;
- em [4]: é gerado o alvo;
Nos registos que aparecem na consola, é importante verificar se o plugin [spring-boot-maven-plugin] aparece. É este que gera o arquivo executável (ver [pom.xml] abaixo):
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
Na consola, acedemos à 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 ficheiro é 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)
...
Agora que a aplicação web está em execução, pode-se aceder à mesma através de um navegador:
![]() |
16.3.8. Implementar a aplicação num servidor Tomcat
Tal como foi feito no projeto anterior, alteramos 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: é necessário indicar que se vai gerar um arquivo WAR (Web ARchive);
Além disso, é necessário configurar a aplicação web. Na ausência do ficheiro [web.xml], isto é feito através 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], executa-se o projeto num dos servidores registados no IDE Eclipse;
Feito isto, pode-se aceder ao URL [http://localhost:8080/gs-rest-service/greeting/?name=Mitchell] num 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 a base de dados [dbproduitscategories] estudada nos capítulos anteriores.























