Manual Da API Spring Boot
Manual Da API Spring Boot
Arquitetura da API
A API segue uma arquitetura em camadas, comumente utilizada em aplicações
Spring Boot, compreendendo:
• Modelos (Entidades): Representam os dados da aplicação e são mapeadas
para tabelas no banco de dados.
• Repositórios: Camada de acesso a dados, responsável pela comunicação com o
banco de dados para operações CRUD (Create, Read, Update, Delete).
• Serviços: Camada de lógica de negócios, onde as regras e operações mais
complexas são implementadas, utilizando os repositórios para interagir com os
dados.
• Controladores: Camada de apresentação, responsável por expor os endpoints
da API, receber requisições HTTP, interagir com os serviços e retornar
respostas.
• Formulários (DTOs): Objetos de Transferência de Dados utilizados para
transportar dados entre as camadas, especialmente entre os controladores e os
serviços, e para validar entradas.
• Configurações: Classes de configuração, como a configuração de CORS, para
definir o comportamento da aplicação.
Componentes da API
1. Entidades (Models)
As entidades representam os objetos de domínio da aplicação.
2. Repositórios (Repositories)
Os repositórios são interfaces que estendem JpaRepository do Spring Data
JPA, fornecendo métodos para interagir com o banco de dados.
3. Serviços (Services)
Os serviços contêm a lógica de negócios da aplicação.
4. Formulários (Forms/DTOs)
Os formulários são utilizados para receber e validar dados de entrada nas
requisições.
5. Controladores (Controllers)
Os controladores gerenciam as requisições HTTP e as respostas da API.
6. Configurações (Configuration)
Arquivos de configuração da aplicação.
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
@Entity
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Uf {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer coduf;
@Column
private String nomeuf;
@Column
private String sigla;
@OneToMany(mappedBy="uf")
private java.util.List<Cidade> cidades;
Anotações Utilizadas:
• @Entity: Marca esta classe como uma entidade JPA, indicando que ela
representa uma tabela no banco de dados.
• @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) :
Usada pela biblioteca Jackson (para serialização/desserialização JSON) para
ignorar propriedades específicas que podem causar problemas durante a
serialização, especialmente em contextos de lazy loading do Hibernate.
hibernateLazyInitializer e handler são propriedades injetadas pelo
Hibernate para gerenciar o carregamento tardio de associações.
• @Id: Especifica que o atributo coduf é a chave primária da entidade.
• @GeneratedValue(strategy = GenerationType.AUTO): Configura a forma
como a chave primária é gerada. GenerationType.AUTO permite que o
provedor de persistência (Hibernate, neste caso) escolha a estratégia mais
apropriada (geralmente uma sequência ou uma coluna de auto incremento no
banco de dados).
• @Column: Embora não seja estritamente necessário para atributos simples (o
JPA pode inferi-los), pode ser usado para especificar detalhes da coluna, como
nome, nulidade, tamanho, etc. Aqui, é usado implicitamente para nomeuf e
sigla.
• @OneToMany(mappedBy="uf"): Define um relacionamento um-para-muitos
entre Uf e Cidade. Uma UF pode ter muitas cidades. O atributo mappedBy="uf"
indica que o lado Cidade da relação é o proprietário do relacionamento, e o
mapeamento é feito pelo atributo uf na classe Cidade. Isso significa que a
tabela Cidade terá uma chave estrangeira referenciando a UF.
Atributos:
• private Integer coduf: Representa o código identificador único da UF. É a
chave primária da tabela.
• private String nomeuf: Armazena o nome completo da Unidade Federativa
(ex: “São Paulo”).
• private String sigla: Armazena a sigla da Unidade Federativa (ex: “SP”).
• private java.util.List<Cidade> cidades: Representa a lista de cidades que
pertencem a esta UF. Este é o lado “muitos” do relacionamento OneToMany com
a entidade Cidade.
Métodos:
A classe Uf possui os métodos getters e setters padrão para todos os seus
atributos (coduf, nomeuf, sigla). Estes métodos permitem o acesso e a modificação
dos valores dos atributos da entidade:
• getCoduf(): Retorna o código da UF.
• setNomeuf(String nomeuf): Define o nome da UF.
• getNomeuf(): Retorna o nome da UF.
• setSigla(String sigla): Define a sigla da UF.
• getSigla(): Retorna a sigla da UF.
• setCoduf(Integer coduf): Define o código da UF.
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Sexo {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer codsexo;
@Column
private String nomesexo;
Anotações Utilizadas:
• @Entity: Designa esta classe como uma entidade JPA, indicando seu
mapeamento para uma tabela de banco de dados.
• @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) :
Similar à entidade Uf, esta anotação instrui o Jackson a ignorar propriedades
específicas do Hibernate durante a serialização JSON, prevenindo problemas
com lazy loading.
• @Id: Marca o atributo codsexo como a chave primária da entidade Sexo.
• @GeneratedValue(strategy = GenerationType.AUTO): Configura a geração
automática da chave primária codsexo, permitindo que o provedor de
persistência determine a melhor estratégia (como auto incremento ou
sequence).
• @Column: Usada implicitamente para o atributo nomesexo, indicando que ele
será mapeado para uma coluna na tabela Sexo.
Atributos:
• private Integer codsexo: O identificador único para cada registro de sexo.
Funciona como a chave primária.
• private String nomesexo: Armazena a descrição do sexo (ex: “Masculino”,
“Feminino”, “Outro”).
Métodos:
A classe Sexo fornece os métodos getters e setters padrão para seus atributos:
• getCodsexo(): Retorna o código do sexo.
• setCodsexo(Integer codsexo): Define o código do sexo.
• getNomesexo(): Retorna o nome/descrição do sexo.
• setNomesexo(String nomesexo): Define o nome/descrição do sexo.
Assim como a entidade Uf, a classe Sexo não possui construtores explícitos,
utilizando o construtor padrão fornecido pelo Java, que é uma exigência para
entidades JPA. Esta entidade é mais simples, não possuindo relacionamentos diretos
com outras entidades neste trecho de código, servindo como uma tabela de lookup
para os possíveis valores de sexo que podem ser associados a outras entidades no
sistema (por exemplo, um cliente ou usuário).
1.3. Entidade Cidade.java
A classe Cidade representa uma cidade dentro do sistema e está
intrinsecamente ligada a uma Unidade Federativa ( Uf). É uma entidade JPA mapeada
para uma tabela no banco de dados.
package com.fatec.comercio.models;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
@Entity
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Cidade {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer codcidade;
@Column
private String nomecidade;
@ManyToOne
@JoinColumn(name = "coduffk")
private Uf uf;
public Uf getUf() {
return uf;
}
public Cidade() {
}
}
Anotações Utilizadas:
• @Entity: Define Cidade como uma entidade JPA, indicando que será persistida
no banco de dados.
• @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) :
Similar às entidades anteriores, esta anotação é usada pelo Jackson para evitar
problemas de serialização com propriedades do Hibernate relacionadas ao lazy
loading.
• @Id: Marca codcidade como a chave primária da entidade.
• @GeneratedValue(strategy = GenerationType.AUTO): Configura a geração
automática da chave primária codcidade.
• @Column: Usada implicitamente para nomecidade, mapeando-o para uma
coluna na tabela Cidade.
• @ManyToOne: Define um relacionamento muitos-para-um entre Cidade e Uf.
Muitas cidades podem pertencer a uma única UF. Este é o lado proprietário do
relacionamento.
• @JoinColumn(name = "coduffk"): Especifica a coluna no banco de dados que
atuará como chave estrangeira para o relacionamento com Uf. A coluna na
tabela Cidade que armazena o ID da UF será nomeada coduffk.
Atributos:
• private Integer codcidade: O identificador único para cada cidade, atuando
como chave primária.
• private String nomecidade: Armazena o nome da cidade (ex: “Campinas”).
• private Uf uf: Representa a Unidade Federativa à qual a cidade pertence.
Este atributo estabelece o vínculo com a entidade Uf.
Construtores:
A classe Cidade possui dois construtores explícitos:
• public Cidade(String nomecidade, Uf uf): Um construtor parametrizado
que permite criar uma instância de Cidade fornecendo diretamente o nome da
cidade e o objeto Uf associado. Isso é útil para criar novas cidades já vinculadas
a uma UF.
• public Cidade(): Um construtor padrão (sem argumentos). Este construtor é
essencial para o funcionamento do JPA, que o utiliza para instanciar objetos da
entidade ao recuperá-los do banco de dados.
Métodos:
A classe Cidade inclui os métodos getters e setters padrão para todos os seus
atributos (codcidade, nomecidade, uf):
• getCodcidade(): Retorna o código da cidade.
• setCodcidade(Integer codcidade): Define o código da cidade.
• getNomecidade(): Retorna o nome da cidade.
• setNomecidade(String nomecidade): Define o nome da cidade.
• getUf(): Retorna o objeto Uf associado à cidade.
• setUf(Uf uf): Define o objeto Uf associado à cidade.
@Entity
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Cep {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer codcep;
@Column
private String numerocep;
Anotações Utilizadas:
• @Entity: Marca esta classe como uma entidade JPA, indicando que ela
representa uma tabela no banco de dados.
• @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) :
Utilizada pela biblioteca Jackson para ignorar propriedades específicas do
Hibernate durante a serialização JSON, o que é útil para evitar problemas com o
carregamento tardio (lazy loading).
• @Id: Especifica que o atributo codcep é a chave primária da entidade Cep.
• @GeneratedValue(strategy = GenerationType.AUTO): Configura a forma
como a chave primária codcep é gerada. A estratégia GenerationType.AUTO
permite que o provedor de persistência (Hibernate) escolha a estratégia mais
apropriada, como uma sequência ou uma coluna de auto incremento.
• @Column: Usada implicitamente para o atributo numerocep, indicando que ele
será mapeado para uma coluna na tabela Cep.
Atributos:
• private Integer codcep: Representa o código identificador único do CEP. É a
chave primária da tabela.
• private String numerocep: Armazena o número do CEP (ex: “13083-852”).
Métodos:
A classe Cep possui os métodos getters e setters padrão para todos os seus
atributos (codcep, numerocep). Estes métodos permitem o acesso e a modificação dos
valores dos atributos da entidade:
• getCodcep(): Retorna o código do CEP.
• setCodcep(Integer codcep): Define o código do CEP.
• getNumerocep(): Retorna o número do CEP.
• setNumerocep(String numerocep): Define o número do CEP.
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMethod;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
@CrossOrigin(
origins = "http://localhost:4200",
methods = { RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT,
RequestMethod.DELETE },
allowedHeaders = "*",
maxAge = 3600 // Tempo de cache do CORS (em segundos)
)
public class Bairro {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer codbairro;
@Column
private String nomebairro;
Anotações Utilizadas:
• @Entity: Designa esta classe como uma entidade JPA, indicando seu
mapeamento para uma tabela de banco de dados.
• @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) :
Instrução para a biblioteca Jackson ignorar propriedades específicas do
Hibernate durante a serialização JSON, útil para evitar problemas com lazy
loading.
• @CrossOrigin(...): Esta anotação é usada para configurar o CORS
diretamente no nível da entidade ou, mais comumente, em controladores. Aqui,
ela está configurada para permitir requisições da origem
http://localhost:4200 (provavelmente uma aplicação frontend Angular),
para os métodos HTTP GET, POST, PUT, DELETE, permitindo todos os
cabeçalhos (allowedHeaders = "*") e definindo um tempo de cache para as
respostas preflight de CORS de 3600 segundos (maxAge = 3600). É importante
notar que, embora funcional, aplicar @CrossOrigin em entidades JPA não é a
prática mais comum; geralmente, é aplicada em classes @RestController ou
configurada globalmente.
• @Id: Marca o atributo codbairro como a chave primária da entidade Bairro.
• @GeneratedValue(strategy = GenerationType.AUTO): Configura a geração
automática da chave primária codbairro, permitindo que o provedor de
persistência escolha a estratégia apropriada.
• @Column: Usada implicitamente para o atributo nomebairro, indicando que ele
será mapeado para uma coluna na tabela Bairro.
Atributos:
• private Integer codbairro: O identificador único para cada registro de
bairro. Funciona como a chave primária.
• private String nomebairro: Armazena o nome do bairro (ex: “Centro”, “Vila
Mariana”).
Métodos:
A classe Bairro fornece os métodos getters e setters padrão para seus
atributos:
• getCodbairro(): Retorna o código do bairro.
• setCodbairro(Integer codbairro): Define o código do bairro.
• getNomebairro(): Retorna o nome do bairro.
• setNomebairro(String nomebairro): Define o nome do bairro.
Assim como as entidades Sexo e Cep, a classe Bairro é uma entidade simples
sem relacionamentos diretos explícitos com outras entidades neste trecho de código.
Ela serve para armazenar informações sobre bairros, que podem ser associados a
outras entidades (como endereços) em diferentes partes do sistema. A ausência de
construtores explícitos indica o uso do construtor padrão Java, necessário para JPA.
Declaração da Interface:
• public interface UfRepository extends JpaRepository<Uf, Integer> :
– public interface UfRepository: Declara uma interface pública
chamada UfRepository.
– extends JpaRepository<Uf, Integer>: Esta é a parte crucial. Ao
estender JpaRepository, a interface UfRepository herda uma série de
métodos para interagir com a entidade Uf.
• O primeiro parâmetro genérico, Uf, especifica a entidade que
este repositório gerenciará.
• O segundo parâmetro genérico, Integer, especifica o tipo da
chave primária da entidade Uf (que é coduf, do tipo Integer).
Métodos Herdados (Exemplos Comuns de JpaRepository):
Ao estender JpaRepository, UfRepository automaticamente disponibiliza
métodos como:
• save(Uf entity): Salva ou atualiza uma entidade Uf.
• findById(Integer id): Busca uma Uf pelo seu ID (retorna um Optional<Uf>).
• findAll(): Retorna uma lista de todas as entidades Uf.
• deleteById(Integer id): Deleta uma Uf pelo seu ID.
• count(): Retorna o número total de entidades Uf.
• E muitos outros, incluindo métodos para paginação e ordenação.
Métodos Personalizados Definidos na Interface:
Além dos métodos herdados, UfRepository define dois métodos de consulta
personalizados. O Spring Data JPA tem um mecanismo poderoso para criar consultas
automaticamente a partir da assinatura dos métodos (query methods).
• public Uf findByCoduf(Integer id);
– Este método busca uma entidade Uf com base no valor do seu atributo
coduf.
– O Spring Data JPA interpreta o nome do método: “find By Coduf”. Ele
procura um atributo chamado coduf na entidade Uf e cria uma consulta
para encontrar um registro onde coduf seja igual ao parâmetro id
fornecido.
– Retorna um único objeto Uf ou null se nenhuma UF for encontrada com
o código especificado.
• public Uf findByNomeuf(String nomeuf);
– Este método busca uma entidade Uf com base no valor do seu atributo
nomeuf.
– Similarmente, o Spring Data JPA interpreta o nome do método: “find By
Nomeuf”. Ele procura um atributo chamado nomeuf na entidade Uf e cria
uma consulta para encontrar um registro onde nomeuf seja igual ao
parâmetro nomeuf fornecido (ignorando maiúsculas/minúsculas
dependendo da configuração do banco de dados e da estratégia de
consulta).
– Retorna um único objeto Uf ou null se nenhuma UF for encontrada com
o nome especificado.
Uso no Sistema:
A interface UfRepository será injetada (usando @Autowired) em classes de
serviço (como UfService) para permitir que a lógica de negócios realize operações de
persistência relacionadas às Unidades Federativas. O Spring Data JPA cuidará da
implementação concreta desta interface em tempo de execução, eliminando a
necessidade de escrever implementações DAO (Data Access Object) manualmente.
2.2. Repositório SexoRepository.java
A interface SexoRepository é a camada de acesso a dados para a entidade
Sexo. Similarmente ao UfRepository, ela estende JpaRepository do Spring Data JPA,
o que lhe confere automaticamente métodos para operações CRUD e outras
funcionalidades de persistência para a entidade Sexo.
package com.fatec.comercio.repository;
Declaração da Interface:
• public interface SexoRepository extends JpaRepository<Sexo,
Integer>:
– Declara uma interface pública SexoRepository.
– Ao estender JpaRepository<Sexo, Integer>, esta interface herda
métodos CRUD para a entidade Sexo, cuja chave primária (codsexo) é
do tipo Integer.
Métodos Herdados (Exemplos Comuns de JpaRepository):
Assim como UfRepository, SexoRepository herda métodos como save(),
findById(), findAll(), deleteById(), count(), entre outros, aplicáveis à entidade
Sexo.
Uso no Sistema:
A interface SexoRepository será injetada em classes de serviço (como
SexoService) para fornecer acesso aos dados da entidade Sexo, permitindo que a
lógica de negócios execute operações de persistência relacionadas a sexo. O Spring
Data JPA gerencia a implementação desta interface em tempo de execução.
Declaração da Interface:
• public interface CidadeRepository extends JpaRepository<Cidade,
Integer>:
– Declara uma interface pública denominada CidadeRepository.
– Ao estender JpaRepository<Cidade, Integer>, esta interface herda
um conjunto completo de métodos CRUD para a entidade Cidade. O tipo
da chave primária da entidade Cidade (codcidade) é Integer.
Métodos Herdados (Exemplos Comuns de JpaRepository):
Assim como os outros repositórios, CidadeRepository herda métodos padrão
como save(Cidade entity), findById(Integer id), findAll(),
deleteById(Integer id), count(), e outros, todos aplicáveis à entidade Cidade.
Declaração da Interface:
• public interface CepRepository extends JpaRepository<Cep, Integer> :
– Declara uma interface pública chamada CepRepository.
– Ao estender JpaRepository<Cep, Integer>, esta interface herda
métodos CRUD para a entidade Cep. A chave primária da entidade Cep
(codcep) é do tipo Integer.
Métodos Herdados (Exemplos Comuns de JpaRepository):
CepRepository herda automaticamente métodos padrão como save(Cep
entity), findById(Integer id), findAll(), deleteById(Integer id), count(),
entre outros, todos aplicáveis à entidade Cep.
Métodos Personalizados Definidos na Interface:
CepRepository define dois métodos de consulta personalizados, que o Spring
Data JPA implementará com base em seus nomes:
• public Cep findByCodcep(Integer id);
– Este método é destinado a buscar uma entidade Cep específica com base
no valor do seu atributo codcep.
– O Spring Data JPA interpreta o nome do método (“find By Codcep”) e
gera a consulta correspondente para encontrar um registro onde o
campo codcep seja igual ao parâmetro id fornecido.
– Espera-se que retorne um único objeto Cep ou null se nenhum CEP com
o código especificado for encontrado.
• public Cep findByNumerocep(String numerocep);
– Este método busca uma entidade Cep com base no valor do seu atributo
numerocep.
– O Spring Data JPA, ao analisar o nome do método (“find By
Numerocep”), cria uma consulta para localizar um registro onde o
campo numerocep seja igual ao parâmetro numerocep fornecido.
– Retorna um único objeto Cep ou null caso nenhum CEP com o número
especificado seja encontrado.
Código Comentado (Observações):
O arquivo CepRepository.java também contém uma seção de código
comentado. É importante notar que os exemplos dentro deste bloco comentado
(findByCodsexoAndNomesexo, a query @Query("select s from sexo s where
s.codsexo > 2"), etc.) parecem ter sido copiados de SexoRepository e não foram
adaptados para a entidade Cep. Em um contexto real, esses exemplos deveriam
referenciar atributos e a entidade Cep se fossem destinados a ela.
Uso no Sistema:
A interface CepRepository será injetada (usando @Autowired) em classes de
serviço que necessitam interagir com dados de CEPs. Isso permite que a lógica de
negócios realize operações de persistência relacionadas aos CEPs, como buscar,
salvar, ou deletar registros de CEPs, com o Spring Data JPA gerenciando a
implementação da interface em tempo de execução. Isso abstrai a complexidade do
acesso direto ao banco de dados.
Declaração da Interface:
• public interface BairroRepository extends JpaRepository<Bairro,
Integer>:
– Declara uma interface pública chamada BairroRepository.
– Ao estender JpaRepository<Bairro, Integer>, esta interface herda
métodos CRUD para a entidade Bairro. A chave primária da entidade
Bairro (codbairro) é do tipo Integer.
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.fatec.comercio.models.Uf;
import com.fatec.comercio.repository.UfRepository;
@Service
public class UfService {
//injeção de dependência
@Autowired
private UfRepository ufRepository;
Construtor:
• UfService (UfRepository ufRepository){ this.ufRepository =
ufRepository; }: Este é um construtor que recebe uma instância de
UfRepository. Embora a injeção de dependência via @Autowired no campo já
seja suficiente, a injeção via construtor é frequentemente considerada uma
melhor prática, pois torna as dependências explícitas e facilita os testes
unitários. O comentário “Aqui o Erro” sugere que talvez houvesse alguma
intenção ou problema anterior com este construtor, mas na forma apresentada,
ele é uma forma válida de injeção de dependência (embora redundante se
@Autowired no campo já estiver presente e funcionando como esperado pelo
desenvolvedor).
Métodos do Serviço:
Os métodos em UfService geralmente delegam as chamadas para os métodos
correspondentes em UfRepository e podem adicionar lógica de negócios adicional se
necessário (embora, nestes exemplos, eles sejam principalmente pass-throughs
diretos).
• public List<Uf> allUfs(): Retorna uma lista de todas as UFs cadastradas.
Ele chama o método findAll() do ufRepository.
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.fatec.comercio.models.Sexo;
import com.fatec.comercio.repository.SexoRepository;
@Service
public class SexoService {
//injeção de dependência
@Autowired
private SexoRepository sexoRepository;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.fatec.comercio.forms.CidadeForm;
import com.fatec.comercio.models.Cidade;
import com.fatec.comercio.models.Uf;
import com.fatec.comercio.repository.CidadeRepository;
import com.fatec.comercio.repository.UfRepository;
@Service
public class CidadeService {
@Autowired
private CidadeRepository cidadeRepository;
@Autowired
private UfRepository ufRepository; // Dependência adicional para
buscar UFs
cidade.setNomecidade(cidadeForm.getNomecidade());
cidade.setUf(uf); // Define a UF (potencialmente atualizada)
// O save aqui não está sendo chamado, então a edição não será
persistida.
// Deveria haver um cidadeRepository.save(cidade) para persistir
as alterações.
return cidade; // Retorna a cidade modificada (mas não persistida
no estado atual do código)
}
}
• public void apagaId(Integer id): Deleta uma cidade pelo seu ID, chamando
cidadeRepository.deleteById(id) .
Propósito e Uso:
CidadeService centraliza a lógica de negócios para a entidade Cidade. Ele lida
com a conversão de DTOs (CidadeForm) para entidades, a busca de entidades
relacionadas (Uf), e a delegação de operações de persistência para os repositórios. Os
controladores (CidadeController) devem usar este serviço para todas as operações
relacionadas a cidades, promovendo uma arquitetura em camadas bem definida.
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.fatec.comercio.models.Bairro;
import com.fatec.comercio.repository.BairroRepository;
@Service
public class BairroService {
@Autowired
private BairroRepository bairroRepository;
import com.fatec.comercio.models.Cidade;
import com.fatec.comercio.models.Uf;
import com.fatec.comercio.repository.UfRepository;
public class CidadeForm {
// Getters e Setters
public Integer getCodcidade() {
return codcidade;
}
public void setCodcidade(Integer codcidade) {
this.codcidade = codcidade;
}
public String getNomecidade() {
return nomecidade;
}
public void setNomecidade(String nomecidade) {
this.nomecidade = nomecidade;
}
public String getNomeuf() {
return nomeuf;
}
public void setNomeuf(String nomeuf) {
this.nomeuf = nomeuf;
}
Atributos:
• private Integer codcidade: Este campo pode ser usado para identificar uma
cidade existente durante uma operação de atualização. Para a criação de uma
nova cidade, ele geralmente seria nulo ou não utilizado, pois o código da cidade
é gerado automaticamente pelo banco de dados.
• private String nomecidade: Armazena o nome da cidade que está sendo
criada ou atualizada.
• private String nomeuf: Armazena o nome da Unidade Federativa (UF) à qual
a cidade pertence. Este nome será usado para buscar a entidade Uf
correspondente no banco de dados.
Métodos:
• Getters e Setters: A classe fornece métodos get e set padrão para todos os
seus atributos (codcidade, nomecidade, nomeuf). Estes são usados pelo
framework Spring MVC (ou similar, como Jackson para desserialização JSON)
para popular o objeto CidadeForm com os dados da requisição HTTP e para
acessar seus valores.
5. Controladores (Controllers)
Os controladores são responsáveis por lidar com as requisições HTTP de
entrada, processá-las (geralmente delegando para a camada de serviço) e retornar
uma resposta HTTP ao cliente. Eles são a porta de entrada da API.
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fatec.comercio.models.Uf;
import com.fatec.comercio.service.UfService;
import jakarta.transaction.Transactional;
import java.util.List;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
// import org.springframework.web.bind.annotation.RequestParam; // Não
utilizado neste controller
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.PutMapping;
@RestController
@RequestMapping("/ufs") // Mapeia todas as requisições para /ufs para
este controller
public class UfController {
Anotações e Configurações:
• @RestController: Esta é uma anotação de conveniência que combina
@Controller e @ResponseBody. Ela indica que esta classe lida com requisições
REST e que os valores retornados pelos seus métodos devem ser diretamente
ligados ao corpo da resposta HTTP (geralmente convertidos para JSON ou
XML).
• @RequestMapping("/ufs"): Mapeia todas as requisições HTTP que começam
com o caminho /ufs para os métodos manipuladores (handler methods)
dentro desta classe. Por exemplo, uma requisição GET para /ufs será tratada
pelo método getUf().
Injeção de Dependência e Construtor:
• private final UfService ufService;: Declara uma dependência final do
UfService. O uso de final junto com a injeção via construtor é uma boa
prática para garantir que a dependência seja imutável após a criação do objeto.
• UfController(UfService ufService) { this.ufService = ufService; } :
Este é o construtor da classe, que recebe uma instância de UfService. O Spring
utiliza este construtor para realizar a injeção de dependência. O comentário
“Criei o Construtor - Esquecemos Essa Parada” sugere que a injeção via
construtor foi uma adição ou correção posterior, o que é uma prática
recomendada em relação à injeção por campo (@Autowired diretamente no
campo).
Métodos (Endpoints da API):
• @GetMapping("") public List<Uf> getUf():
– Mapeia requisições HTTP GET para /ufs.
– Chama ufService.allUfs() para obter a lista de todas as UFs.
– Retorna a lista de UFs, que será convertida para JSON na resposta HTTP.
• @GetMapping("/{id}") public Uf pegaUfId(@PathVariable Integer id) :
– Mapeia requisições HTTP GET para /ufs/{id}, onde {id} é uma
variável de caminho (path variable) que representa o código da UF.
– @PathVariable Integer id: Extrai o valor de id da URL e o converte
para Integer.
– Chama ufService.ufId(id) para buscar a UF correspondente.
– Retorna a entidade Uf encontrada (ou null/erro se não encontrada,
dependendo da implementação do serviço), que será convertida para
JSON.
• @DeleteMapping("/{id}") public String apagaSexoId(@PathVariable
Integer id):
– Mapeia requisições HTTP DELETE para /ufs/{id}.
– Observação: O nome do método apagaSexoId é um pouco enganoso,
pois ele está deletando uma Uf, não um Sexo. Seria mais claro se fosse
nomeado como apagaUfId ou similar.
– Chama ufService.apagaId(id) para deletar a UF.
– Retorna uma mensagem de string indicando o sucesso da operação.
• @PostMapping("") public String salvaDadosUf(@RequestBody Uf uf) :
– Mapeia requisições HTTP POST para /ufs.
– @RequestBody Uf uf: Indica que o corpo da requisição HTTP (esperado
em formato JSON) deve ser desserializado em um objeto Uf.
– Chama ufService.salvarUf(uf) para persistir a nova UF.
– Retorna uma mensagem de string confirmando o cadastro.
• @PutMapping("/{id}") @Transactional public String
atualizaDadosUf(@PathVariable Integer id, @RequestBody Uf uf) :
– Mapeia requisições HTTP PUT para /ufs/{id}.
– @PathVariable Integer id: Extrai o ID da UF a ser atualizada da URL.
– @RequestBody Uf uf: Obtém os novos dados da UF do corpo da
requisição.
– @Transactional: Esta anotação é importante, especialmente para
operações de atualização. Ela garante que o método seja executado
dentro de uma transação do banco de dados. Se o método editaUf no
serviço modificar uma entidade gerenciada pelo JPA dentro desta
transação, as alterações podem ser automaticamente persistidas ao final
da transação (dirty checking), dependendo da configuração. No entanto,
como UfService.editaUf explicitamente chama save, a transação aqui
garante atomicidade.
– Chama ufService.editaUf(uf, id) para atualizar a UF.
– Retorna uma mensagem de string indicando o sucesso da atualização.
Propósito e Uso:
UfController expõe as funcionalidades de gerenciamento de UFs através de
uma API RESTful. Clientes HTTP (como frontends de aplicações web, aplicações
móveis ou outros serviços) podem interagir com estes endpoints para realizar
operações CRUD sobre os dados das Unidades Federativas. O controlador delega a
lógica de negócios real para UfService, mantendo-se focado em lidar com a
comunicação HTTP.
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fatec.comercio.models.Sexo;
import com.fatec.comercio.service.SexoService;
import jakarta.transaction.Transactional;
import java.util.List;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
// import org.springframework.web.bind.annotation.RequestParam; // Não
utilizado neste controller
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.PutMapping;
@RestController
@RequestMapping("/sexos") // Mapeia todas as requisições para /sexos para
este controller
public class SexoController {
Anotações e Configurações:
• @RestController: Indica que esta classe é um controlador REST, cujos
métodos retornam dados que são diretamente escritos no corpo da resposta
HTTP (geralmente em JSON).
• @RequestMapping("/sexos"): Mapeia todas as requisições HTTP que começam
com o caminho base /sexos para os métodos manipuladores definidos nesta
classe.
Injeção de Dependência e Construtor:
• private final SexoService sexoService;: Declara uma dependência final
do SexoService.
• SexoController(SexoService sexoService) { this.sexoService =
sexoService; }: Construtor utilizado pelo Spring para injetar a dependência
de SexoService. O comentário “Criei o Construtor - Esquecemos Essa Parada”
sugere que esta forma de injeção (via construtor, que é uma prática
recomendada) foi implementada posteriormente.
Métodos (Endpoints da API):
• @GetMapping("") public List<Sexo> getSexo():
– Mapeia requisições HTTP GET para /sexos.
– Chama sexoService.allSexos() para obter a lista de todas as
entidades Sexo.
– Retorna a lista de Sexo, que será serializada para JSON.
• @GetMapping("/{id}") public Sexo pegaSexoId(@PathVariable Integer
id):
– Mapeia requisições HTTP GET para /sexos/{id}, onde {id} é o código
do sexo.
– @PathVariable Integer id: Extrai o valor de id da URL.
– Chama sexoService.sexoId(id) para buscar o Sexo correspondente.
– Retorna a entidade Sexo encontrada.
• @DeleteMapping("/{id}") public String apagaSexoId(@PathVariable
Integer id):
– Mapeia requisições HTTP DELETE para /sexos/{id}.
– Chama sexoService.apagaId(id) para deletar o Sexo.
– Retorna uma mensagem de string confirmando a exclusão.
• @PostMapping("") public String salvaDadosSexo(@RequestBody Sexo
sexo):
– Mapeia requisições HTTP POST para /sexos.
– @RequestBody Sexo sexo: Indica que o corpo da requisição HTTP
(esperado em JSON) deve ser desserializado em um objeto Sexo.
– Chama sexoService.salvarSexo(sexo) para persistir a nova entidade
Sexo.
– Retorna uma mensagem de string confirmando o cadastro.
• @PutMapping("/{id}") @Transactional public String
atualizaDadosSexo(@PathVariable Integer id, @RequestBody Sexo
sexo):
– Mapeia requisições HTTP PUT para /sexos/{id}.
– @PathVariable Integer id: Extrai o ID do Sexo a ser atualizado da
URL.
– @RequestBody Sexo sexo: Obtém os novos dados do Sexo do corpo da
requisição.
– @Transactional: Garante que a operação de atualização seja executada
dentro de uma transação do banco de dados, promovendo a
atomicidade da operação.
– Chama sexoService.editaSexo(sexo, id) para atualizar a entidade
Sexo.
– Retorna uma mensagem de string indicando o sucesso da atualização.
Propósito e Uso:
SexoController serve como a interface RESTful para as operações
relacionadas à entidade Sexo. Ele recebe requisições HTTP, delega a lógica de
processamento para SexoService e retorna respostas apropriadas para o cliente. Esta
estrutura segue o padrão de arquitetura em camadas, separando as responsabilidades
de manipulação de requisições (controller) da lógica de negócios (service) e do acesso
a dados (repository).
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fatec.comercio.forms.CidadeForm; // DTO para entrada de dados
de cidade
import com.fatec.comercio.models.Cidade;
import com.fatec.comercio.service.CidadeService;
import jakarta.transaction.Transactional;
import java.util.List;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
// import org.springframework.web.bind.annotation.RequestParam; // Não
utilizado neste controller
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.PutMapping;
@RestController
@RequestMapping("/cidades") // Mapeia todas as requisições para /cidades
para este controller
public class CidadeController {
Anotações e Configurações:
• @RestController: Designa esta classe como um controlador REST, onde os
valores de retorno dos métodos são diretamente serializados no corpo da
resposta HTTP (normalmente como JSON).
• @RequestMapping("/cidades"): Define o caminho base para todas as
requisições manipuladas por este controlador. Todas as requisições que
começam com /cidades serão direcionadas para cá.
Injeção de Dependência e Construtor:
• private final CidadeService cidadeService;: Declara uma dependência
final do CidadeService.
• CidadeController(CidadeService cidadeService) { this.cidadeService
= cidadeService; }: Construtor que o Spring utiliza para injetar a
dependência de CidadeService. O comentário “Criei o Construtor -
Esquecemos Essa Parada” indica que a injeção via construtor (uma prática
recomendada) foi uma adição ou correção posterior.
Métodos (Endpoints da API):
• @GetMapping("") public List<Cidade> getCidade():
– Mapeia requisições HTTP GET para /cidades.
– Chama cidadeService.allCidades() para obter a lista de todas as
entidades Cidade.
– Retorna a lista de Cidade, que será serializada para JSON.
• @GetMapping("/{id}") public Cidade pegaCidadeId(@PathVariable
Integer id):
– Mapeia requisições HTTP GET para /cidades/{id}, onde {id} é o
código da cidade.
– @PathVariable Integer id: Extrai o valor de id da URL.
– Chama cidadeService.cidadeId(id) para buscar a Cidade
correspondente.
– Retorna a entidade Cidade encontrada.
• @DeleteMapping("/{id}") public String apagaCidadeId(@PathVariable
Integer id):
– Mapeia requisições HTTP DELETE para /cidades/{id}.
– Chama cidadeService.apagaId(id) para deletar a Cidade.
– Retorna uma mensagem de string confirmando a exclusão.
• @PostMapping("") public String salvaDadosCidade(@RequestBody
CidadeForm cidadeForm):
– Mapeia requisições HTTP POST para /cidades.
– @RequestBody CidadeForm cidadeForm: Indica que o corpo da
requisição HTTP (esperado em JSON) deve ser desserializado em um
objeto CidadeForm (o DTO).
– Chama cidadeService.salvarCidade(cidadeForm) para processar o
DTO e persistir a nova entidade Cidade.
– Retorna uma mensagem de string confirmando o cadastro, utilizando o
nome da cidade do cidadeForm.
• @PutMapping("/{id}") @Transactional public String
atualizaDadosCidade(@PathVariable Integer id, @RequestBody
CidadeForm cidadeForm):
– Mapeia requisições HTTP PUT para /cidades/{id}.
– @PathVariable Integer id: Extrai o ID da Cidade a ser atualizada da
URL.
– @RequestBody CidadeForm cidadeForm: Obtém os novos dados da
Cidade do corpo da requisição, na forma de um CidadeForm.
– @Transactional: Garante que a operação de atualização seja executada
dentro de uma transação do banco de dados. Isso é particularmente
importante se o método de serviço editaCidade realizar múltiplas
operações no banco ou depender do dirty checking do JPA (embora, no
CidadeService analisado, a persistência da edição parecia estar
faltando uma chamada save).
– Chama cidadeService.editaCidade(cidadeForm, id) para processar
o DTO e atualizar a entidade Cidade.
– Retorna uma mensagem de string indicando o sucesso da atualização.
Propósito e Uso:
CidadeController atua como a interface RESTful para as operações
relacionadas à entidade Cidade. Ele recebe requisições HTTP, utiliza o CidadeForm
para capturar dados de entrada para criação e atualização, delega a lógica de
processamento para CidadeService e retorna respostas apropriadas para o cliente.
Esta abordagem mantém uma clara separação de responsabilidades entre as camadas
da aplicação, seguindo as melhores práticas de design de APIs REST e arquitetura
Spring Boot.
5.4. Controlador BairroController.java
A classe BairroController é um controlador REST (@RestController) que
gerencia as requisições HTTP relacionadas à entidade Bairro. Ela define os endpoints
para as operações CRUD (Criar, Ler, Atualizar, Deletar) sobre os dados dos bairros,
delegando a lógica de negócios para BairroService.
package com.fatec.comercio.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fatec.comercio.models.Bairro;
import com.fatec.comercio.service.BairroService;
import jakarta.transaction.Transactional;
import java.util.List;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
// import org.springframework.web.bind.annotation.RequestParam; // Não
utilizado neste controller
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.PutMapping;
@RestController
@RequestMapping("/bairros") // Mapeia todas as requisições para /bairros
para este controller
public class BairroController {
Anotações e Configurações:
• @RestController: Designa esta classe como um controlador REST. Os valores
de retorno dos seus métodos são diretamente serializados no corpo da
resposta HTTP (geralmente como JSON).
• @RequestMapping("/bairros"): Define o caminho base para todas as
requisições manipuladas por este controlador. Todas as requisições que
começam com /bairros serão direcionadas para os métodos desta classe.
Injeção de Dependência e Construtor:
• private final BairroService bairroService;: Declara uma dependência
final do BairroService.
• BairroController(BairroService bairroService) { this.bairroService
= bairroService; }: Construtor utilizado pelo Spring para injetar a
dependência de BairroService. O comentário “Criei o Construtor -
Esquecemos Essa Parada” sugere que a injeção via construtor (uma prática
recomendada) foi uma adição ou correção posterior.
Métodos (Endpoints da API):
• @GetMapping("") public List<Bairro> getBairros():
– Mapeia requisições HTTP GET para /bairros.
– Chama bairroService.allBairros() para obter a lista de todas as
entidades Bairro.
– Retorna a lista de Bairro, que será serializada para JSON.
• @GetMapping("/{id}") public Bairro pegaBairroId(@PathVariable
Integer id):
– Mapeia requisições HTTP GET para /bairros/{id}, onde {id} é o
código do bairro.
– @PathVariable Integer id: Extrai o valor de id da URL.
– Chama bairroService.bairroId(id) para buscar o Bairro
correspondente.
– Retorna a entidade Bairro encontrada.
• @DeleteMapping("/{id}") public String apagaBairroId(@PathVariable
Integer id):
– Mapeia requisições HTTP DELETE para /bairros/{id}.
– Chama bairroService.apagaId(id) para deletar o Bairro.
– Retorna uma mensagem de string confirmando a exclusão.
• @PostMapping("") public String salvaDadosBairro(@RequestBody Bairro
bairro):
– Mapeia requisições HTTP POST para /bairros.
– @RequestBody Bairro bairro: Indica que o corpo da requisição HTTP
(esperado em JSON) deve ser desserializado diretamente em um objeto
da entidade Bairro. Diferentemente do CidadeController que usava
um DTO (CidadeForm), este endpoint espera a própria entidade Bairro
no corpo da requisição para criação.
– Chama bairroService.salvarBairro(bairro) para persistir a nova
entidade Bairro.
– Retorna uma mensagem de string confirmando o cadastro.
• @PutMapping("/{id}") @Transactional public String
atualizaDadosBairro(@PathVariable Integer id, @RequestBody Bairro
bairro):
– Mapeia requisições HTTP PUT para /bairros/{id}.
– @PathVariable Integer id: Extrai o ID do Bairro a ser atualizado da
URL.
– @RequestBody Bairro bairro: Obtém os novos dados do Bairro do
corpo da requisição, também esperando a entidade Bairro diretamente.
– @Transactional: Garante que a operação de atualização seja executada
dentro de uma transação do banco de dados, promovendo a
atomicidade.
– Chama bairroService.editaBairro(bairro, id) para atualizar a
entidade Bairro.
– Retorna uma mensagem de string indicando o sucesso da atualização.
Propósito e Uso:
BairroController serve como a interface RESTful para as operações
relacionadas à entidade Bairro. Ele recebe requisições HTTP, delega a lógica de
processamento para BairroService e retorna respostas apropriadas para o cliente.
Uma diferença notável em relação ao CidadeController é que os métodos de criação
(@PostMapping) e atualização (@PutMapping) deste controlador recebem a entidade
Bairro diretamente no @RequestBody, em vez de um DTO específico como
CidadeForm. Embora isso possa ser mais simples para entidades sem lógica complexa
de entrada ou validação, o uso de DTOs é geralmente preferido para melhor
desacoplamento e controle sobre os dados expostos e recebidos pela API.
6. Configurações
As classes de configuração no Spring Boot são usadas para personalizar o
comportamento da aplicação, definir beans, configurar a segurança, entre outros
aspectos.
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import
org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
Anotações e Interface:
• @Configuration: Esta anotação marca a classe CorsConfig como uma fonte de
definições de beans e configurações para o contêiner Spring. O Spring irá
processar esta classe para aplicar as configurações nela definidas.
• implements WebMvcConfigurer: Ao implementar a interface
WebMvcConfigurer, a classe ganha a capacidade de personalizar a configuração
do Spring MVC. Esta interface fornece métodos de callback que podem ser
sobrescritos para ajustar diversos aspectos do framework MVC, incluindo o
CORS.
Método addCorsMappings:
• @Override public void addCorsMappings(CorsRegistry registry) :
– Este método é sobrescrito da interface WebMvcConfigurer e é o local
onde as regras de CORS são definidas.
– O parâmetro CorsRegistry registry é fornecido pelo Spring MVC e
permite registrar mapeamentos CORS específicos.
– registry.addMapping("/**"):
• Este chamado configura o CORS para ser aplicado a todos os
caminhos (endpoints) da aplicação. O padrão /** é um curinga
que corresponde a qualquer rota na API.
– .allowedOrigins("http://localhost:4200"):
• Especifica quais origens (domínios) têm permissão para fazer
requisições cross-origin para esta API.
• Neste caso, apenas requisições vindas de
http://localhost:4200 são permitidas. Isso é comum em
desenvolvimento, onde o frontend (por exemplo, uma aplicação
Angular) está rodando localmente na porta 4200.
• Para ambientes de produção, este valor seria alterado para o
domínio real do frontend.
– .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") :
• Define quais métodos HTTP são permitidos nas requisições
cross-origin.
• Os métodos listados (GET, POST, PUT, DELETE, OPTIONS) cobrem as
operações CRUD típicas e o método OPTIONS (usado para
requisições de “preflight” em CORS).
– .allowedHeaders("*"):
• Permite que as requisições cross-origin incluam quaisquer
cabeçalhos. O * é um curinga para todos os cabeçalhos.
• Pode-se restringir a cabeçalhos específicos se necessário por
segurança.
– .allowCredentials(true):
• Indica se o navegador deve enviar credenciais (como cookies,
tokens de autorização HTTP) junto com as requisições cross-
origin.
• Quando definido como true, o servidor informa ao navegador
que ele pode processar a requisição mesmo que ela inclua
credenciais. Se definido como false (o padrão se não
especificado), as credenciais não seriam enviadas ou seriam
ignoradas.
• Importante: Se allowCredentials(true) for usado,
allowedOrigins não pode ser *. Uma origem específica deve ser
definida.
Propósito e Uso:
Sem uma configuração CORS adequada, os navegadores modernos bloqueariam as
requisições feitas por um frontend (ex: http://localhost:4200) para um backend
API rodando em uma origem diferente (ex: http://localhost:8080, que é a porta
padrão para aplicações Spring Boot). A classe CorsConfig garante que a API Spring
Boot envie os cabeçalhos CORS corretos nas respostas HTTP, instruindo o navegador a
permitir essas requisições.
Esta configuração é essencial para o desenvolvimento e funcionamento de aplicações
web modernas onde o frontend e o backend são desacoplados e servidos de diferentes
origens.
8. Referências
Os arquivos de código-fonte analisados neste manual são a principal referência
para a API:
• Uf.java
• Sexo.java
• Cidade.java
• Cep.java
• Bairro.java
• UfRepository.java
• SexoRepository.java
• CidadeRepository.java
• CepRepository.java
• BairroRepository.java
• UfService.java
• SexoService.java
• CidadeService.java
• BairroService.java
• CidadeForm.java
• UfController.java
• SexoController.java
• CidadeController.java
• BairroController.java
• CorsConfig.java
EXERCÍCIO
Construa a estrura que ainda falta com base na imagem. Lembre-se que ainda
não conseguiremos fazer o Mapeamento N x N. Teste todos os mapeamentos no
Postman.