Você está na página 1de 45

Spring Web: Criando aplicações

backend
Notas de aula
Mauricio Escobar

Revisão: Maio. 2023.


Dependências comuns/necessárias

Spring Boot Dev Tools Resultado no POM.XML:


Spring Data JPA <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
MySQL Driver </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
Spring Web <artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
A dependência de Web é <artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
para a segunda parte da </dependency>
<dependency>
disciplina… <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Configuração geral no arquivo
src/main/resources/application.properties

# # Propriedades do ambiente de desenvolvimento ##


# modo de operacao do hibernate
# https://springhow.com/spring-boot-database-initialization/
spring.jpa.hibernate.ddl-auto=update

# String de conexao. O nome lp3 ao final indica o nome do database que sera utilizado
# No MySQL voce pode usar o comando "create database lp3" para criar uma nova base de dados
spring.datasource.url=jdbc:mysql://localhost:3306/lp3

# nome do usuario e senha do banco


spring.datasource.username=root
spring.datasource.password=root
# spring.datasource.password=alunoinfo # para uso nos laboratorios do if

spring.jpa.show-sql=false # opcional, se quiser mostrar no console os comandos SQL executados


server.port=8080
Data
Definindo uma Entidade

Sempre definir as classes de vocês a partir do pacote de código-fonte base do projeto. Nunca em níveis
hierárquicos acima.

Anotação que marca a


classe como sendo uma
entidade persistente…

Marca o atributo como ID


(chave primária)

Encapsulamento
padrão: getters e Estratégia que define
setters… automaticamente o valor
do ID (autoincremento)...
Definindo uma Entidade O Spring usa o nome dos elementos
para gerar as estruturas no banco de
dados automaticamente

No banco, será gerada uma tabela


chamada “pessoa” com uma coluna de
valor inteiro chamada “id”

Se houver algum atributo ou nome de


classe no padrão camel case, no nível
do banco será usado o caractere _
Definindo uma Entidade

Como o Spring constrói automaticamente as estruturas do banco, é importante regularmente


inspecionar as tabelas para verificar se o resultado está ficando como esperado.

Opcionalmente, você pode usar as anotações @Table e @Column para especializar ainda mais a tabela.
Note que a anotação @Table não substitui a anotação @Entity.

Passe para o próximo slide…

Inspeção da tabela
usando o MySQL
Workbench, clicando
com o botão direito na
tabela desejada e
selecionando a opção
Alter Table
Refinando a entidade
Quando o nome da entidade (classe) difere
do nome da tabela…

length só pode ser usado em strings…


nullable false indica que não pode ser nulo no banco

Precisão e escala de um número decimal

Usamos columnDefinition para comandos específicos


de um determinado banco ou não previstos através
de anotações…
Refinando a entidade

Resultado do
mapeamento…
Valores padrão sem afetar a estrutura da tabela

Não afeta a estrutura da


tabela. Os valores padrão
são utilizados se omitidos
no momento de salvar a
entidade.
Manipulando dados com o uso de repositórios

Um repositório é uma abstração do Spring Data cujo objetivo é reduzir significativamente o código
repetitivo necessário para implementar o acesso aos dados nas diferentes fontes/camadas de
persistência.

Sintaxe:
Tipo de dado do ID

Nome da interface: você Entidade que será


define de acordo com a manipulada pelo
entidade mapeada repositório
Manipulando dados com o uso de repositórios

Principais métodos HERDADOS (você não precisa declarar eles) da interface CrudRepository:

Salvar ou atualizar uma entidade.


Retorna a instância atualizada.
Buscar uma entidade por ID

<S extends T> S save(S entity); Retornar todas as instâncias


armazenadas. O retorno pode ser
armazenado em um List<T>
T findOne(ID primaryKey);
Retornar o número de instâncias
Iterable<T> findAll(); armazenadas

Long count();
Recebe a instância a ser removida.
Nesse caso, o ID deve possuir um
void delete(T entity); valor válido.

boolean exists(ID primaryKey);


Verificar se há alguma instância
armazenada com o ID informado.
Exemplo de uso
Exemplo de uso

Você pode usar uma classe anotada Ela será instanciada


como @Component para testes ou automaticamente pelo Spring (ao
funcionalidades pontuais… rodar a classe MAIN), e todos os
métodos anotados como
@PostConstruct também serão
chamados automaticamente…
A anotação @Autowired serve para
que a instanciação seja feita pelo
Spring, isto é, ele fará uma injeção
de dependência.

Salva e guarda o retorno para poder


ter o valor do ID após a inserção no
banco…
Exemplo de uso
Ainda na classe @Component,
criamos mais um método de teste.
Agora para listar no console todas
as instâncias armazenadas…

Estrutura FOR simplificada para


percorrer todos os elementos de
uma coleção. A variável local “m”
guarda o elemento da vez.

Resultado
Definindo Query Methods

Os query methods são operações definidas em um repositório que permitem realizar consultas
personalizadas em uma base de dados usando uma sintaxe concisa e convenções na escrita das
operações.

Através do nome do método (seguindo uma convenção de nomenclatura), tipo de retorno e parâmetros, o
Spring Data é capaz de interpretar automaticamente e gerar a consulta correspondente.
Definindo Query Methods
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repository-query-keywords

Palavras chave (prefixos) comuns:

find…By - Normalmente usada para retornar o tipo de dado do repositório, uma coleção, etc.

count…By - Retorna um valor numérico contendo a projeção (contagem) de valores

remove…By, delete…By - Remove um elemento retornando nenhum valor (void) ou o número de


elementos removidos

…First<numero>...

…Top<numero>...

…Discintct…
Definindo Query Methods
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repository-query-keywords

Operadores Logicos: Modificadores:

And, Or, After, Before


IgnoreCase, Used with a predicate
IgnoringCase
Containing keyword for
case-insensitive
Between
comparison.
Exists
AllIgnoreCase, Ignore case for all suitable
AllIgnoringCase
GreaterThan properties. Used
somewhere in the query
LessThan
method predicate.
e muitos outros
OrderBy…
Definindo Query Methods - exemplos
Relacionamento entre entidades
1:1 OneToOne Anotações do Lombok

Cascade são as operações


Aqui é o NOME do
propagadas para a entidade
atributo que detalha o
relacionada (user) ao manipular a
mapeamento… o “dono”
entidade base (profile)
da relação.

Anotação para
detalhar a chave
estrangeira
1:1 OneToOne

Apenas para teste. Limpa a tabela


antes de inserir novos dados.

Esse builder é um facilitador do


lombok para popular um objeto e
gerar uma instância

Relaciona as instâncias e…

Salva a entidade base no banco. Se não tivesse o CASCADE


PERSIST, cada entidade deveria ter sido salva individualmente,
primeiro o USER, depois PROFILE
para a Web
Criando um serviço web através de uma classe de controle

Rota base para todas as operações do controller


(opcional, pois pode ser definido também em
cada operação)
@Controller
@RequestMapping("/hello") Operação que trata
public class HelloWorldController { chamadas HTTP do tipo
GET
@GetMapping
@ResponseBody
public String hello() { Serializar e coloca o retorno do
método no corpo da resposta HTTP
return String.format("Olá mundo");
para a aplicação cliente
}
}
O tipo de retorno pode ser qualquer classe Java
serializável…
Testando

1. Execute a Main do projeto


2. Abra o navegador ou o Postman
3. Acesse através da seguinte URL:
http://localhost:8080/hello @Controller
@RequestMapping("/hello")
/hello é uma ROTA (caminho relativo no servidor de aplicação) public class HelloWorldController {
para acessar o controller. 8080 é a porta padrão do Tomcat ou
a definida manualmente no arquivo .properties @GetMapping
@ResponseBody
public String hello() {
return String.format("Olá mundo");
}
}
Qual o problema dessa implementação?

@Controller
@RequestMapping("/hello")
public class HelloWorldController {

@GetMapping O problema aqui é


ambiguidade, isto é, há
@ResponseBody
rotas iguais para as
public String hello() {
mesmas operações HTTP.
return String.format("Olá mundo");
}
A ambiguidade pode
aparecer em um mesmo
@GetMapping
controller, que é o caso
@ResponseBody
aqui, ou entre classes de
public String hello2() {
controle diferentes…
return String.format("Hello world");
}
}
Resolvendo a ambiguidade…

@Controller
@RequestMapping("/hello")
public class HelloWorldController {

@GetMapping
@ResponseBody
public String hello() {
return String.format("Olá mundo");
}

@GetMapping("/world")
@ResponseBody
public String hello2() {
return String.format("Hello world"); Perceba a agregação na
} URL
}
Lidando com parâmetros (vindos do lado cliente)

Parâmetros são
informações enviadas
na requisição
Forma 1: parâmetros no formato par chave-valor

Exemplo de URL: http://localhost:8080/hello?nome=Mauricio&sobrenome=Escobar

O caractere “?” marca o início da área de parâmetros para a rota /hello

A partir daí, os parâmetros possuem uma chave que os identifica, o sinal de igual, e um valor.

Cada parâmetro adicional é separado pelo caractere & (e comercial). O limite de parâmetros que formam
a requisição pode variar dependendo das tecnologias na camada do servidor.

Acentuação, espaços em branco, etc, devem ser devidamente codificados. As linguagens modernas
normalmente possuem APIs para isso…
Vamos ao código…

Exemplo de URL: http://localhost:8080/hello?nome=Mauricio&sobrenome=Escobar


Vamos ao código… Dessa forma, os parâmetros
são opcionais na requisição.
É atribuído o valor null caso
ele não seja enviado pela
aplicação cliente
Para detalhar as restrições de um parâmetro do tipo
chave-valor, use a anotação @RequestParam
Valor padrão caso o parâmetro não seja enviado
ou possua valor vazio. Usada quando required é
false.

Nome do parâmetro. Como deve aparecer


na requisição. Pode ser diferente do nome
do argumento da operação Java.
Indica se o parâmetro é obrigatório ou não. Gera um erro HTTP
400 - Bad Request
Exemplo:
Exemplo
Forma 2: parâmetros que influenciam no
caminho/rota
Exemplo de URL: http://localhost:8080/hello/Mauricio/Escobar

Note, que no exemplo acima, os valores Mauricio e Escobar formam um caminho para o servidor, a partir
da rota base /hello.

Neste exemplo em específico, o nome vêm sempre antes do sobrenome. A ordem de formação da URL
deve ser respeitada, isto é, é uma forma mais rígida do que a mostrada anteriormente.

Para trabalhar com esse formato, usa-se a anotação @PathVariable

Cuidado, pois os mapeamentos usando PathVariable podem gerar ambiguidades (comentei nos slides
iniciais)...
Exemplo

Mapeamento usando o nome do argumento.


Exemplo

Mapeamento explícito usando o nome da variável


no caminho (URL)

Por padrão, os parâmetros na URL são obrigatórios. Você pode


mudar esse comportamento utilizando a propriedade required
dentro da anotação @PathVariable. Mas cuidado com a rota
resultante…
Exemplo Variações (possibilidades) de
rota para esta operação…

Ter um argumento opcional


implica em ter uma variação na
rota
Exemplo

Você pode utilizar o tipo


Optional para facilitar as
operações de teste para
parâmetros não obrigatórios
Associando o Controller à camada de dados

Considerando que você possui as entidades e os repositórios, utilize a anotação @Autoriwed, como
mostrado no exemplo a seguir.

Essa anotação realiza a injeção de dependência.

Na prática, é o framework Spring que fica responsável por criar uma instância dos repositórios, para
facilitar seu uso e evitar códigos repetitivos.
Exemplo
Forma 3: recebendo objetos (em JSON)

O JSON (JavaScript Object Notation) é um formato leve para o intercâmbio de dados entre aplicações.

É fácil, inclusive, para humanos lerem e escreverem em seu formato.

JSON pode ser visto como um subconjunto da linguagem JavaScript e é de fácil conversão e geração a
partir de programas construídos em praticamente qualquer linguagem de programação (moderna).

Exemplo de um objeto simples em JSON: Exemplo de um array de objetos em JSON:


[
{ {

“nome” : “Mauricio”, “nome” : “Mauricio”, “sobrenome” : “Escobar”

},
“sobrenome” : “Escobar”
{

} “nome” : “João”, “sobrenome” : “da Silva”

]
Vamos ao Spring:
Utilize esta anotação para o Spring converter
o JSON de entrada em um objeto Java

Agora você pode receber um objeto


(entidade, DTO, ou qualquer padrão de
objetos de transferência)
Para testar, você pode utilizar o Postman…
Tipo de operação HTTP Aqui você executa a requisição
Rota

Agora os dados serão enviados no CORPO da


requisição, e não mais na área de parâmetros ou
URL

Selecione RAW e depois JSON


no tipo de conteúdo do corpo

Aqui vai o conteúdo em JSON


(corpo da requisição)

E aqui nesta zona são mostrados os


detalhes da resposta que o Spring retornou.
Continua nos próximos capítulos…

Você também pode gostar