0% acharam este documento útil (0 voto)
11 visualizações175 páginas

Desenvolvimento de Sistemas Web com Spring Boot

O documento aborda o desenvolvimento de sistemas web com Spring Boot, focando em webservices REST e apresentando um exemplo de gerenciador de dados pessoais. Ele detalha as funcionalidades, definições de URIs, códigos de resposta HTTP, e conceitos fundamentais como injeção de dependências e arquitetura MVC. Além disso, discute a importância do Spring Framework e suas características, como a criação e gerenciamento de beans.

Enviado por

ZoomKS
Direitos autorais
© All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
0% acharam este documento útil (0 voto)
11 visualizações175 páginas

Desenvolvimento de Sistemas Web com Spring Boot

O documento aborda o desenvolvimento de sistemas web com Spring Boot, focando em webservices REST e apresentando um exemplo de gerenciador de dados pessoais. Ele detalha as funcionalidades, definições de URIs, códigos de resposta HTTP, e conceitos fundamentais como injeção de dependências e arquitetura MVC. Além disso, discute a importância do Spring Framework e suas características, como a criação e gerenciamento de beans.

Enviado por

ZoomKS
Direitos autorais
© All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd

Desenvolvimento de

Sistemas Web

Desenvolvimento Backend com Spring Boot –


Webservices REST

Versão 25.2.0

Prof. Fernando Tsuda


Exemplo a ser desenvolvido
Gerenciador de dados pessoais
• Possibilitar a apresentação das • Internamente, deve manter as
seguintes informações: seguintes informações
• Nome completo adicionais:
• Data de nascimento • Apelido único (username)
• E-mail • Senha de acesso
• Telefone
• Interesses (selecionar entre
opções pré-cadastradas)
• Foto
• Link para Linkedin
• Link para Github
Prof. Fernando Tsuda
Exemplo a ser desenvolvido
Gerenciador de dados pessoais
• Funcionalidades previstas
• Listagem de pessoas
• Busca textual
• Visualizar dados da pessoa
• Inclusão de nova pessoa
• Upload da foto
• Alteração dos dados da pessoa
• Exclusão da pessoa
• Listagem de interesses

Prof. Fernando Tsuda


Definição das URIs + Códigos de resposta usuais
Ação Método HTTP + URI Códigos de resposta
Listar GET /recursos 200 – Sucesso + Array com dados
(se não existir, retornar Array vazio)
Incluir novo POST /recursos 201 – Incluído com sucesso + location (URI)
400 – Erro nos dados enviados (validação)
Visualizar 1 recurso GET /recursos/{id} 200 – Sucesso + Dados
existente 404 – Item não encontrado
Alterar existente PUT /recursos/{id} 200 ou 204 – Alterado com sucesso
404 – Item não encontrado
400 – Erro nos dados enviados (validação)
Excluir DELETE /recursos/{id} 200 ou 204 – Excluído com sucesso
404 – Item não encontrado
Nome do recurso na URI
- Usar nome no plural
- Usar letras minúsculas
- Se for composto, separar com hífen
(ex: dados-pessoais) Prof. Fernando Tsuda
Objetivos
• Apresentar os principais componentes para desenvolvimento de sistemas
web usando o Spring Boot (Webservices REST)
• Controllers
• Tratamento de requisições GET
• Resolução de URLs, envio de parâmetros, tratamento de cabeçalhos
• Envio de dados com POST
• Criação de funcionalidades com PUT e DELETE
• CORS
• Validação de dados
• Internacionalização das mensagens (i18n)
• Upload de arquivos
• Outros assuntos até o final do semestre
• Integração com banco de dados usando JPA (slides a parte)
• Inclusão de autenticação/autorização de acesso com Spring Security e JWT

Prof. Fernando Tsuda


Troca de mensagens
Modelo Client-Server usando protocolo
HTTP

HTML
Spring Boot
CSS Java
JS
Framework
• Conjunto de componentes e processos que visam facilitar o
desenvolvimento de um software específico, através de
funcionalidades que são comuns a várias aplicações
• Adoção implícita de boas práticas

Prof. Fernando Tsuda


Analogia:
Preparar uma
pizza

Prof. Fernando Tsuda


Spring Framework
• Framework que provê uma infraestrutura de componentes para o
desenvolvimento de aplicações Java
• Tem como principal característica a criação e o gerenciamento dos
objetos usados pela aplicação – estes objetos são chamados "Beans"
• Os beans são associados uns aos outros usando a técnica de Inversão
de controle (IoC - Inversion of control) ou Injeção de Dependências
(DI - Dependency Injection)
• Permite um desacoplamento entre os diversos módulos do sistema

Prof. Fernando Tsuda


Bean
• Objeto criado e gerenciado pelo Spring Framework
• Normalmente criado através do uso das anotações @Component ou
equivalente no nível das classes e @Bean para métodos que criam
objetos

Prof. Fernando Tsuda


Beans - Exemplos
@Component // Classe normal, sem recursos do Spring
public class ExemploComponent { public class ExemploBean {
// Spring Framework cria objeto }
// bean a partir desta classe
// no processo de Component Scan @Configuration
public class Inicializador {
}
// Spring cria objeto bean através da
Após a criação dos objetos, eles ficam // chamada ao método abaixo
@Bean
disponíveis para serem injetadas em
public ExemploBean exemploBean() {
outras classes. return new ExemploBean();
}
Também podem ser acessadas através do }
ApplicationContext

Prof. Fernando Tsuda


Bean - Tipos
Tipo Características Depende de
ambiente web
Singleton Uma instância única por aplicação. Configuração padrão. NÃO
Prototype Cada acesso gera um novo objeto. NÃO
Request Bean criado e mantido durante o processamento de uma SIM
requisição
Session Bean criado e mantido para cada sessão de usuário SIM
Application Bean criado por aplicação rodando dentro de um contexto web SIM
Websocket Bean criado e mantido durante uma sessão acessada via SIM
websocket

Prof. Fernando Tsuda


Exemplo Injeção Dependências
Modo usual – SEM injeção
public class SomeService { Neste exemplo, ao criar objetos com new
... SomeService(), pode ocorrer uma situação onde
terão 2 objetos deste tipo instanciados ao
}
mesmo tempo (um pela Teste1, outro pela
Teste2)
public class Teste1 {
private SomeService serv = new SomeService();
}

public class Teste2 {


private SomeService serv = new SomeService();
}

Prof. Fernando Tsuda


Exemplo Injeção Dependências
Uso do @Autowired @Component
public class SomeService {
...
O uso da anotação @Component nas classes
}
permite que o Spring crie e gerencie as
instâncias de cada uma delas. Por padrão, é @Component
adotado o padrão "Singleton" (somente 1 public class Teste1 {
instância/objeto é criada por classe).
@Autowired
Através do uso do @Autowired nas classes
Teste1 e Teste2, o Spring sabe que o "serv" vai private SomeService serv;
manter uma associação com o objeto }
SomeService e "injeta" uma referência nestas
@Component
"variáveis".
public class Teste2 {
@Autowired
private SomeService serv;
}
Prof. Fernando Tsuda
Exemplo Injeção Dependências
Uso do @Autowired
@Component @Component
public class FooService { public class Teste {
...
}
@Autowired
@Component private FooService fooService;
public class BarService {
... @Autowired
} private BarService barService;

}
OBS: Uso do @Autowired não é
recomendado em projetos novos
– usar injeção via Contrutor ou
via método Set
Exemplo Injeção Dependências pelo
Construtor ou set()
@Component @Component
public class FooService { public class Teste {
...
private FooService fooService;
}
private BarService barService;
@Component
public class BarService {
@Autowired // <-- PODE SER OMITIDO SE TIVER SÓ 1 CONSTRUTOR.
...
public Teste(FooService fooService, BarService barService) {
}
[Link] = fooService;
[Link] = barService;
Injeção é tratada }
automaticamente pelo IoC do
}
Spring Framework através do
construtor ou set da classe Teste
Exemplo Injeção Dependências pelo
Construtor ou set()
@Component @Component
public class FooService { public class Teste {
...
private FooService fooService;
}
private BarService barService;
@Component
public class BarService {
@Autowired // <-- PODE SER OMITIDO SE TIVER SÓ 1 CONSTRUTOR.
...
public Teste(FooService fooService) {
}
[Link] = fooService;
}
Injeção é tratada // Abordagem do set indica que dependência é opcional
public void setBarService(BarService barService) {
automaticamente pelo IoC do [Link] = barService;
Spring Framework através do }
construtor ou set da classe Teste }
Exemplo Injeção Dependências pelo
Construtor com Lombok
@Component @Component
public class FooService { @RequiredArgsContructor // Lombok
... public class Teste {
}

@Component private final FooService fooService;


public class BarService { private final BarService barService;
...
} }
ATENÇÃO: Dependendo da IDE
usada, pode ser necessário instalar o
// Anotação @RequiredArgsConstructor do Lombok gera Lombok como extensão ou plugin
// automaticamente o construtor abaixo: para este código funcionar
public Teste(FooService fooService, BarService barService) {
[Link] = fooService;
[Link] = barService;
}
Spring Framework
• Primeira versão lançada em 2003
• Criado e mantido pela Pivotal ([Link]
• Versão atual: 6.2.x
• 6.2.0 lançada em nov/2024
• Precisa rodar com Java 17 ou superior
• Não é compatível com namespace do Java EE (javax.*) – Somente Jakarta EE (jakarta.*)
• Versões anteriores
• 6.0.0 lançada em nov/2022

Prof. Fernando Tsuda


Spring Framework
• Composto por vários módulos com finalidades específicas
• Exemplos:
• Web
• Acesso aos dados

Prof. Fernando Tsuda


Arquitetura 3 camadas (layers)

Presentation Layer

Service Layer

Repository Layer

Prof. Fernando Tsuda


DTOs (Data Transfer Objects)
Representação das informações que
podem trafegar para acessos externos
Apresentação/ Interface
com "mundo externo"
Services/
Casos de uso
Services / Casos de
Repository
uso
Entities
Representação das
informações do banco
até a camada de Services

Prof. Fernando Tsuda


Modelo Client-Server com MVC

Model

View Controller
Arquitetura MVC
Consulta o Altera o
estado estado

Model

Notificação de
mudanças
Seleciona a view

View Controller
Gestos do usuário
Chamada de métodos
Eventos
Arquitetura MVC

Model View Controller

• Encapsula o estado • Renderiza o modelo • Define o


da aplicação • Requisita as comportamento da
• Responde às atualizações do aplicação
consultas ao estado modelo • Mapeia as ações do
• Expõe as • Envia os gestos dos usuário ao modelo
funcionalidades da usuários ao Controle • Seleciona as views de
aplicação • Permite ao Controle resposta
• Notifica as Views selecionar a View • Um controle para
sobre mudanças cada funcionalidade
Vantagens MVC
• Desacoplamento entre a apresentação, controle, comportamento e
persistência de dados, possibilitando uma maior flexibilidade
• Facilita a manutenção e evolução do projeto, ao reduzir a
complexidade do código
• Promove a divisão de responsabilidades
Spring Web MVC
• Módulo do Spring Framework que possibilita o desenvolvimento de
aplicações web que usem a arquitetura MVC (Model-View-Controller)
• Utiliza o modelo de processamento action-based (ou push-based),
onde os controladores irão ser acionados através da requisição HTTP.
• Seu funcionamento se baseia em um front controller (ou dispatcher
servlet), responsável pelo recebimento das requisições e posterior
encaminhamento ao bean correspondente.

Prof. Fernando Tsuda


Spring MVC X Servlet/JSP
Model View Controller Passagem de
informações do
Controller para View
Servlet/JSP em JSP Servlet [Link]()
conjunto no modelo
MVC
Spring MVC + Requisitos de Templates HTML Classe Java [Link]()
Thymeleaf (web negócio com sintaxe configurada como OU
tradicional) implementados com Thymeleaf @Controller [Link]()

Spring MVC linguagem Java Aplicação Javascript Classe Java Não se aplica
(Webservices REST rodando no cliente configurada como (Serialização JSON)
– web moderna) + integração via @RestController
JSON

Prof. Fernando Tsuda


MVC com Servlets/JSP e JEE
Model 2 Architecture

Server
Spring Web MVC (Tradicional)
HTTP

MODEL

Prof. Fernando Tsuda


Spring Web MVC (Tradicional)
Implementado através
do HttpServlet
1) Requisição é recebida
HTTP
pelo Front controller (ou
Dispatcher Servlet)

MODEL

Prof. Fernando Tsuda


Spring Web MVC (Tradicional)
2) O Front controller delega o
processamento para o
Controller correspondente

HTTP

MODEL

Prof. Fernando Tsuda


3) Controller processa a
Spring Web MVC (Tradicional) requisição e retorna um
modelo e instruções sobre o
template a ser usado para
gerar a resposta
HTTP

MODEL

Prof. Fernando Tsuda


Spring Web MVC (Tradicional)
HTTP

MODEL

4) Front controller repassa o


modelo para o template, que
irá gerar a resposta ao cliente

Prof. Fernando Tsuda


Spring Web MVC (Tradicional)
HTTP

MODEL

5) Após a resposta ser


gerada, Front controller
retorna a resposta ao cliente

Prof. Fernando Tsuda


Spring Web MVC (Tradicional) Implementado pelo
desenvolvedor
Fornecido pelo
HTTP Spring MVC

MODEL

Objeto do Spring
usado para troca de
informações entre
Implementado pelo Controller e View
desenvolvedor

Prof. Fernando Tsuda


[Link]
Prof. Fernando Tsuda
Webservice
• Também conhecido como APIs Web
• Aplicação web disponibilizando informações para outras aplicações
clientes
• Sites (Interfaces frontend)
• Aplicativos móveis
• Sensores/atuadores IoT (Internet das coisas)
• Outras aplicações "client" com acesso à web
• Ex: Postman, cURL

Prof. Fernando Tsuda


REST
• REpresentational State Transfer (Transferência de estado
representacional).
• Estilo arquitetural de software que permite o acesso às informações
dos recursos centralizados em um ou mais servidores sem a
necessidade de manutenção de estado com o cliente consumidor.
• Informações são acessadas através de operações (ou métodos)
definidos pelo protocolo HTTP (Hypertext Transfer Protocol).

Prof. Fernando Tsuda


Características REST X HTTP
• Recursos são identificados/representados por URIs (Uniform Resource
Identifier) e são descritos usando uma notação comum (normalmente
JSON ou XML)
• Stateless (sem estado) → EVITAR USAR SESSÃO HTTP
• Usa os métodos do HTTP para definir as ações a serem realizadas
• GET – obtém um recurso do servidor
• POST – inclui um novo recurso no servidor
• PUT/PATCH – substituí um recurso inteiramente ou parcialmente, respectivamente
• DELETE – apaga um recurso
• Usa os códigos do HTTP para indicar o resultado da operação
• 200 – Sucesso
• 201 – Recurso criado
• 400 – Erro nas informações enviadas
• 404 – Recurso não encontrado
Prof. Fernando Tsuda
Ferramentas para implementar REST em Java
• Spring MVC
• Pode ser usado somente usando o módulo MVC ou através do módulo Spring
Data REST
• Permite uso do módulo Spring HATEOAS para criação de webservices RESTful
• Componente Jackson 2 é responsável pela Serialização/Deserialização de um
objeto Java para String JSON e vice-versa
• JAX-RS (parte do Jakarta EE) → Atualmente está na versão 2.x (a
partir do Java EE 7)
• Jersey
• RESTEasy
• Apache CXF
Jackson 2
• Componente padrão usado pelo Spring Boot para converter os
objetos Java (POJOs) em JSON e vice-versa, através do objeto
ObjectMapper
• Na configuração padrão, as seguintes propriedades do ObjectMapper
são desabilitadas na aplicação Spring Boot
• MapperFeature.DEFAULT_VIEW_INCLUSION
• DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
• SerializationFeature.WRITE_DATES_AS_TIMESTAMPS
• SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS

[Link]

Prof. Fernando Tsuda


Jackson 2 - Exemplo de serialização
public class Produto {
private String nome;
private Integer preco;
ObjectMapper objectMapper = new ObjectMapper();
public Produto() { }
Produto prod = new Produto("Bolo", 100);
public Produto(String nome,
String json = [Link](prod);
int preco) {
[Link] = nome;
[Link] = preco;
}
// Getters e Setters
}

Prof. Fernando Tsuda


Jackson 2 - Exemplo de de-serialização
{
"nome": "Bolo",
"preco": 100
}
ObjectMapper objectMapper = new ObjectMapper();
String json = """
{
"nome": "Bolo",
"preco": 100
}
""";
Produto prod = [Link](json, [Link]);

Prof. Fernando Tsuda


Spring MVC Tradicional X REST
Model View Controller Passagem de Outras características
informações do
Controller para View
Spring MVC + • Templates HTML Classe Java [Link]() • Somente GET ou
Thymeleaf com sintaxe configurada OU POST
(web Thymeleaf como [Link]() • Sessão para manter
tradicional - • Telas geradas no
@Controller estado do usuário
SSR) servidor (SSR =
Server side
Requisitos de
rendering)
negócio
Spring MVC implementado • Aplicação Javascript Classe Java Não se aplica • Todos métodos HTTP
(Webservices rodando no cliente configurada (Serialização JSON) com semântica para
com linguagem
REST - web + integração via como ações
moderna - Java requisições @RestController
• Stateless (necessita
frontend assíncronas + JSON
"separado") • Processamento de adotar algum padrão
telas no navegador para manter dados
(cliente-side de navegação)
rendering)
Prof. Fernando Tsuda
Spring MVC Tradicional X REST
Vantagens Desvantagens

Spring MVC + Thymeleaf • Possibilita desenvolver exemplos mais • Essa abordagem de SSR está em desuso no
(web tradicional - SSR) didáticos e mais simples, pois envolve mercado, principalmente para aplicações
somente a lógica do backend + sintaxe voltadas para usuários em geral
do Thymeleaf para geração das telas
com resultados
• Na maioria dos casos, não necessita
conhecimentos de Javascript
Spring MVC (Webservices • Abordagem mais utilizada pelo mercado • Necessita conhecimento do Javascript para
REST - web moderna - atualmente manipulação da interface HTML e criação de
frontend "separado") • Facilita a adoção de frameworks e requisições assíncronas
bibliotecas para a criação de projetos de • Exemplos mais complexos, pois, para cada
frontend mais complexos (ex: React, funcionalidade, será necessário criar Javascript
Angular, VueJS) para receber e apresentar resultados na tela

Prof. Fernando Tsuda


CORS
• Cross-origin resource sharing
• Mecanismo que usa cabeçalhos HTTP adicionais para garantir
permissão de acesso a recursos de um servidor diferente do da
origem da página (domínio) em uso
• Um user-agent realiza um requisição HTTP de origem cruzada quando
executa uma requisição de um domínio, protocolo ou porta diferente
do qual originou o documento corrente.

[Link]
Prof. Fernando Tsuda
CORS - Exemplo
• Usuário acessando [Link]
• Javascript fazendo requisição para a URL [Link] deve
enviar um cabeçalho Origin indicando a URL de origem.
• Acesso ao recurso [Link] só será permitido se a resposta da
requisição apresentar cabeçalhos adicionais (ex: Access-Control-Allow-Origin)
• Se o cabeçalho adicional não estiver presente, o user-agent não permite a
execução do Javascript
• Configuração de CORS em aplicações Spring MVC
• Ver [Link]

Prof. Fernando Tsuda


RESTFul
HATEOAS →Hypermedia As The Engine Of Application State

[Link]
Características REST {
"account_number" : 123456,
"balance_value" : 100.0,
"balance_currency" : "USD",
"links" : [

• Hypermidia → Links para que o {


"rel" : "deposit",

recurso possa ser manipulado "type" : "PUT",


"href" : "[Link]
},
{
HTTP/1.1 200 OK "rel" : "withdraw",
"type" : "POST",
Content-Type: application/json "href" : "[Link]
Content-Length: ... },
{
"rel" : "transfer",
"type" : "POST",
"href" : "[Link]
},
{
"rel" : "close",
"type" : "POST",
"href" : "[Link]
}
]
}

Referência: [Link]
Desenvolvendo uma aplicação
REST com Spring MVC

Prof. Fernando Tsuda


Configuração inicial da aplicação
• 3 formas principais de configuração
1. Declarativa – configuração usando arquivos XML
2. Programática – configuração usando programação
3. Spring Boot – projeto que permite o desenvolvimento de aplicações
usando os componentes do Spring
• Vantagem do Spring Boot
• Inclui automaticamente no projeto configurações iniciais básicas para as
dependências adicionadas (projetos "starter")
• Ex: No starter web, o servidor Tomcat já é inicializado com configurações padrão
• Permite executar uma aplicação web a partir de um projeto Java comum
(projeto não-web) → Servidor web Tomcat embutido no projeto

Prof. Fernando Tsuda


Spring Framework/Boot – Pré-requisitos
• Maven ou Gradle
• Versionamento semântico (SemVer) e política de atualizações
• Orientação a objetos
• JavaBean/POJOs
• Convenção ao invés de configuração
• Configuração através de anotações
• Desacoplamento de componentes
• Interfaces
• Organização das URLs (ou URIs) da aplicação (sitemaps)
Prof. Fernando Tsuda
Versionamento semântico (SemVer)

1.2.3
Major – Versão principal do componente, sua mudança pode
envolver alterações que afetam o software desenvolvido que
usa o componente
Minor – Versão secundária do componente, sua mudança
pode trazer novas funcionalidades mas devem evitar impactar
o software desenvolvido

Patch – Versão que indica correções de bugs e pequenas


melhorias, sem trazer novas funcionalidades

Prof. Fernando Tsuda


Spring Boot
• Versão atual: 3.5.x
• Versão 3.5.0 lançada em mai/2025 → Usa Spring Framework 6.2.x
• Também precisa de Java 17 ou superior para funcionar
• Usa como base o Jakarta EE 9 mas suporta recursos do Jakarta EE 10
• Patches lançados mensalmente (aproximadamente)
• Versão “minor” lançada a cada 6 meses (aproximadamente)
• Versões anteriores
• 3.4.0 – lançada em nov/2024
• 3.3.0 – lançada em mai/2024
• 3.2.0 – lançada em nov/2023
• 3.1.0 – lançada em mai/2023
• 3.0.0 – lançada em nov/2022

Prof. Fernando Tsuda


Criar e abrir o projeto
Spring Boot – seguir [Link]
instruções conforme link
fornecido no Blackboard Group: [Link]
até 19:45 Artifact: exemplos-spring-inicial
Package name:
[Link]
Dependencies (Clicar em Add
Dependencies, digitar e
selecionar):
• Web
• Devtools
• Configuration Processor
• Validation
• Lombok
• Thymeleaf
- Clicar em Generate para baixar o
zip contendo o projeto
- Descompactar e abrir o projeto
na IDE de preferência
Spring Doc – Open API 3.0 + Swagger
• Incluir a dependência abaixo no [Link]
<dependency>
<groupId>[Link]</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.8.13</version>
</dependency>

• Após desenvolver RestControllers e rodar aplicação, acessar a


seguinte URL: [Link] para visualizar
documentação online das URIs (endpoints) disponíveis
• Site oficial da biblioteca: [Link]
Prof. Fernando Tsuda
Clients para testes de Webservices REST
• Postman
• Insomnia
• Bruno
• cURL

[Link]

Prof. Fernando Tsuda


Estrutura do projeto • Pacotes de códigos-fonte → Classes Java
• Pacotes de teste → Classes Java para testes
unitários
• Importante: neste exemplo, todas a classes
devem ficar dentro do pacote ou em
subpacotes de [Link]
• Outros códigos-fonte
• src/main/resources
• Arquivo [Link] → Propriedades
da aplicação
• static → Diretório onde deverão ser colocados
arquivos estáticos (html estático, css, js,
imagens, fontes, etc)
No Netbeans: • templates → Diretório onde deverão ser
colocados arquivos usados como templates para
Projeto Java geração da view (JSPs, html dinâmico)
NORMAL
(NÃO WEB)
• Arquivos do projeto
• [Link] → Configurações do projeto Maven

Prof. Fernando Tsuda


IMPORTANTE!!!
• Notar que o projeto gerado será empacotado como um arquivo JAR, pois o
Spring Boot irá usar uma versão incorporada (embedded) do Web
container Tomcat.
• Apesar de ser empacotado como um arquivo JAR, o sistema irá se
comportar normalmente como um sistema web.
• O acesso à aplicação deve ser feito através do navegador usando, por
padrão, a URL [Link] - ou seja, a aplicação roda usando
contexto raiz (root context-path) (/).
• Para alterar porta e contexto-path, incluir as seguintes configurações no arquivo
[Link] (fornecido no projeto inicial)
[Link]=8080
[Link]-path=/
• Antes de reexecutar a aplicação, lembrar de parar a execução anterior. A
dependência DevTools permite que as atualizações no código sejam feitas
sem necessidade de reiniciar a aplicação na maioria das vezes – basta fazer
as alterações, salvar e acessar o navegador
Prof. Fernando Tsuda
Classe principal (gerada automaticamente)
Notar a anotação @SpringBootApplication,
responsável por aplicar as configurações padrão para
que o aplicativo funcione como um aplicativo web
MVC
@SpringBootApplication
public class ExemploApplication {

public static void main(String[] args) {


[Link]([Link], args);
}
}
A anotação @SpringBootApplication equivale às seguintes anotações:
@Configuration
@ComponentScan
@EnableAutoConfiguration

Prof. Fernando Tsuda


Anotações básicas
• @Configuration – Indica que a classe representa uma configuração da
aplicação. Dentro desta classe podem ser criados métodos com a
annotation @Bean, cujo resultado fica disponível para ser injetado
dentro da aplicação Spring através do applicationContext.
• @ComponentScan – Indica que o Spring irá procurar as classes de
configuração, @Components e derivados dentro do package e
subpackages onde a classe anotada se encontra.
• @EnableAutoConfiguration – Ativa o recurso de auto configuração
dos módulos do Spring Boot

Prof. Fernando Tsuda


Anotações comuns da web
• @Controller – Indica que a classe irá ser configurada como um
Controlador web dentro de uma aplicação Spring MVC
• @RequestMapping – Mapeia um padrão de URL (rota) para a
requisição ser processada pela classe e/ou pelo método
• Forma reduzida (neste exemplo aceita requisição de qualquer método HTTP):
@RequestMapping("/exemplo") OU @RequestMapping(value="/exemplo")
• Forma completa:
@RequestMapping(value="/exemplo", method=[Link])
OU
@RequestMapping(path="/exemplo", method=[Link])

Prof. Fernando Tsuda


Anotações comuns
• @GetMapping – Atalho do mapeamento de um padrão de URL. Para
processamento de requisições GET. Equivale ao @RequestMapping
com method configurado como [Link].
• @PostMapping – Atalho do mapeamento de um padrão de URL para
processamento de requisições POST. Equivale ao @RequestMapping
com method configurado como [Link].

• Pela mesma lógica, também podem ser usadas as anotações


@PutMapping, @PatchMapping, @DeleteMapping e outros
métodos HTTP usuais
Prof. Fernando Tsuda
Anotações comuns
• @ResponseBody – Configuração que indica que a resposta do
método deverá ser retornada como corpo da mensagem de resposta
HTTP
• O uso da anotação @RestController ao invés do @Controller antes da
declaração da classe possibilita a omissão desta anotação nos métodos
• Caso não seja informada, o Spring MVC irá tratar a resposta do método do
tipo String como sendo a view que será utilizada no fluxo MVC tradicional.

Prof. Fernando Tsuda


Diferenças @Controller X @RestController
para retornar Body HTTP
@Controller @RestController
public class TesteController1 { public class TesteController2 {

@GetMapping("/teste1") @GetMapping("/teste2")
@ResponseBody // Não precisa do @ResponseBody
public String mostrarMensagem() { public String mostrarMensagem() {
return "Exemplo @Controller"; return "Exemplo @RestController";
} }
} }
ATENÇÃO: Neste caso acima, a não inclusão do
@ResponseBody indica ao Spring que a String
retornada representa o nome da
view/template que irá gerar a resposta ao
usuário (modelo MVC tradicional)

Prof. Fernando Tsuda


Controller com parâmetros – Usando
@RequestParam
@GetMapping("/exemplo-request-param")
public Dados exemploRequestParam (
@RequestParam("param1") String param1,
@RequestParam(name = "param2str", required = true,
defaultValue = "xyz") String param2,
@RequestParam(name = "param3int", required = false,
defaultValue = "99") int param3) {
Dados dados = new Dados(param1, param2, param3);
return dados;
}
Parâmetros enviados através de query string
Ex: [Link]

Prof. Fernando Tsuda


Controller com parâmetros – Usando
@PathVariable
@GetMapping("/exemplo-path-var/{param1str}/{param2int}")
public Dados exemploPathVariable(
@PathVariable("param1str") String param1,
@PathVariable(name = "param2int",
required = true) int param2) {
Dados dados = new Dados(param1, param2);
return dados;
}

Parâmetros enviados no caminho da URL


Ex: [Link]

Prof. Fernando Tsuda


POST – Objetivos do exemplo
• Cadastrar as seguintes informações:
• Nome (obrigatório, máx. 100 caracteres)
• Apelido (obrigatório, máx. 64 caracteres)
• E-mail (obrigatório, máx. 100 caracteres e formato válido)
• Telefone
• Data de nascimento (obrigatório, data no passado)
• Senha / Repetição senha (obrigatórios)
• Interesses (Tecnologia / Esportes / Gastronomia / Viagens / Investimentos) →
Múltiplas opções pré cadastradas

Prof. Fernando Tsuda


Pontos importantes ao implementar POST
• Modelar uma classe POJO/DTO que represente as informações que
serão preenchidas no formulário
• POJO (Plain Old Java Object)→ Classe Java com atributos privados, acesso via
get/set e construtor "padrão" (sem parâmetros)
• Usualmente, os atributos name definidos nas tags
<input>/<textarea>/<select> serão os mesmos atributos da classe criada
• No método que trata a requisição POST (definido pela anotação
@PostMapping), incluir a anotação @RequestBody no parâmetro que
recebe o objeto com as informações preenchidas

Prof. Fernando Tsuda


POST básico
@PostMapping
public ResponseEntity<Void> salvar(@RequestBody Dados dados) {

// *** IMPLEMENTAR A LÓGICA PARA TRATAR OS DADOS RECEBIDOS ***

// Prepara a URI que identifica os dados salvos


// Essa informação é retornada no cabeçalho "Location"
URI location =
[Link]().path("/{id}")
.buildAndExpand([Link]()).toUri();
return [Link](location).build();
}

Prof. Fernando Tsuda


Validação de dados
• Client-side
• Uso de atributos dos campos input (required, max, min, pattern, uso dos types email, number etc)
• Funções de validação Javascript para lógicas complexas que envolvam mais de um campo
• Referência MDN: [Link]
• Server-side
• Jakarta/Java EE – Bean Validation 2.0 (JSR-380)
• @NotNull
• @NotBlank
• @Min(<valor>)
• @Max(<valor>)
• @Size(min = <valor>, max = <valor>)
• @Future
• @Past
• @Digits(integer = <valor>, decimal = <valor>
• @Pattern(<regex>)
• @Email
[Link]
[Link]
Prof. Fernando Tsuda
Validação de dados
• A partir do Spring Boot 2.3.x, o módulo de validação deve ser
declarado de maneira explícita como uma dependência no [Link]
• Caso o módulo não tenha sido incluído ao criar o projeto no Spring
Initializr, adicionar o trecho abaixo no [Link]

<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

Prof. Fernando Tsuda


Validação de dados
• Na classe POJO/DTO/Entity
• Usar as anotações do Bean Validation nos atributos que devem ser validados
• No RestController
• Adicionar a anotação @Valid no objeto que está sendo recebido do cliente via
@RequestBody
• Na view (Javascript)
• Em caso de erros, o Servidor irá retornar o status 400 – Bad request
• Analisar o objeto de erro retornado no corpo da mensagem
• Notar a presença de um Array "errors", onde cada erro contém as propriedades "field" e
"defaultMessage"
• Usar estas e outras informações no código Javascript para apresentar as informações na
tela (seletor CSS no [Link]() e texto da mensagem)

Prof. Fernando Tsuda


POST com validação

@PostMapping("/salvar")
public DadosPessoais salvar(@RequestBody @Valid DadosPessoais dadosEnviados) {
[Link]([Link](), dadosEnviados);
return dadosEnviados;
}

Prof. Fernando Tsuda


Upload de arquivos
• O upload em um sistema web é essencialmente o envio de um
arquivo local da máquina (através do navegador) para o servidor
remoto.
• Usualmente, o arquivo deverá ser acessado remotamente pela web.
Para isso, é necessário configurar uma URL que mapeie o local onde
os arquivos foram salvos no servidor.

Prof. Fernando Tsuda


Upload de arquivos
Implementação do upload via web:
• No código HTML do formulário que irá enviar o arquivo:
• Configurar o atributo “enctype” com o valor "multipart/form-data" no <form>
• Incluir um ou mais <input type="file" name="nome-campo">
• OU implementar Javascript que recebe a imagem via FormData e enviar
requisição usando Fetch API
• No Controller, receber o arquivo através do parâmetro
@RequestParam("nome-campo") MultipartFile arquivo
• A lógica na aplicação servidora consiste em copiar o conteúdo do
arquivo recebido pela rede para o destino (disco, banco de dados,
etc).
Prof. Fernando Tsuda
ATENÇÃO
• No processamento do upload, EVITAR salvar os arquivos nos
diretórios do projeto
• Esse diretório só vai existir na máquina do desenvolvedor
• Arquivos não serão mantidos quando a aplicação for implantada/atualizada
em algum servidor
• Criar um diretório externo separado do projeto para manter as
imagens

Prof. Fernando Tsuda


Upload de arquivos
• Formulário HTML para envio (com Javascript/Fetch API/FormData)
<script>
<form id="formUpload"> async function upload(event) {
<div> [Link]();
<label>Selecione o arquivo</label> const formData = new FormData([Link]);
<input type="file" name="arquivo" /> // [Link] acima equivale a
</div> // [Link]('formUpload')
<button type="submit">Enviar</button> const httpResp = await fetch('/upload', {
</form> method: 'POST',
body: formData,
});
if ([Link]) {
alert('Arquivo enviado com sucesso!');
} else {
Cabeçalho content-type: alert('Erro ao enviar o arquivo.');
multipart/form-data está implícito no }
objeto formData }
[Link]('formUpload')
.addEventListener('submit', upload);
</script>
Prof. Fernando Tsuda
Upload de arquivos
• Controller responsável por receber o arquivo e gravar em disco
@RestController
public class UploadController {

@PostMapping("/upload")
public ResponseEntity<?> receberArquivo(@RequestParam MultipartFile arquivo) {
Path destino = [Link]("C:/uploads", [Link]());
try {
[Link]([Link](), destino, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException ex) {
[Link]();
return [Link]().body("Erro - Arquivo já existe");
}
return [Link]().build();
}

Prof. Fernando Tsuda


Upload de arquivos
Caminho para acessar os arquivos após upload
• Configurar uma rota para acessar os arquivos que estão no diretório
de destino na classe de configuração do Spring MVC.
• Criar a classe WebMvcConfig caso não exista
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
[Link]("/arquivos-uploads/**")
.addResourceLocations("[Link]
}
}

Prof. Fernando Tsuda


Internacionalização (i18n)
• Técnica que permite preparar a aplicação para suportar mensagens
em diversos idiomas
• Navegador envia o código do idioma no cabeçalho HTTP Accept-Language
• Referências:
• [Link]
• [Link]
• [Link]

Prof. Fernando Tsuda


Internacionalização (i18n)
• Criar os arquivos com as mensagens nos idiomas suportados. Por
padrão do Spring Boot, o nome do arquivo deve iniciar com
"messages" e completado com o código da localidade (idioma, país →
Exemplos: Brasil = pt_BR, Idioma inglês = en)

# Arquivo /src/main/resources/messages_pt_BR.properties
# Mensagens em português/Brasil
[Link]-vindas=Bem vindo
[Link]-com-parametro=Olá {0}

# Arquivo /src/main/resources/messages_en.properties
# Mensagens em inglês
[Link]-vindas=Welcome
[Link]-com-parametro=Hello {0}

Prof. Fernando Tsuda


Internacionalização (i18n)
• Acessar as mensagens usando o comando [Link]()

@RestController
public class ExemploController {

@Autowired
private MessageSource messageSource;

@GetMapping("/boas-vindas")
public String boasVindas() {
return [Link]("[Link]-vindas", [Link]());
}

// Acessar [Link]
@GetMapping("/ola")
public String ola(@RequestParam("nome") String nome) {
return [Link]("[Link]-com-parametro",
new String[] { nome }, [Link]());
}
}
Prof. Fernando Tsuda
Internacionalização (i18n)
• Para integrar as mensagens com o mecanismo de validação, tem que
implementar manualmente uma configuração para associar o
resource bundle ao mecanismo de validação
• Caso não exista, criar a classe WebMvcConfig e incluir a lógica abaixo
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

@Bean
public LocalValidatorFactoryBean getValidator(
@Autowired MessageSource messageSource) {
LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
[Link](messageSource);
return bean;
}

}
Prof. Fernando Tsuda
Internacionalização (i18n)
• Nas anotações de validação, usar a expressão {<chave-mensagem>}
para indicar qual mensagem será apresentada
public DadosDto {

@NotBlank(message = "{[Link]}")
private String mensagem;
}

• Nos arquivos de mensagens, incluir, por exemplo, a propriedade


abaixo para cada idioma, traduzindo o texto
[Link]=A mensagem não pode ser nula nem ter somente espaços

Prof. Fernando Tsuda


Outros tópicos Spring Boot para ver
• Tratamento global de erros
(@ControllerAdvice/@RestControllerAdvice, @ExceptionHandler)
• Eventos da aplicação (@EventListener)
• Tarefas periódicas (@Scheduled)
• Uso de profiles
• Spring Boot Actuator

• Outras dicas em [Link]


desenvolvimento/blob/main/[Link]
Prof. Fernando Tsuda
Integração com DB usando Spring Data JPA
• ORM → JPA
• Atividades:
• Criação do banco de dados
• Configuração da aplicação para integração com o BD (ex: MySQL, H2, etc)
• Configuração das classes e atributos usando anotações do JPA
• @Entity, @Id, @Column
• Anotações do Bean Validation podem ser usadas para criar restrições no banco de dados
(ex: campos not null, tamanho dos campos, etc)
• @OneToOne, @OneToMany/@ManyToOne e @ManyToMany → Usadas para mapear
relacionamentos entre entidades distintas
• Configuração e implementação das funcionalidades nos componentes
@Repository

Prof. Fernando Tsuda


Autenticação e autorização
• Autenticação – Identificar o usuário que acessa a aplicação. Saber
QUEM está acessando o sistema.
• Autenticação é feito através do Login (normalmente usando credenciais do
tipo identificação + senha)
• Manter informações do usuário autenticado em Sessão (sistemas
tradicionais) ou em Tokens (webservices)
• Mecanismo de autorização – Saber O QUE o usuário pode acessar
• Controlado através das Permissões/Papeis atribuídos ao usuário
Autenticação e autorização de acesso com
Spring Security
• Módulo do Spring responsável pelas funcionalidades relacionadas a
segurança de uma aplicação
• Implementar autenticação/autorização através das seguintes atividades
• Adicionar dependência do Spring Boot Security Starter no [Link]
• Desenvolver classe Permissao implementando a interface GrantedAuthority
• Desenvolver classe UsuarioSistema implementando a interface UserDetails
• Desenvolver classe de serviço UsuarioSistemaService implementando
UserDetailsService (método loadUserByUsername(String username))
• Criar classe de configuração SecurityConfig para permitir a associação dos padrões
de URL com os papeis definidos pela classe Permissao.
• Adicionar Beans PasswordEncoder e AuthenticationManager
• Criar @RestController de Login (+ desabilitar Form Login padrão do Spring Security)
• Verificar formato de configuração pós Spring Security 5.7/Spring Boot 2.7 (Beans de
configuração + Uso de funções Lambda DSL no método filterChain)

Prof. Fernando Tsuda


Filter chain

[Link]

Prof. Fernando Tsuda


Prof. Fernando Tsuda
Se estiver criando projeto novo em
[Link], pode-se adicionar a
Dependência [Link] dependência “security” na seção
correspondente.
<!-- SPRING SECURITY STARTER PADRÃO-->
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

<!-- PARA USAR JWT, ADICIONAR A DEPENDÊNCIA ABAIXO -->


<!-- JA INCLUI O STARTER PADRÃO ACIMA -->
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>

Prof. Fernando Tsuda


Spring Security Starter
• A configuração padrão do Spring Security Starter apresenta as
seguintes características
• Usuário padrão "user"
• Senha gerada aleatoriamente na inicialização da aplicação (apresentada no
log)
• Proteção de acesso para todas as URLs (rotas) da aplicação
• Telas para login e funcionalidade de logout

[Link]

Prof. Fernando Tsuda


Modelo genérico para associar Usuários X
Permissões
Classe Permissao
public class Permissao implements GrantedAuthority {

@Override
public String getAuthority() { return nome; }

OBS: A String retornada pelo método sempre deve ter


o prefixo “ROLE_” (ex: ROLE_ADMIN,
ROLE_FUNCIONARIO, ROLE_GERENTE)

Prof. Fernando Tsuda


Classe UsuarioSistema
public class UsuarioSistema implements UserDetails {

@Override
public String getUsername() { return username; }

@Override
public String getPassword() { return hashSenha; }

@Override
//public Collection<? extends GrantedAuthority> getAuthorities() {
public List<Permissao> getAuthorities() { return permissoes; }

// Opcional - IMPLEMENTAR DEMAIS MÉTODOS DE UserDetails


}
Prof. Fernando Tsuda
Classe UsuarioSistemaService
@Service
public class UsuarioSistemaService implements UserDetailsService {

@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
// LÓGICA PARA CARREGAR UM USUÁRIO VÁLIDO PELO USERNAME
// FORNECIDO

Prof. Fernando Tsuda


Classe SecurityConfig (1/3)
@Configuration
// @EnableMethodSecurity // <=== Habilita uso do @PreAuthorize e @PostAutorize
public class SecurityConfig {

// Delegating Password Encoder – suporte a múltiplos algoritmos de hash


@Bean
PasswordEncoder passwordEncoder() {
Map<String, PasswordEncoder> encoders = new HashMap<>();
BCryptPasswordEncoder bcryptEnc = new BCryptPasswordEncoder();
[Link]("bcrypt", bcryptEnc); // {bcrypt}HASH
[Link]("noop", [Link]()); // {noop}SENHA
var passwordEncoder = new DelegatingPasswordEncoder("bcrypt", encoders);
[Link](bcryptEnc);
return passwordEncoder;
}
// CONTINUA 2 ->

Prof. Fernando Tsuda


Classe SecurityConfig (2/3)
// -> CONTINUAÇÃO 2

// Bean authenticationManager - Usado para iniciar o fluxo de autenticação


@Bean
AuthenticationManager authenticationManager(
UsuarioSistemaService usuarioService,
PasswordEncoder passwordEncoder) {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
[Link](usuarioService);
[Link](passwordEncoder);
return new ProviderManager(authProvider);
}

// CONTINUA 3 ->

Prof. Fernando Tsuda


Classe SecurityConfig (3/3)
// -> CONTINUAÇÃO 3

// filterChain - Configuração geral dos parâmetros do Spring Security


// que serão ativados e pode-se configurar as autorizações de acesso
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.cors(cors -> [Link]())
.csrf(csrf -> [Link]())
.headers(headers -> [Link](fo -> [Link]())) // Permite mostrar H2 Console
.formLogin(formLogin -> [Link]())
.authorizeHttpRequests(authorize
-> authorize
.requestMatchers("/login", "/[Link]", "/[Link]",
"/h2-console/**",
"/[Link]", "/swagger-ui/**", "/v3/api-docs/**").permitAll()
.requestMatchers("/admin").hasAuthority("SCOPE_ADMIN")
.anyRequest().authenticated())
.build();
}

Prof. Fernando Tsuda


JWT - JSON Web Token
• Token com informações autocontidas a respeito do contexto onde ele será
usado
• RFC 7519
• Composto de informações denominadas "claims"
• Os dados são "codificados", porém são legíveis após a decodificação.
• O JWT prevê um mecanismo de assinatura para garantir a integridade das
informações (alterações no payload também alteram a assinatura)
• Composto de 3 partes, separadas por um "." (ponto)
• Header
• Payload → Dados do usuário que se logou + informações de validade
• Assinatura

Prof. Fernando Tsuda


Para criar/verificar JWT,
JWT - JSON Web Token acessar
[Link]
HEADER PAYLOAD (DADOS/CLAIMS)
{ {
"alg": "HS256", "sub": "fulano",
"typ": "JWT" "name": "Fulano da Silva",
} "iat": 1516239022
} Trecho do token marcado em
base64UrlEncode base64UrlEncode verde é usado para gerar
assinatura

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJmdWxhbm8iLCJuYW1lIjoiRnVsYW5vI
GRhIFNpbHZhIiwiaWF0IjoxNTE2MjM5MDIyfQ.jz3N590LAtw2TLMbcq-w95w3yqhOMS2fxM52-
fiTL1w

ASSINATURA
HMACSHA256(base64UrlEncode(HEADER) + "." + base64UrlEncode(PAYLOAD), segredo256bits)

Prof. Fernando Tsuda


Implementar mecanismo de criação do JWT
• Adicionar dependência para oauth2-resource-server no [Link]
• Criar as seguintes classes:
• JwtConfig - Beans para codificação e decodificação do JWT usando recursos
da biblioteca Nimbus (padrão usado pelo Spring Security)
• JwtService - Serviços para converter UsuarioSistema para JWT e vice-versa
• JwtAuthenticationFilter - Filtro para verificar se o JWT foi enviado no
cabeçalho HTTP Authorization e converter para objeto UsuarioSistema
• Uma vez que o token foi concedido, a aplicação deve confiar nas informações que estão
nele.
• No login, gerar JWT e retornar ao usuário

Prof. Fernando Tsuda


Dependência [Link]
<!-- SPRING SECURITY STARTER PADRÃO – PODE REMOVER SE USAR DEPENDÊNCIA ABAIXO -->
<!-- <dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency> -->

<!-- PARA USAR JWT, ADICIONAR A DEPENDÊNCIA ABAIXO E REMOVER O starter-security -->
<!-- JA INCLUI O STARTER PADRÃO ACIMA -->
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>

Prof. Fernando Tsuda


Classe JwtConfig (1/2)
@Configuration
public class JwtConfig {

// Chave simétrica para assinatura do JWT


private static final String CHAVE_ASSINATURA_JWT = "cH@v353cr37@"; // NÃO DEIXAR NO CÓDIGO

// Bean para a SecretKey - Chave simétrica usada tanto para codificar quanto decodificar com HMAC
@Bean
public SecretKey jwtSecretKey() {
try {
byte[] decodedKey = [Link]("SHA-256")
.digest(CHAVE_ASSINATURA_JWT.getBytes(StandardCharsets.UTF_8));
// Garante que a chave tem tamanho suficiente para HS256 (32 bytes)
if ([Link] < 32) { // 256 bits
// Poderia lançar uma exceção aqui para impedir a inicialização
throw new IllegalArgumentException("Deve ter pelo menos 256 bits.");
}
return new SecretKeySpec(decodedKey, 0, [Link], "HmacSHA256");
} catch (NoSuchAlgorithmException ex) {
throw new RuntimeException(ex);
} catch (IllegalArgumentException ex) {
throw new IllegalArgumentException("Chave secreta JWT Base64 inválida.", ex);
}
}
// CONTINUA 1 ->
Prof. Fernando Tsuda
Classe JwtConfig (2/2)
// -> CONTINUAÇÃO 1
// Bean para o JWKSource (necessário pelo NimbusJwtEncoder)
@Bean
public JWKSource<SecurityContext> jwkSource(SecretKey secretKey) {
// Cria um JWK do tipo OctetSequenceKey para HMAC
JWK jwk = new [Link](secretKey).build();
JWKSet jwkSet = new JWKSet(jwk);
return new ImmutableJWKSet<>(jwkSet);
}

// Bean para o JwtEncoder (usa JWKSource)


@Bean
public JwtEncoder jwtEncoder(JWKSource<SecurityContext> jwkSource) {
return new NimbusJwtEncoder(jwkSource);
}

// Bean para o JwtDecoder (usa a SecretKey diretamente para HMAC)


@Bean
public JwtDecoder jwtDecoder(SecretKey secretKey) {
// Configura o decoder para usar a chave secreta e o algoritmo HMAC SHA-256
return [Link](secretKey)
.macAlgorithm(MacAlgorithm.HS256) // Especifica o algoritmo esperado
.build();
}

} Prof. Fernando Tsuda


Classe JwtService (1/4)
@Service
public class JwtService {

@Autowired
private JwtEncoder jwtEncoder;

@Autowired
private JwtDecoder jwtDecoder;

private int intervaloExpiracao = 10; // 10 minutos

// Gera um token JWT para o usuário usando JwtEncoder


public String gerarJwt(UsuarioSistema usuario) {
Instant now = [Link]();
Instant expiry = [Link](intervaloExpiracao,
[Link]);

// Extrai as roles do UserDetails


List<String> permissoes = new ArrayList<>();
for (Permissao p : [Link]()) {
[Link]([Link]());
}

Prof. Fernando Tsuda


Classe JwtService (2/4)
// Define as claims do token
JwtClaimsSet claims = [Link]()
.issuer("pessoas-crud") // Emissor
.issuedAt(now) // Data de emissão
.expiresAt(expiry) // Data de expiração
.subject([Link]()) // Subject (username no nosso caso)
.claim("name", [Link]())
.claim("roles", permissoes) // Claim customizada com as roles
.build();

// Define o cabeçalho JWS - Usamos MacAlgorithm.HS256 que corresponde ao HmacSHA256


JwsHeader jwsHeader = [Link](MacAlgorithm.HS256).build();

// Codifica o token usando o JwtEncoder


try {
Jwt jwt = [Link]([Link](jwsHeader, claims));
return [Link]();
} catch (JwtEncodingException ex) {
// [Link]("Erro ao codificar token JWT: {}", [Link](), ex);
throw new RuntimeException("Erro ao gerar token JWT", ex);
}
}

Prof. Fernando Tsuda


Classe JwtService (3/4)
public UsuarioSistema obterUsuarioDoToken(String token) {
try {
Jwt jwt = decodificarToken(token);
final String username = [Link]();
List<String> permissoesToken = [Link]("roles");
List<Permissao> permissoes = new ArrayList<>();
for (String p : permissoesToken) {
[Link](new Permissao(p));
}
// CRIAR OBJETO COM DADOS DO USUARIO LOGADO
UsuarioSistema usuario = new UsuarioSistema([Link]("name"),
username, null, permissoes);
return usuario;
} catch (JwtException ex) {
// [Link]("Validação do JWT falhou: {}", [Link]());
}
return null;
}

Prof. Fernando Tsuda


Classe JwtService (4/4)
private Jwt decodificarToken(String token) throws JwtException {
try {
// O decoder já valida assinatura, expiração (com alguma tolerância talvez), e claims padrão
return [Link](token);
} catch (BadJwtException ex) {
// [Link]("Token JWT mal formado ou inválido: {}", [Link]());
throw ex; // Relança a exceção específica
} catch (JwtException ex) {
// [Link]("Erro inesperado ao decodificar JWT: {}", [Link](), e);
throw ex; // Relança outras exceções JWT
}
}
}

Prof. Fernando Tsuda


Classe JwtAuthenticationFilter (1/2)
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

@Autowired
private JwtService jwtService;

@Override
protected void doFilterInternal(
@NonNull HttpServletRequest request,
@NonNull HttpServletResponse response,
@NonNull FilterChain filterChain)
throws ServletException, IOException {

final String authHeader = [Link]("Authorization");


if (authHeader == null || ![Link]("Bearer ")) {
[Link](request, response);
return;
}

final String jwt = [Link](7);

Prof. Fernando Tsuda


Classe JwtAuthenticationFilter (2/2)
try {
UsuarioSistema usuario = [Link](jwt);
if (usuario == null) {
// [Link]("Token JWT inválido ou expirado detectado para o usuário '{}'.", userEmail);
// Não lançar exceção aqui, apenas não autentica
[Link]();
}
if ([Link]().getAuthentication() == null) {
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
usuario,
null,
[Link]()
);
[Link](new WebAuthenticationDetailsSource().buildDetails(request));
[Link]().setAuthentication(authToken);
}
} catch (Exception ex) {
// Não lançar exceção aqui, apenas não autentica
// [Link]("Erro ao processar token JWT no filtro: {}", [Link]());
[Link]();
}
[Link](request, response);
}
}
Prof. Fernando Tsuda
Alterar filterChain no SecurityConfig
@Autowired
private JwtAuthenticationFilter jwtAuthFilter;

@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

return http
.cors(cors -> [Link]())
.csrf(csrf -> [Link]())
.headers(headers -> [Link](fo -> [Link]())) // Permite mostrar H2 Console
.formLogin(formLogin -> [Link]())
// .sessionManagement(session -> [Link]([Link]))
.authorizeHttpRequests(authorize
-> authorize
.requestMatchers("/login", "/[Link]", "/[Link]",
"/h2-console/**",
"/[Link]", "/swagger-ui/**", "/v3/api-docs/**").permitAll()
// .requestMatchers("/peao").hasAuthority("SCOPE_PEAO")
// .requestMatchers("/gerente").hasAuthority("SCOPE_GERENTE")
// .requestMatchers("/diretor").hasAuthority("SCOPE_DIRETOR")
.anyRequest().authenticated())
// Injetar e adicionar filtro JWT ANTES do filtro padrão de Username/Password
.addFilterBefore(jwtAuthFilter, [Link])
.build();
} Prof. Fernando Tsuda
Spring Security – Integração com Swagger
• Para que o Swagger envie o JWT nas requisições, adicionar no projeto
a seguinte classe de configuração

@Configuration
@SecurityScheme(
name = "bearer-jwt",
type = [Link],
bearerFormat = "JWT",
scheme = "bearer"
)
public class SwaggerConfig {

Prof. Fernando Tsuda


Spring Security – Integração com Swagger
• Nas classes Controller, incluir a anotação abaixo na classe toda ou nos
métodos que necessitam de autenticação
@RestController
@SecurityRequirement(name = "bearer-jwt") // Aplica para todos endpoints
public class DadosController {

@Autowired
private UsuarioSistemaService usuarioService;

@GetMapping("/me")
// @SecurityRequirement(name = "bearer-jwt") // Somente neste método
public UsuarioSistemaDto obterDados(Authentication authn) {

// ...
}
}

Prof. Fernando Tsuda


Spring Security – Integração com frontend
• Implementar tela HTML + JS para tratar o token recebido
• Manter JWT em LocalStorage/SessionStorage como string ou em Cookie http-
only + secure
• Alterar código do Fetch API para enviar o token no cabeçalho "Authorization"
• Buscar informações do usuário → endpoint "/me“
• O username deve ser obtido do JWT decodificado

Prof. Fernando Tsuda


JWT - JSON Web Token
• Como "ler" o token usando Javascript -
[Link]
function decodificarJwt(jwt) {
const jwtParts = [Link]('.');
// Converte para base64 padrão (jwt usa base64Url)
const b64 = jwtParts[1].replace(/-/g, '+').replace(/_/g, '/’); // Extrai payload
const jwtData = decodeURIComponent(atob(b64)
.split('')
.map(c => '%' + ('00' + [Link](0).toString(16)).slice(-2))
.join(''));
alert('Dados token: ' + jwtData);
return [Link](jwtData);
}

Prof. Fernando Tsuda


Boas práticas
• OAuth2/OpenID
• Usado em aplicações famosas como Google, Azure AD, Facebook, etc
• 2FA/MFA (Two-factor authentication/Multi-factor authentication)
• Uso de passkeys – senhas temporárias enviadas por outro meio (ex:
e-mail)
• Spring Authorization Server
• Keycloak

Prof. Fernando Tsuda


Referências Spring para Webservices REST
• [Link]
reference/htmlsingle
• [Link]
boot/docs/current/reference/htmlsingle/
• [Link]
• [Link] (Vídeos Michelli
Brito)
• [Link] (Vídeos
Fernanda Kipper)

Prof. Fernando Tsuda


Referências PWA e REST
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
apps/
• [Link]
• [Link]

Prof. Fernando Tsuda


Desenvolvimento de
Sistemas Web

Integração com Banco de dados


usando JPA/Spring Data JPA
Versão 25.2.0

Prof. Fernando Tsuda


Objetivos
• Apresentação da técnica ORM
• Integração de aplicação Java com banco de dados
– JDBC
– JPA
– Spring Data JPA
Exemplo Base – Disponibilizada na versão inicial
Gerenciador de
Dados Pessoais
JDBC
• Java Database Connectivity
• Conjunto de classes e APIs responsáveis pela conexão e
execução de comandos SQL com o banco de dados
• Abstração do SGBD usado
Connection String - Exemplos
SGBD Driver Connection string
MySQL [Link] jdbc:mysql://<HOST>:3306/<DB>
MySQL (v8) [Link] jdbc:mysql://<HOST>:3306/<DB>?
useUnicode=yes&
characterEncoding=UTF-8&
useTimezone=true&
serverTimezone=UTC
JavaDB/Derby [Link] jdbc:derby://<HOST>:1527/<DB>
H2 [Link] jdbc:h2:file:~/<DBFILE>
MS SQL Server [Link]. jdbc:microsoft:sqlserver://<HOST>:1433[;D
SQLServerDriver atabaseName=<DB>]
Oracle Database [Link] jdbc:oracle:thin:@<HOST>:1521: <SID>
IBM DB2 [Link].DB2Driver jdbc:db2://<HOST>:6789/<DB>
(porta padrão tb pode ser 50000 ou 446)
PostgreSQL [Link] jdbc:postgresql://<HOST>:5432/<DB>

[Link]
JDBC
• Etapas de configuração
– Banco de dados
• Criar base de dados
• Criar tabelas
– Servidor de aplicações
• Criar pool de conexões
• Criar referência JNDI
– Aplicação
• Usar referência JNDI
Fluxo de conexão usual com JDBC

Executar comando
Abrir conexão com Fechar conexão com
SQL (Statement ou
BD BD
PreparedStatement)
JDBC - Obter conexão com BD
private Connection obterConexao()
throws ClassNotFoundException, SQLException {
Connection conn = null;

// Passo 1: Registrar driver JDBC


[Link]("[Link]");
// Passo 2: Obter a conexao
conn = [Link](
"jdbc:mysql://localhost:3306/produtobd",
"root", "");
return conn;
}
JDBC - Executar consulta
public Produto findById(Long id) {
String querySql = "SELECT ID, NOME, DESCRICAO FROM PRODUTO WHERE ID=?";
try (Connection conn = obterConexao();
PreparedStatement stmt = [Link](querySql)) {
[Link](1, id);
try (ResultSet resultados = [Link]()) {
while ([Link]()) {
Produto p = new Produto();
[Link]([Link]("ID"));
[Link]([Link]("NOME"));
[Link]([Link]("DESCRICAO"));
return p;
}
} Mapeamento dos dados da
} catch (SQLException | ClassNotFoundException ex) { registro do banco de dados
// TRATAR ERRO para o objeto Produto
}
return null;
}
Consulta JDBC

No JDBC:
- Pegar ResultSet
Aplicação - Iterar em cada item do ResultSet BD
OO - Criar o objeto na aplicação Relacional
- Popular objeto com dados da tabela
ORM
• Mapeamento objeto-relacional (Object-relational mapping)
• Técnica que possibilita configurar um componente responsável
pela conversão dos dados mantidos em uma estrutura
entidade-relacionamento (tabelas do banco de dados) para
uma estrutura orientada a objetos
– Cada registro do banco será convertido para um objeto durante a
execução da aplicação Java
ORM

No JDBC:
- Pegar ResultSet
Aplicação - Iterar em cada item do ResultSet BD
OO naORM
- Criar o objeto →
aplicação Relacional
- Popular objeto com dados da tabela
JPA
• Jakarta Persistence API (Antigo Java Persistence API)
• Permite o gerenciamento de dados relacionais através da
programação Java através da técnica ORM
• Oferece a linguagem Jakarta Persistence Query Language
(JPQL) para possibilitar a consulta aos dados
– Alternativa: Criteria API
• Assim como o JDBC, permite a transparência em relação ao
SGBD usado
JPA
• O JPA é uma especificação que faz parte do Jakarta EE (antigo
Java EE), ou seja, ele apenas define os recursos disponíveis,
sem entrar no nível da implementação, que é feita por outras
bibliotecas desenvolvidas por vários grupos/empresas.
• Exemplos de bibliotecas que implementam o JPA:
– Hibernate (após versão 3.5.0 - usada pelo Spring Boot)
– EclipseLink (biblioteca usada pelo Glassfish)
– OpenJPA
Consulta JPA

No JDBC:
JPA
- Pegar pega os dados da
ResultSet
Aplicação - Iterar em tabela e gera
cada item do ResultSet BD
OO - Criar o objeto na aplicação Relacional
automaticamente
- Popular os
objeto com dados da tabela
Classes geradas Objetos
representam as
tabelas do BD dentro
do código Java
JPA
• Etapas de configuração
– Banco de dados
• Criar banco de dados Não precisa fazer ao usar H2
– Aplicação Spring Boot
• Adicionar dependências do Driver JDBC do banco usado e spring-boot-starter-
data-jpa no arquivo [Link]
• Adicionar as configurações de conexão no arquivo [Link]
• O Spring Boot usa o Hibernate como implementação JPA
– OBS: Para aplicações Jakarta/Java EE NÃO-SPRING → Configurações para acesso
ao banco devem ficar dentro do arquivo META-INF/[Link]
Dependências no [Link]

<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency> <!-- TROCAR PARA VERSÃO DO BANCO USADA NO PROJETO -->
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
Configurações no [Link] para H2
# Configuracoes do Banco de dados
[Link]=h2
[Link]-class-name=[Link]
# No Windows, cria o arquivo "[Link]" no diretorio C:\Usuarios\[usuario]
# Para reiniciar o banco, apagar o arquivo e reiniciar a aplicacao Spring boot
[Link]=jdbc:h2:file:~/nome-banco
[Link]=sa
[Link]=
Caso não seja feita nenhuma
configuração, o Spring Data JPA irá
[Link]-sql=true
gerar um banco em memória com
[Link]-auto=update
nome aleatório - Ver no log o nome
#[Link]-in-view=false gerado
O banco em memória é apagado
# Configuracoes especificas do banco H2 quando a aplicação é parada
[Link]=true
[Link]-allow-others=true
Configurações no [Link]
para MySQL 8

# Configuracoes para acessar MySQL 8+


# Para funcionar o MySQL deve estar instalado e rodando na porta 3306
# O banco "nome-banco" também deve estar criado
[Link]-class-name=[Link]
[Link]=jdbc:mysql://localhost:3306/nome-banco
[Link]=root
[Link]=
[Link]=[Link]
[Link]-sql=true
[Link]-auto=update
#[Link]-in-view=false
JPA
• Para usar o JPA na aplicação, normalmente são necessários os
seguintes passos:
– Criar as classes de entidade e configurá-las com as Annotations do
JPA, que irão definir seu mapeamento com a tabela do Banco de
Dados e os relacionamentos
– Implementar as funções necessárias para o funcionamento da
aplicação (consultas, inclusões, alterações, remoções, etc).
JPA
• Annotations na classe de entidade (OBS: todos pertencem ao pacote
[Link] [Link])
– @Entity – Indica que a classe será mapeada a uma tabela do BD
– @Table – Permite indicar o nome da tabela mapeada a entidade
• Annotations usadas nos atributos das classes:
– @Id – Indica que o atributo será o identificador da entidade (chave primária)
– @GeneratedValue – Indica que o valor do ID será gerado automaticamente
– @Column – Permite indicar o nome da coluna mapeada ao atributo e outras
propriedades como obrigatoriedade, tamanho do campo, restrições, etc)
– @Temporal – Indica que o atributo mantém uma informação de data e hora (vale para
atributos do tipo Date ou Calendar) – Não precisa para LocalDate/LocalDateTime ou
derivados
– @Transient – Indica que o atributo não será salvo no banco de dados
JPA
• Anotações para declarar relacionamentos entre entidades:
– @OneToOne
– @OneToMany e @ManyToOne
– @ManyToMany
• Anotações auxiliares para a criação dos relacionamentos
– @JoinTable
– @JoinColumn
Exemplo Base – Disponibilizada na versão inicial
Do ponto de vista do banco de dados,
Do ponto de vista do banco de dados,
qual tipo de relacionamento existe qual tipo de relacionamento existe
entre DadosPessoais e FotoPessoa? entre DadosPessoais e Interesse?

1. OneToOne 1. OneToOne
2. OneToMany 2. OneToMany
3. ManyToMany 3. ManyToMany
JPA – Exemplo OneToMany (1/2)
@Entity
@Table(name = "TB_IMAGEM_PRODUTO")
public class ImagemProduto implements Serializable {

@Id
@GeneratedValue(strategy = [Link])
@Column(name = "ID_IMAGEM")
private Integer id;

@Column(name = "NM_IMAGEM", nullable = false)


private String nomeArquivo;

@ManyToOne(fetch = [Link])
@JoinColumn(name = "ID_PRODUTO", nullable = false)
private Produto produto;
}

[Link]
JPA – Exemplo OneToMany (2/2)
@Entity
@Table(name = "TB_PRODUTO")
public class Produto implements Serializable {

@Id
@GeneratedValue(strategy = [Link])
@Column(name = "ID_PRODUTO")
private Integer id;

@Column(name = "NM_PRODUTO", nullable = false)


private String nome;

@OneToMany(mappedBy = "produto")
// produto é o nome do atributo na classe ImagemProduto
private List<ImagemProduto> imagens;
}

[Link]
JPA – Exemplo ManyToMany (1/2)
@Entity
@Table(name = "TB_PRODUTO")
public class Produto implements Serializable {

@Id
@GeneratedValue(strategy = [Link])
@Column(name = "ID_PRODUTO")
private Integer id; O @JoinTable permite
configurar a tabela de
@Column(name = "NM_PRODUTO", nullable = false) relacionamento entre as
private String nome; duas entidades no banco
de dados
@ManyToMany
@JoinTable(name = "TB_PRODUTO_CATEGORIA",
joinColumns = {@JoinColumn(name = "ID_PRODUTO")},
inverseJoinColumns = {@JoinColumn(name = "ID_CATEGORIA")})
private List<Categoria> categorias;
}

[Link]
JPA – Exemplo ManyToMany (2/2)
@Entity
@Table(name = "TB_CATEGORIA")
public class Categoria implements Serializable {

@Id
@GeneratedValue(strategy = [Link])
@Column(name = "ID_CATEGORIA", nullable = false)
private Integer id;

@Column(name = "NM_CATEGORIA", nullable = false, unique = true)


// unique = true evita a duplicação do nome.
private String nome;

@ManyToMany(mappedBy = "categorias", fetch = [Link])


// categorias é o nome do atributo na classe Produto
private List<Produto> produtos;
}

[Link]
Implementação da lógica
• As operações do JPA são sempre executadas através do
EntityManager, que é responsável pelo mapeamento dos
dados dos objetos/entidades da aplicação nas tabelas do
banco de dados e vice-versa.
Obtenção do EntityManager nos projetos Spring
Boot
• A classe deve ter a anotação @Repository
public class ExemploRepository {
@Repository
• O objeto EntityManager deve ser @PersistenceContext
associado a classe de repositório private EntityManager entityManager;
através de um atributo anotado // Implementar os métodos de
com @PersistenceContext // consulta ao banco de dados usando
• O objeto EntityManager será // os recursos do JPA
configurado usando as }
informações de conexão
fornecidas no arquivo
[Link]
Consulta aos dados
• A query de consulta pode ser escrita usando a JPQL, que possuí
uma sintaxe parecida com a SQL dos bancos de dados relacionais.
• Ex: SELECT p FROM Produto p
– Notar que Produto refere-se à classe Produto da aplicação configurada
como @Entity, e não a tabela do banco de dados.
• O JPQL deve ser criado e executado através do EntityManager (ver
exemplos nos próximos slides e no código de exemplo).
• É recomendável o uso do TypedQuery para evitar a conversão de
tipos de Classes usando "casting"
Consulta aos dados
• Ex: Listar os produtos cadastrados no sistema:

public List<Produto> listar() {


Query query = [Link](
"SELECT p FROM Produto p");
List<Produto> resultados = [Link]();
return resultados;
}

[Link]
Consulta aos dados
• Ex: Recuperar um único objeto a partir de seu ID:

public Produto obter(Integer id) {


Query query = [Link](
"SELECT p FROM Produto p WHERE [Link] = :idProd")
.setParameter("idProd", id);
Produto resultado = (Produto) [Link]();
return resultado;
}
Inclusão de uma nova entidade
• Ex: Salvar um novo produto no sistema
– OBS: Incluir a anotação @Transactional (pacote [Link])
antes do nome do método

@Transactional
public void incluir(Produto p) {
[Link](p);
}
Alteração de uma entidade existente
• Ex: Alterar um produto no sistema
– OBS: Incluir a anotação @Transactional (pacote [Link])
antes do nome do método
– O objeto Produto deve ter o ID definido (não nulo)

@Transactional
public void alterar(Produto p) {
Produto pAlterado = [Link](p);
}
Exclusão de uma entidade existente
• Ex: Excluir um produto do sistema
– OBS: Incluir a anotação @Transactional (pacote [Link]) antes
do nome do método
– O objeto Produto deve ter o ID definido (não nulo)

@Transactional
public void excluir(Integer idProduto) {
// TEM QUE FAZER CONSULTA PARA ESTAR ASSOCIADO AO
// ENTITY MANAGER (ESTADO "ATTACHED")
Produto p = [Link]([Link], idProduto);
[Link](p);
}
Consulta aos dados com Criteria API
• Forma alternativa para realizar consultas aos dados, onde cada
consulta é desenvolvida dinamicamente através de programação
Java (a partir do JPA 2.0)
• Uma vantagem é que seu permite criar consultas “tipadas”, ou seja,
os tipos de dados retornados são conhecidos durante o
desenvolvimento.
– No caso do JPQL, a JVM só pode inferir o tipo de dado retornado durante a
fase de execução (runtime)
• Uma desvantagem é que a escrita das consultas pode ficar
extremamente complexa.
Consulta aos dados com Criteria API
• Uso do JPQL para recuperar um Produto pelo ID
Query jpqlQuery =
[Link]("SELECT p FROM Produto p WHERE [Link] = :idProd")
.setParameter("idProd", id)
Produto p = (Produto) [Link](); // CAST de Object para Produto

• Uso do Criteria API para recuperar um produto pelo ID


CriteriaBuilder cb = [Link]();
CriteriaQuery<Produto> criteriaQuery = [Link]([Link]);
Root<Produto> root = [Link]([Link]);
[Link]([Link]([Link]("id"), id));
TypedQuery<Produto> query = [Link](criteriaQuery);
Produto p = [Link]();
JPA no Spring
• Opção “[Link]-in-view” habilitada por padrão – Mantém
conexão com banco de dados aberta enquanto a requisição HTTP
estiver sendo processada (pode fazer automaticamente consultas
adicionais para trazer informações faltantes)
– Apesar de estar habilitada por padrão, não é uma boa prática manter esta
opção ativada (notar WARN nos logs após iniciar a aplicação)
– Alternativas
• Usar fetch = EAGER (também não é uma boa prática - problema n+1)
• Escrever as consultas fazendo JOIN FETCH
• Uso do Entity Graph
• Representar as entidades usando DTOs
Desenvolvimento de
Sistemas Web

Integração com Banco de dados


usando JPA/Spring Data JPA
Versão 21.2.0

Prof. Fernando Tsuda


Objetivos
• Apresentação da técnica ORM
• Integração de aplicação Java com banco de dados
– JDBC
– JPA
– Spring Data JPA
• Ajustar a aplicação de exemplo para uso do Spring Data JPA
Spring Data JPA
• Módulo do Spring responsável por funcionalidades que visam
acessar os dados de um banco de dados usando o JPA.
• Notar que, ao contrário do JPA “puro” visto até aqui, o Spring Data
JPA NÃO É parte do JEE (Jakarta/Java EE)
• Para maior aproveitamento, são necessários alguns pré-requisitos:
– Conhecimento básico do JPA para definir propriedades das Entidades
– Entender a hierarquia das interfaces disponibilizadas pelo Spring Data JPA
– Entender a regra do Spring Data para criar as consultas
Conhecimento básico JPA
• Configurações das classes que serão mapeadas nas tabelas do
banco de dados
– @Entity
– @Table
– @Id
– @GeneratedValue
– @Column
– @OneToOne/@ManyToOne/@OneToMany/@ManyToMany
• @JoinTable e @JoinColumn
– Outras anotações de configuração das Entidades
Conhecimento básico JPA
• Desenvolvimento das ações no banco
– Anotação @Transaction (importado do pacote
[Link]) nos métodos que
modificam algum registro no banco de dados
Hierarquia das interfaces Spring Data JPA
<<interface>> public interface MeuRepository extends
Repository JpaRepository<ClasseEntidade, IdEntidade> {
// MeuRepository herda as
Spring <<interface>>
// funcionalidades das classes pai
Data [List]CrudRepository }

<<interface>>
[List]PagingAndSortingRepository

Spring <<interface>>
Data JPA [Link]
JpaRepository
commons/tree/main/src/main/java/org/springframework/data/repository

[Link]
<<interface>>
jpa/src/main/java/org/springframework/data/jpa/repository/[Link]
MeuRepository
Spring Data JPA

[Link]
Spring Data JPA
public class Person { // ENTIDADE DE EXEMPLO

Query Methods (1/3) @Id


private
private
String id;
String firstname;
private String lastname;
private Address address;

// getters and setters omitidos


}

Keyword Sample JPQL snippet


Distinct findDistinctByLastnameAndFirstname select distinct …​where [Link] = ?1 and
[Link] = ?2
And findByLastnameAndFirstname … where [Link] = ?1 and [Link] = ?2

Or findByLastnameOrFirstname … where [Link] = ?1 or [Link] = ?2

Is, Equals findByFirstname, findByFirstnameIs, … where [Link] = ?1 (or … where


findByFirstnameEquals [Link] IS NULL if the argument is null)
Between findByStartDateBetween … where [Link] between ?1 and ?2

False findByActiveFalse() … where [Link] = false

IgnoreCase findByFirstnameIgnoreCase … where UPPER([Link]) = UPPER(?1)

[Link]
Query Methods (2/3)
Keyword Sample JPQL snippet
LessThan findByAgeLessThan … where [Link] < ?1
LessThanEqual findByAgeLessThanEqual … where [Link] <= ?1
GreaterThan findByAgeGreaterThan … where [Link] > ?1
GreaterThanEqual findByAgeGreaterThanEqual … where [Link] >= ?1
After findByStartDateAfter … where [Link] > ?1
Before findByStartDateBefore … where [Link] < ?1
IsNull, Null findByAge(Is)Null … where [Link] is null
IsNotNull, NotNull findByAge(Is)NotNull … where [Link] is not null
Like findByFirstnameLike … where [Link] like ?1
NotLike findByFirstnameNotLike … where [Link] not like ?1
Query Methods (3/3)
Keyword Sample JPQL snippet
StartingWith findByFirstnameStartingWith … where [Link] like ?1 (parameter bound with
appended %)
EndingWith findByFirstnameEndingWith … where [Link] like ?1 (parameter bound with
prepended %)
Containing findByFirstnameContaining … where [Link] like ?1 (parameter bound wrapped
in %)
OrderBy findByAgeOrderByLastnameDesc … where [Link] = ?1 order by [Link] desc
Not findByLastnameNot … where [Link] <> ?1
In findByAgeIn(Collection<Age> ages) … where [Link] in ?1
NotIn findByAgeNotIn(Collection<Age> ages) … where [Link] not in ?1
True findByActiveTrue() … where [Link] = true
False findByActiveFalse() … where [Link] = false
IgnoreCase findByFirstnameIgnoreCase … where UPPER([Link]) = UPPER(?1)
Regra geral
• Para consultas onde o resultado é único: método declarado no
Repository pode retornar Optional<ClasseEntity>
• Para consultas onde o resultado pode ter mais de um item:
método declarado no Repository pode retornar
List<ClasseEntity>
– Em sistemas complexos, atentar-se para otimizar as informações
retornadas (ex: uso de paginação)
@Query e @NativeQuery
// Uso do JPQL do JPA
@Query("SELECT p FROM Pessoa p WHERE [Link] = :id")
Optional<Pessoa> buscarComJpql(Integer id);

// Uso de SQL nativo do banco de dados


// Tabela pessoa e campo id seguindo nomenclatura criada no banco de dados
@NativeQuery("SELECT * FROM pessoa WHERE id = :id")
// OU @Query(value = "SELECT * FROM pessoa WHERE id = :id", nativeQuery = true)
Optional<Pessoa> buscarComSqlNativo(Integer id);
Criação dos métodos de busca
[Link]

[Link]

[Link]
Outros tópicos
• Auditoria de alterações
– JPA Auditing
– Envers
• Versionamento do banco de dados
– Liquibase
– Flyway
Referências
• [Link]
• [Link]
• [Link]

Você também pode gostar