# data[].attributes.body
https://mvnrepository.com/search?q=Spring+web

# data[].attributes.body
@Entity indica que a classe é uma entidade, ou seja,  ele será utilizada para gerar uma tabela no Banco de Dados.

@Table indica o nome da tabela no Banco de dados. Caso ela não seja declarada, o Banco criará a tabela com o mesmo nome da classe.

@ID inidica que o atributo é a chave primária da tabela.

@GeneratedValue indica que a chave primária será gerada automaticamente pelo Banco de Dados.
O parâmetro strategy indica como a Chave Primária será gerada.
A opção GenerationType.IDENTITY indica que será uma sequência numérica iniciando em 1 e será responsabilidade do Banco de dados gerar esta sequência, ou seja, a propriedade auto_increment do SQL.

Não confundir o auto-incremento do Banco de Dados que inicia em 1 com o indice de um Array (Vetor ou Matriz) que inicia em 0.

@NotBlank indica que um atributo não pode ser nulo e também não pode ser deixado em branco (vazio).
O parâmetro message insere uma mensagem que será exibida caso o atributo seja nulo.

@Size tem a função de definir o tamanho minimo e máximo de caracteres de um atributo String. Não é obrigatório definir os 2 parâmetros, você pode definir apenas um deles de acordo com as necessidades do seu projeto.

@JsonFormat(shape = JsonFormat.Shape.STRING) é utilizada  para formatar o valor do preço do produto como uma String. Desta forma, conseguiremos visualizar a parte decimal do preço mesmo sendo 00.

@JsonIgnoreProperties é utilizado para impedir que o informado seja negativo.

@UpdateTimestamp Indica se o atributo receberá um Timestamp (Data e hora do sistema) e sempre que a Postagem for atualizada o atributo também será atualizado.

***OneToMeny****ManyToOne***

@OneToMany(mappedBy = "tema", cascade = CascadeType.ALL): indica,  que a Classe Tema terá um relacionamento do tipo One To Many (Um para Muitos) com a Classe  Postagem
mppedBy = "tema": Indica qual Objeto será utilizado como "chave estrangeira" no relacionamento, em nosso exemplo será o objeto tema inserido na Classe Postagem
cascade = CascadeType.ALL: Indica que toda e qualquer mudança efetuada num objeto da Classe Tema se propagará para todos os respectivos objetos associados.  Exemplo: Se eu apagar um tema, todas as postagens associadas ao tema apaga

@ManyToOne: Anotação que indica que a Classe Postagem terá um relacionamento  do tipo Many To One (Muitos para Um) com a Classe Tema

@JsonIgnoreProperties("postagem"): Anotação que desabilita a recursividade  infinita durante a exibição dos dados no formato JSON (Desserialização).  private Tema tema;: Objeto do tipo Tema que atuará como a "chave estrangeira" da Classe  Postagem na relação com a Classe Tema, além de exibir o tema da postagem

GetterAndSetter

# data[].attributes.body
spring.jpa.hibernate.ddl-auto=update
spring.jpa.database=mysql
spring.datasource.url=jdbc:mysql://localhost/db_blogpessoal?createDatabaseIfNotExist=true&serverTimezone=America/Sao_Paulo&useSSl=false
spring.datasource.username=root
spring.datasource.password=root

spring.jpa.show-sql=true

spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL8Dialect

spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=Brazil/East

# data[].attributes.body
@Repository: indica que a Interface é do tipo repositório, ou seja, é responsável pela comunicação com o Banco de dados através dos métodos padrão e das Method Queries (Métodos Personalizados), que são as consultas personalizadas  criadas através de palavras chave que representam as instruções da linguagem SQL.

Observe que na próxima linha, na declaração da Interface foi adicionada uma Herança através da palavra reservada extends com a Interface JpaRepository, que recebe  2 parâmetros:

1) A Classe Postagem, que é a Entidade (Tabela) que será mapeada em nosso Banco de dados (Lembre-se que a Classe Postagem foi quem gerou a nossa tabela tb_postagens)

2) O Long representa a nossa Chave Primária (Primary Key), que é o atributo que recebeu a anotação @Id na nossa Classe Postagem (o atributo também se chama id em nossa Classe Postagem).

Estes 2 parâmetros são do tipo Java Generics (podem receber qualquer tipo de Objeto <T, T>).

Dentro contexto do JPA são o mínimo necessário para executar os Métodos padrão da

Interface JpaRepository, que serão implementados na próxima etapa na Classe PostagemController.

Alguns métodos básicos já ficam automaticamente disponíveis no Recurso Postagem a partir do momento que a Interface PostagemRepository herda a Interface JpaRepository.

public interface ProdutoRepository extends JpaRepository<Produto, Long>{

public List <Postagem> findAllByTituloContainingIgnoreCase(String titulo);

select * from tb_postagens where titulo like "%%"
select -> find
* -> All
where -> By
like -> Containing
IgnoreCase - ignora o maiusculo e minusculo

# data[].attributes.body
public List<Produto>findAllByNomeContainingIgnoreCase(String nome);

find -> encontre
All -> tudo
By -> por
(Atributo Nome)
Containing -> contendo
IgnoreCase -> ignorar caso(ignora letras  maiúsculo

public List<Produto>findAllByPrecoGreaterThanOrderByPreco(BigDecimal preco);

find -> encontre
All -> tudo
By -> por
(Atributo Preco)
Greater -> melhor
Then -> que
Order -> ordem
By -> por
(Atributo Preco)

public List<Produto>findAllByPrecoLessThanOrderByPrecoDesc(BigDecimal preco);

find -> encontre
All -> tudo
By -> por
(Atributo Preco)
Less -> menor
Then -> que
Order -> ordem
By -> por
(Atributo Preco)
Desc -> decrescente

public List <Produto> findAllByNomeContainingIgnoreCaseAndLaboratorioContainingIgnoreCase (String nome, String laboratorio);

find -> encontre
All -> tudo
By -> por
(Atributo Nome)
Containing -> contendo
IgnoreCase -> ignorar caso(ignora letras  maiúsculo)
And -> e
(Atributo Categoria)
Containing -> contendo
IgnoreCase -> ignorar caso(ignora letras  maiúsculo)

public List <Produto> ContainingIgnoreCaseOrLaboratorioContainingIgnoreCase(String nome, String laboratorio);

find -> encontre
All -> tudo
By -> por
(Atributo Nome)
Containing -> contendo
IgnoreCase -> ignorar caso(ignora letras  maiúsculo)
And -> e
(Atributo Categoria)
Containing -> contendo
IgnoreCase -> ignorar caso(ignora letras  maiúsculo)

public List <Produto> findAllByPrecoBetweenOrderByPreco(BigDecimal preco1, BigDecimal preco2);

find -> encontre
All -> tudo
By -> por
(Atributo Preco)
Between -> entre
Order -> ordem
By -> por
(Atributo Preco)

@Query -> Permite executar uma consulta no Spring utilizando código SQL nativo

inicio -> Parâmetro da consulta SQL (Valor inicial)

final -> Parâmetro da consulta SQL (Valor final)

nativeQuery = true -> Indica que o código da consulta é o SQL nativo que é compatível com qualquer SGBD Relacional

@Param("inicio") -> Mapeia o parâmetro :inicio da consulta na variável BigDecimal inicio  que é o primeiro parâmetro do método buscarProdutosEntre

@Param("fim") -> Mapeia o parâmetro :fim da consulta na variável BigDecimal fim  que é o segundo parâmetro do método buscarProdutosEntre

Method Query equivalente: public List<Produto> findByPrecoBetween(BigDecimal inicio, BigDecimal fim);

Ex:@Query(value = "select * from tb_produtos where preco between :inicio and :fim", nativeQuery = true)
public List <Produto> buscarProdutosEntre(@Param("inicio") BigDecimal inicio, @Param("fim") BigDecimal fim);

# data[].attributes.body
@RestController: indica que a Classe é uma RestController, ou seja, é responsável por responder todas as requisições http enviadas para um endpoint (endereço) definido na anotação @RequestMapping.
___________________________________

@RequestMapping("/postagens"): indica o endpoint (endereço) que a controladora responderá as requisições.
___________________________________

@CrossOrigin("*"): indica que a classe controladora permitirá o recebimento de requisições realizadas de fora do domínio (localhost, em nosso caso) ao qual ela pertence. Essa anotação é essencial para que o front-end (Angular ou React), tenha acesso à nossa API (O termo técnico é consumir a API)

Para as versões mais recentes do Angular e do React, é necessário configurar esta anotação com os seguintes parâmetros:
@CrossOrigin(origins = "*", allowedHeaders = "*")

Esta anotação, além de liberar todas as origens (origins), libera também todos os parâmetros do cabeçalho das requisições (allowedHeaders).
Em produção, o *(asterisco) é substituido pelo endereço de domínio (exemplo: www.meudominio.com) do Frontend.
___________________________________
@Autowired é uma Injeção de Dependência. Consiste  na  maneira,  ou  seja,  na  implementação utilizada pelo  Spring  Framework  de  aplicar  a  Inversão  de  Controle  quando  for necessário.

A Injeção de Dependência define quais classes serão instanciadas e em quais lugares serão injetadas quando houver necessidade.

Em nosso exemplo a classe controladora cria um ponto de injeção da interface PostagemRepository, e quando houver a necessidade o Spring Framework irá criar uma instância (objeto) desta interface permitindo o uso de todos os métodos (padrão ou personalizados da Interface PostagemRepository).
___________________________________
@GetMapping: indica que o método abaixo responderá todas as requisições do tipo GET que forem enviadas no endpoint /postagens

O Método getAll() será do tipo ResponseEntity porque ele responderá a requisição (Request), com uma HTTP Response (Resposta http).

<List<Postagem>>: O Método além de retornar um objeto da Classe ResponseEntity (OK 🡪 200), no parâmetro body (Corpo da Resposta), será retornado um Objeto da Classe List (Collection), contendo todos os Objetos da Classe Postagem persistidos no Banco de dados, na tabela tb_postagens. Observe que nesta linha foi utilizado um recurso chamado Java Generics, que além de simplificar o retorno do Objeto da Classe List, dispensa o uso do casting(mudança de tipos).
Observe que na definição do Método foram utilizados os símbolos <T>, onde T é o Tipo do Objeto que será retornado no Corpo da Resposta.

return ResponseEntity.ok(postagemRepository.findAll());: Executa o método findAll() (Método padrão da Interface JpaRepository), que retornará todos os Objetos da Classe Postagem persistidos no Banco de dados
(<List<Postagem>>). Como a List sempre será gerada (vazia ou não), o Método sempre retornará o Status 200 🡪 OK.
O Mátodo findAll() é equivalente a consulta SQL: SELECT * FROM tb_postagens;
___________________________________
Listar postagem por id
Utilizando Expressões Lambda
As expressões Lambda representam uma função anônima, ou seja, uma função lambda é uma função sem declaração,
isto é, não é necessário colocar um nome, um tipo de retorno e o modificador de acesso. A ideia é que o método seja declarado no mesmo lugar em que será usado. As expressões lambda em Java tem a sintaxe definida como: (argumento) -> (corpo). Elas são semelhantes as Arrow Functions do Javascript/Typescript.

@GetMapping("/{id}"): Anotação que indica que o método abaixo responderá todas as requisições do tipo GET que forem enviadas no endpoint /postagens/id, onde id é uma variável de caminho (path variable), que receberá em nosso o exemplo o Id que você deseja encontrar

O Método getById(@PathVariable Long id) será do tipo ResponseEntity porque ele responderá a requisição (Request), com uma HTTP Response (Resposta http), em nosso exemplo a Response Status 200 => OK, caso a Postagem seja encontrada. Caso não seja encontrada, a resposta será Not Found => 404 (Não Encontrada).

@PathVariable Long id: Anotação que insere a variável de caminho (path variable) id, que foi informada no endereço da requisição, e insere no parâmetro id do método getById.
Exemplo: http://localhost:8080/postagens/1

O parâmetro id do método receberá o valor 1 (Id que será procurado na tabela postagens através do método findById(id))

<Postagem>: Como o Método listará apenas 1 registro da nossa tabela, o método retornará dentro da resposta um objeto do tipo Postagem, que são os dados encontrados na tabela.

return postagemRepository.findById(id): Retorna a execução do método findById(id)

Lambda
.map(resposta -> ResponseEntity.ok(resposta)): Se a postagem existir, a função map (tipo Optional), aplica o valor do objeto resposta (objeto do tipo Postagem com o retorno do método findById(id) no método:
ResponseEntity.ok(resposta); e retorna o status OK => 200

.orElse(ResponseEntity.notFound().build()); : Se a postagem não for encontrada, retorna o status Not Found => 404. (build)

Optional (map): É um contêiner para um valor que pode estar ausente. Em nosso contexto, tem como principal função evitar o erro do tipo NullPointerException (Objeto nulo), caso a Postagem procurada pelo método findById(id)não seja encontrada na Model Postagens.
___________________________________
Consultar postagens por titulo
@GetMapping("/titulo/{titulo}"): Anotação que indica que o método abaixo responderá todas as requisições do tipo GET que forem enviadas no endpoint /postagens/titulo/titulo, onde a segunda palavra titulo é uma variável de caminho (path variable), que receberá em nosso exemplo a String (palavra, sílaba e etc), que você deseja encontrar na tabela tb_postagens

O Método getByTitulo(@PathVariable Long titulo) será do tipo ResponseEntity porque ele responderá a requisição (Request), com uma HTTP Response (Resposta http), neste caso Response Status 200 => OK, independente da Postagem ser ou não encontrada. O método retornará uma lista de Postagens vazia, caso nenhuma postagem que atenda ao critério de busca seja encontrada.
@PathVariable String titulo: Anotação que insere o valor da variável de caminho titulo, informada no endereço da requisição e insere no parâmetro titulo do método getByTitulo.
Exemplo:http://localhost:8080/postagens/titulo/primeira

O parâmetro titulo do método receberá a String "primeira" (palavra que será procurada na tabela postagens no campo titulo via findAllByTituloContainingIgnoreCase(titulo))

<List<Postagem>>: Como o Método listará todos os registros da nossa tabela, que possuam a string enviada pelo path, o método retornará dentro da resposta um objeto do tipo List (Collection) preenchido com
objetos do tipo Postagem, que são os dados da tabela.

return ResponseEntity.ok(postagemRepository.findAllByTituloContainingIgnoreCase(titulo));: Executa o método findAllByTituloContainingIgnoreCase(titulo) e retorna o status OK => 200

Como o Método sempre irá criar a List independente ter ou não valores na tabela, ele sempre retornará 200.
___________________________________
Criar nova postagem
@PostMapping: Anotação que indica que o método abaixo responderá todas as requisições do tipo POST que forem enviadas no endpoint /postagens

O Método ResponseEntity<Postagem> postPostagem (@RequestBody Postagem postagem) será do tipo  ResponseEntity porque ele responderá a requisição (Request), com uma HTTP Response (Resposta http),  neste caso Response Status 201 => CREATED, caso a Postagem seja inserida na tabela. Caso não seja inserida na tabela, a resposta será Internal Server Error => 500

@Valid: Valida o Objeto Postagem enviado no corpo da requisição (Request Body), conforme as regras definidas na Model Postagem. Caso algum atributo não seja validado, o método retornará um status 400 => Bad Request.

@RequestBody Postagem postagem: Anntotation (anotação) que insere o objeto do tipo Postagem enviado no corpo da requisição (Request Body) e insere no parâmetro postagem do método postPostagem

<Postagem>: O Método retornará dentro da resposta um objeto do tipo Postagem, que são os dados da tabela.

return ResponseEntity.status(HttpStatus.CREATED).body(postagemRepository.save(postagem));: Executa o método save(postagem) e retorna o status CREATED = 201 se o objeto Postagem foi inserido na tabela postagens no Banco de dados.

Ao fazer o envio dos dados via Postman ou front-end, não é necessário passar o Id e a Data
___________________________________
Editar uma postagem
@PutMapping: Annotation (Anotação), que indica que o método abaixo responderá todas as requisições do tipo PUT que forem enviadas no endpoint /postagens

O Método ResponseEntity<Postagem> putPostagem (@RequestBody Postagem postagem) será do tipo
ResponseEntity porque ele responderá a requisição (Request), com uma HTTP Response (Resposta http),
neste caso Response Status 200 => OK, caso a Postagem seja atualizada na tabela. Caso não seja atualizada na tabela, a resposta será Internal Server Error => 500

@Valid: Valida o Objeto Postagem enviado no corpo da requisição (Request Body), conforme as regras definidas na Model Postagem. Caso algum atributo não seja validado, o método retornará um status 400 => Bad Request.

@RequestBody Postagem postagem: Anntotation (anotação) que insere o objeto do tipo Postagem enviado
no corpo da requisição (Request Body) e insere no parâmetro postagem do método postPostagem

<Postagem>: O Método retornará dentro da resposta um objeto do tipo Postagem, que são os dados da tabela.

return postagemRepository.findById(postagem.getId()): Retorna a execução do método findById(postagem.getId()).
Observe que o Id da postagem é obtido através do método getId() que retorna o Id da Postagem enviada no Corpo da requisição (Request Body)

.map(resposta -> ResponseEntity.ok().body(postagemRepository.save(postagem))): Se a postagem existir, a função map (tipo Optional), executa o método save(postagem) e retorna o status OK = 200 se o objeto Postagem foi atualizado na tabela postagens no Banco de dados.

.orElse(ResponseEntity.notFound().build());: Se a postagem não for encontrada pelo método findById(postagem.getId()),
retorna o status Not Found = 404

Optional (map): É um contêiner para um valor que pode estar ausente. Em nosso contexto, tem como principal função evitar o erro do tipo NullPointerException (Objeto nulo), caso a Postagem procurada pelo método findById(id)não seja encontrada na Model Postagens.

Ao fazer o envio dos dados via Postman ou front-end é necessário passar o Id para identificar qual a
Postagem será atualizada.
___________________________________
Deletar uma postagem
@DeleteMapping("/{id}"): Annotation (Anotação), que indica que o método abaixo responderá todas as requisições do tipo DELETE que forem enviadas no endpoint /postagens/id

O Método deletePostagem(@PathVariable Long id)  será do tipo ResponseEntity porque ele responderá a requisição (Request), com uma HTTP Response (Resposta http), neste caso Response Status 204 => NO_CONTENT caso a stagem seja encontrada e excluída da tabela. Caso não seja encontrada, a resposta será Not Found => 404

A Annotation @PathVariable Long id: insere a variável de path (caminho ou url do endpoint),  passada no endereço da requisição, e insere no parâmetro id do método deletePostagem
Exemplo:http://localhost:8080/postagens/1
o parâmetro id do método receberá o valor 1 (Id que será procurado na tabela postagens e deletado via deleteById())

<?>: O ?, no contexto de genéricos, basicamente serve como um coringa, ou seja, ele representa "qualquer tipo".
Sua função é permitir o uso do polimorfismo junto com genéricos, logo você não está definindo um tipo específico
para retorno. Como Delete não retorna nada, o tipo ResponseEntity<Void> é o tipo genérico que será retornado.
return postagemRepository.findById(id): Retorna a execução do método findById(id). Observe que o Id da postagem foi passado via path (caminho ou url do endpoint)

.map(resposta -> {
postagemRepository.deleteById(id);
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
})

O Trecho de código acima será executado se a postagem for encontrada pelo método findById. Primeiro, o método
deleteById(id) irá excluir a postagem da tabela postagens. Na sequência, será retornado o status NO_CONTENT = 204
indicando que a postagem foi excluída e não existe mais.

.orElse(ResponseEntity.notFound().build()): Caso a Postagem não seja encontrada pelo método findById, a resposta será Not Found => 404

# data[].attributes.body
Ok -> 200
CREATED -> 201
NO_CONTENT -> 204

Bad Request ->400
Not Found -> 404

Server Error => 500

# data[].attributes.body
Como e onde aplicar o Optional dentro do STS?

https://drive.google.com/file/d/15vk9Ctp2FHcYKpU4ImaKRGDO_bxaJVdu/view?usp=sharing

# data[].attributes.body
Fornece todas as Bibliotecas necessárias para trabalhar com o protocolo http.

# data[].attributes.body
Permite a atualização do projeto em tempo real durante o processo de Desenvolvimento da aplicação.

# data[].attributes.body
Fornece um conjunto de anotações que permite validar os atributos das Classes da Camada Model.

# data[].attributes.body
Java Persistence API é uma biblioteca que armazena e recupera objetos que são armazenados em bancos de dados.

# data[].attributes.body
Responsável pela conexão entre nossa API e o Banco de Dados MySQL.

# data[].attributes.body
Valida se o valor da propriedade anotada não é nulo.

# data[].attributes.body
Valida se o valor da propriedade anotada é verdadeiro.

# data[].attributes.body
Valida se o valor da propriedade anotada tem um tamanho entre os atributos min e max; pode ser aplicado a propriedades String, Collection, Map e array.

# data[].attributes.body
Valida se a propriedade anotada tem um valor maior ou igual ao valor mínimo atribuído ao atributo

# data[].attributes.body
Valida se a propriedade anotada tem um valor menor ou igual ao valor máximo atribuído ao atributo.

# data[].attributes.body
Valida se a propriedade anotada é um email

# data[].attributes.body
Valida se a propriedade não é nula ou vazia; pode ser aplicado a valores de String, Collection, Map ou Array.

# data[].attributes.body
Pode ser aplicado apenas a valores de texto e valida se a propriedade não é nula ou espaço em branco.

# data[].attributes.body
Aplique a valores numéricos e valide se eles são estritamente positivos

# data[].attributes.body
Aplique a valores numéricos e valide se eles são estritamente positivos ou positivos incluindo o Zero.

# data[].attributes.body
Aplique a valores numéricos e valide se eles são estritamente negativos

# data[].attributes.body
Aplique a valores numéricos e valide se eles são estritamente negativos ou negativos incluindo o Zero.

# data[].attributes.body
Valida se um valor de data está no passado

# data[].attributes.body
Valida se um valor de data está no passado ou no presente.

# data[].attributes.body
Valida se um valor de data está no futuro

# data[].attributes.body
Valida se um valor de data está no futuro ou no presente.

# data[].attributes.body
Valida CPF

# data[].attributes.body
Valida CNPJ

# data[].attributes.body
Valida o ISBN de um Livro

# data[].attributes.body
Valida o Título de Eleitor

# data[].attributes.body
Valida o numero do Cartão de Crédito

# data[].attributes.body
Salva ou Atualiza um objeto no Banco de Dados.

# data[].attributes.headline
findById Retorna (exibe) um registro na tabela pelo id

# data[].attributes.subject
findById Retorna (exibe) um registro na tabela pelo id

# data[].attributes.body
Retorna (exibe) um registro na tabela pelo id

# data[].attributes.body
Checa se um id existe na tabela.

# data[].attributes.body
Retorna (exibe) todos os registros da tabela

# data[].attributes.body
Localiza um registro na tabela pelo id e deleta.

# data[].attributes.body
Deleta todos os registros da tabela