# data[].attributes.body
Classe BasicSecurityConfig

Esta classe é responsável por habilitar a segurança básica da aplicação e o login na aplicação.

Para habilitar a segurança HTTP no Spring, precisamos extender (herdar) a  Classe WebSecurityConfigurerAdapter para fornecer uma configuração padrão no método configure (HttpSecurity http)

A configuração padrão garante que qualquer requisição enviada para a API seja autenticada com login baseado em formulário ou autenticação via Browser.

Para personalizar a autenticação utilizaremos a sobrecarga dos métodos da Classe WebSecurityConfigurerAdapter
____________________________________

@EnableWebSecurity:
A annotation @EnableWebSecurity: habilita a configuração de segurança padrão do Spring Security na nossa api.
EX.:
@EnableWebSecurity
public class BasicSecurityConfig extends
WebSecurityConfigurerAdapter {
____________________________________

@Autowired
A annotation @Autowired insere uma Injeção de Dependência.

Como iremos utilizar os usuários salvos no nosso Banco de dados, na tabela tb_usuarios, para efetuar o login na api precisamos injetar um objeto da Interface UserDetailsService que será implementada na Classe UserDetailsServiceImpl que fará o acesso ao nosso Banco de dado para recuperar os dados do usuário.

EX.:
@Autowired
private UserDetailsService userDetailsService;
____________________________________

@Override
Sobrescreve (@Override) o primeiro método Configure, que tem a função de criar uma nova instância da Classe AuthenticationManagerBuilder e define que o login será efetuado através dos usuários criados no Banco de dados.
Para recuperar os dados do usuário no Banco de Dados utilizaremos a Interface UserDetailsService.
Outra alternativa de login seria acriação de um usuário em memória, que veremos nas próximas sessões.

O método é do tipo protected por definição da classe.

Lembrete:
1) public: permite acesso a qualquer código externo a classe.
2) protected: permite acesso às classes filhas, mas proíbe a qualquer outro acesso externo.
3) private: proíbe qualquer acesso externo à própria classe, inclusive das classes filhas.

EX.:
@Override
protected void configure(AuthenticationManagerBuilder
auth) throws Exception {
____________________________________

auth
O objeto auth registra e cria uma nova instância do objeto userDetailsService da interface UserDetailsService implementada na Classe UserDetailsServiceImpl para recuperar os dados dos usuários gravados no Banco de dados.

EX.:
auth.userDetailsService(userDetailsService);

auth.inMemoryAuthentication()
.withUser("root")
.password(passwordEncoder().encode("root"))
.authorities("ROLE_USER");
____________________________________

@Bean
A annotation @Bean transforma a instância retornada pelo método como um objeto gerenciado pelo Spring, desta forma, ele pode ser injetado em qualquer classe, a qualquer momento que você precisar sem a necessidade de usar a
annotation @Autowired

O método abaixo é responsável por criptografar a senha do usuário utilizando o método hash Bcrypt.

EX.:
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
____________________________________

@Override
Sobrescreve (@Override) o segundo método Configure que é responsável por criar uma instância da Classe HttpSecurity, que permite configurar a segurança baseada na web para solicitações http específicas (endpoints)

EX.:
@Override
protected void configure(HttpSecurity http) throws
Exception {
____________________________________

antMatchers().permitAll -> Endpoint liberado de autenticação

HttpMethod.OPTIONS -> O parâmetro HttpMethod.OPTIONS permite que o cliente (frontend), possa descobrir quais são as opções de requisição permitidas para um determinado recurso em um servidor. Nesta implementação, está sendo liberada todas as opções das requisições através do método permitAll().

anyRequest().authenticated() -> Todos os demais endpoints
serão autenticados

httpBasic -> Tipo de autenticação http (Basic Security)

Http Sessions: As sessões HTTP são um recurso que permite que os servidores da Web mantenham a identidade do usuário e armazenem dados específicos do usuário durante várias interações (request/response) entre um aplicativo cliente e um aplicativo da Web.

sessionManagement() -> Cria um gerenciador de Sessões

sessionCreationPolicy(SessionCreationPolicy.STATELESS) -> Define como o Spring Secuiryt irá criar (ou não) as sessões

STATELESS -> Nunca será criada uma sessão, ou seja, basta enviar o token através do cabeçalho da requisição que a mesma será processada.

cors -> O compartilhamento de recursos de origem cruzada (CORS) surgiu porquê os navegadores não permitem solicitações feitas por um domínio (endereço) diferente daquele de onde o site foi carregado. Desta forma o Frontend da aplicação, por exemplo, obrigatoriamente teria que estar no mesmo domínio que o Backend. Habilitando o CORS, o Spring desabilita esta regra e permite conexões de outros domínios.

CSRF: O cross-site request forgery (falsificação de solicitação entre sites), é um tipo de ataque no qual comandos não autorizados são transmitidos a partir de um usuário em quem a aplicação web confia.

csrf().disabled() -> Esta opção de proteção é habilitada por padrão no Spring Security, entretanto precisamos desabilitar, caso contrário, todos os endpoints que respondem ao verbo POST não serão executados.

EX.:
http.authorizeRequests()
.antMatchers("/usuarios/logar").permitAll()
.antMatchers("/usuarios/cadastrar").permitAll()
.antMatchers(HttpMethod.OPTIONS).permitAll()
.anyRequest().authenticated()
.and().httpBasic()
.and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().cors()
.and().csrf().disable();
}
}

# data[].attributes.body
Classe UserDetailsImpl

Implementa a interface UserDetails, que descreve o usuário para o Spring Security,ou seja, detalha as caracteríticas do usuário.

Por se tratar de uma implementação de uma interface, a classe deve ter em seu nome o sufixo Impl para indicar que se trata de uma implementação.

As características descritas na interface UserDetails são:

1) Credenciais do usuário (Username e Password)
2) As Autorizações do usuário (o que ele pode e não pode fazer), através da Collection authorities do tipo GrantedAuthority
3) As Restrições (isAccountNonExpired(), isAccountNonLocked(), isCredentialsNonExpired() e isEnabled()) da conta do usuário.

EX.:
public class UserDetailsImpl implements UserDetails {
private static final long serialVersionUID = 1L;

private String userName;
private String password;
private List<GrantedAuthority> authorities;

____________________________________

Método construtor com parâmetros

Observe que este método Construtor recebe um objeto Usuario e recupera os dados necessários através dos respectivos métodos Get.

EX.:
public UserDetailsImpl(Usuario usuario) {
this.userName = usuario.getUsuario();
this.password = usuario.getSenha();
}
____________________________________

Método construtor sem parâmetros

public UserDetailsImpl() { }

____________________________________

@Override

Sobrescreve (@Override) o método que retorna as Autorizações da conta do usuário. Nesta implementação, não há nenhuma autorização negada.

EX.:
@Override
public Collection<? extends GrantedAuthority>
getAuthorities() {
return authorities;
}

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

@Override
public String getUsername() {

return userName;
}
____________________________________

@Override

Sobrescreve (@Override) o método que Indica se a conta do usuário expirou.

EX.:
@Override
public boolean isAccountNonExpired() {
return true;
}
____________________________________

@Override
Sobrescreve (@Override) o método que Indica se o usuário
está bloqueado ou desbloqueado.

EX.:
@Override
public boolean isAccountNonLocked() {
return true;
}

____________________________________

@Override

Sobrescreve (@Override) o método que indica se as credenciais do usuário (senha) expiraram.

EX.:
@Override
public boolean isCredentialsNonExpired() {
return true;
}

____________________________________

@Override

Sobrescreve (@Override) o método que Indica se o usuário
está habilitado ou desabilitado. Se mudar para false nenhum usuário conseguirá logar.

EX.:
@Override
public boolean isEnabled() {
return true;
}
}

# data[].attributes.body
Classe UserDetailsServiceImpl

Implementa a interface UserDetailsService, que é responsável por recuperar os dados do usuário no Banco de Dados pelo usuário e converter em um objeto da Classe
UserDetailsImpl.

Por se tratar de uma implementação de uma interface, a classe deve ter em seu nome o sufixo Impl para indicar que se trata de uma implementação.
____________________________________

@Service

A annotation @Service indica que esta é uma Classe de Serviço, ou seja, implementa regras de negócio da aplicação

EX.:
@Service
public class UserDetailsServiceImpl implements
UserDetailsService {

@Autowired
private UsuarioRepository userRepository;
____________________________________

@Override

Sobrescreve (@Override) o método loadUserByUsername.

A implementação de autenticação chama o método loadUserByUsername(String username), para obter os dados de um usuário com um determinado nome de usuário.
O nome do usuário deve ser único. O usuário retornado por este método é um objeto da classe UserDetailsImpl.

EX.:
@Override
public UserDetails loadUserByUsername(String
userName) throws UsernameNotFoundException {

Para buscar o usuário no Banco de dados, utilizaremos o método findByUsuario, que foi assinado na interface UsuarioRepository

Optional<Usuario> usuario =
userRepository.findByUsuario(userName);

Se o usuário não existir, o método lança uma Exception do tipo UsernameNotFoundException.

EX.:
usuario.orElseThrow(() -> new
UsernameNotFoundException(userName + " not
found."));

Retorna um objeto do tipo UserDetailsImpl criado com os dados recuperados do Banco de dados.

O operador :: faz parte de uma expressão que referencia um método, complementando uma função lambda. Neste exemplo, o operador faz referência ao construtor da Classe UserDetailsImpl.

EX.:
return usuario.map(UserDetailsImpl::new).get();
}
}

# data[].attributes.body
No arquivo pom.xml, btão direito e add status: incluir dependencia da Spring Security e avançar > adicionar > finish, aguardar baixar as dependências. Somente com isso ele ja tranca a app toda. Quando você da PLAY no spring ele já gera um password no console e quando vou acessar a URL no localhost:8080/hello, ele redirecionar automaticamente para usuario e senha.

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

# data[].attributes.body
Codificação do Token

No mvnrepository.com você encontra esta dependência. https://mvnrepository.com/artifact/commons-codec/commons-codec/1.15

O commons code nada mais é do que o Usuario, seguido de dois pontos + a senha. Codifica em 64 bits. Essa sequencia de palavra é seguida de Basic e espaço entre a palavra Basic e o token. Ex: Basic ZW1haWxAZ9hGosluY

IMPORTANTE: o código do pom.xml precisa estar com a identação alinhadissima, senao nao baixa as dependencias.

Os filtros (15 filtros) são responsáveis por trancar a aplicação, e a partir da implemenntação você seleciona quais de fato serão utilizados na app do blog pessoal.

<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>

# data[].attributes.body
https://mvnrepository.com/

# data[].attributes.body
A Classe UsuarioService implementa as regras de negócio do Recurso Usuario.

Regras de negócio são as particularidades das funcionalidades a serem implementadas no objeto, tais como:

1) O Usuário não pode estar duplicado no Banco de dados
2) A senha do Usuario deve ser criptografada

Observe que toda a implementação dos metodos Cadastrar, Atualizar e Logar estão implmentadas na classe de serviço, enquanto a Classe Controller se limitará a checar a resposta da requisição.
____________________________________

@Service

A Anotação @Service indica que esta é uma Classe de Serviço, ou seja, implementa todas regras de negócio do Recurso Usuário.

EX.:
@Service
public class UsuarioService {

@Autowired
private UsuarioRepository usuarioRepository;

____________________________________

Cadastrar Usuário

Checa se o usuário já existe no Banco de Dados através do método findByUsuario, porquê não pode existir 2 usuários com o mesmo email.
Se não existir retorna um Optional vazio.

isPresent() -> Se um valor estiver presente retorna true, caso contrário retorna false.

empty -> Retorna uma instância de Optional vazia.

EX.:
public Optional<Usuario> cadastrarUsuario(Usuario
usuario) {

if (usuarioRepository.findByUsuario(usuario.
getUsuario()).isPresent())
return Optional.empty();

____________________________________

Cadastrar Usuário maior de 18 anos

if  (usuarioRepository.findByUsuario(usuario.getUsuario()).isPresent())
return Optional.empty();

if (calcularIdade(usuario.getDataNascimento()) < 18)
throw new ResponseStatusException(
HttpStatus.BAD_REQUEST, "Usuário é menor de 18 anos", null);

usuario.setSenha(criptografarSenha(usuario.getSenha()));
return   Optional.ofNullable(usuarioRepository.save(usuario));
}

____________________________________
Criptografar Senha.

Se o Usuário não existir no Banco de Dados, a senha será criptografada através do Método criptografarSenha.

EX:
usuario.setSenha(criptografarSenha(usuario.getSenha()));

Assim como na Expressão Lambda, o resultado do método save será retornado dentro de um Optional, com o Usuario persistido no Banco de Dados.

of​ -> Retorna um Optional com o valor fornecido, mas o valor não pode ser nulo.  Se não tiver certeza de que o valor não é nulo use ofNullable.

EX.:
return Optional.of(usuarioRepository.save(usuario));
}
____________________________________

Atualizar Usuário

Checa se o usuário já existe no Banco de Dados através do método findById, porquê não é possíve atualizar 1 usuário inexistente.
Se não existir retorna um Optional vazio.

isPresent() -> Se um valor estiver presente retorna true, caso contrário retorna false.

EX.:
public Optional<Usuario> atualizarUsuario(Usuario usuario) {

if(usuarioRepository.findById(usuario.getId()).isPresent())
{

Cria um Objeto Optional com o resultado do método findById

EX.:
Optional<Usuario> buscaUsuario =      usuarioRepository.findByUsuario(usuario.getUsuario());

Se o Usuário existir no Banco de dados e o Id do Usuário encontrado no Banco for diferente do usuário do Id do Usuário enviado na requisição, a Atualização dos dados do Usuário não pode ser realizada.

EX.:
if ( (buscaUsuario.isPresent()) && (  buscaUsuario.get().getId() != usuario.getId()))
throw new ResponseStatusException(
HttpStatus.BAD_REQUEST, "Usuário já existe!", null);

Se o Usuário existir no Banco de Dados e o Id for o mesmo, a senha será criptografada através do Método criptografarSenha.

EX.:
usuario.setSenha(criptografarSenha(usuario.getSenha()));

Assim como na Expressão Lambda, o resultado do método save será retornado dentro de um Optional, com o Usuario persistido no Banco de Dados ou um Optional vazio, caso aconteça algum erro.

ofNullable​ -> Se um valor estiver presente, retorna um Optional com o valor,  caso contrário, retorna um Optional vazio.

EX.:
return Optional.
ofNullable(usuarioRepository.save(usuario))
}

empty -> Retorna uma instância de Optional vazia, caso o usuário não seja encontrado.

EX.:
return Optional.empty();

}
____________________________________

Atualizar Usuário (maior de 18 anos)

public Optional<Usuario> atualizarUsuario(Usuario usuario) {
if(usuarioRepository.findById(usuario.getId()).isPresent()) {

Optional<Usuario> buscaUsuario = usuarioRepository.findByUsuario(usuario.getUsuario());

if ( (buscaUsuario.isPresent()) && ( buscaUsuario.get().getId() != usuario.getId()))
throw new ResponseStatusException(
HttpStatus.BAD_REQUEST, "Usuário já existe!", null);

if (calcularIdade(usuario.getDataNascimento()) < 18)
throw new ResponseStatusException(
HttpStatus.BAD_REQUEST, "Usuário é menor de 18 anos", null);

usuario.setSenha(criptografarSenha(usuario.getSenha()));
return Optional.ofNullable(usuarioRepository.save(usuario));
}
return Optional.empty();
}

____________________________________

Autenticar Usuario

A principal função do método autenticarUsuario, que é executado no endpoint logar, é gerar o token do usuário codificado em Base64. O login prorpiamente dito é executado pela BasicSecurityConfig em conjunto com as classes UserDetailsService e Userdetails

EX.:
public Optional<UsuarioLogin>  autenticarUsuario(Optional<UsuarioLogin> usuarioLogin) {

Cria um objeto Optional do tipo Usuario para receber o resultado do método findByUsuario().

Observe que o método autenticarUsuario recebe como parâmetro um objeto da Classe UsuarioLogin, ao invés de Usuario.

get() -> Se um valor estiver presente no objeto ele retorna o valor, caso contrário lança uma Exception NoSuchElementException. Então para usar get é preciso ter certeza de que o Optional não está vazio.
O get() funciona como uma chave que abre o Objeto Optional e permite acessar os Métodos do Objeto encpsulado.

EX.:
Optional<Usuario> usuario = usuarioRepository.findByUsuario(usuarioLogin.get().getUsuario());

Checa se o usuario existe

EX.:
if (usuario.isPresent()) {

Checa se a senha enviada, depois de criptografada, é igual a senha gravada no Banco de Dados, através do Método compararSenhas.

O Método Retorna verdadeiro se as senhas forem iguais, e falso caso contrário.

EX.:
if (compararSenhas(usuarioLogin.get().getSenha(),  usuario.get().getSenha())) {

Se as senhas forem iguais, atualiza o objeto usuarioLogin com os dados recuperados do Banco de Dados e insere o Token Gerado através do Método gerarBasicToken.
Desta forma, será possível exibir o nome e a foto do usuário no Frontend.

EX.:
usuarioLogin.get().setId(usuario.get().getId());
usuarioLogin.get().setNome(usuario.get().getNome());
usuarioLogin.get().setFoto(usuario.get().getFoto());
usuarioLogin.get().setToken(gerarBasicToken(usuarioLogin.get().getUsuario(), usuarioLogin.get().getSenha()));
usuarioLogin.get().setSenha(usuario.get().getSenha());

Retorna o objeto usarioLogin atualizado para a classe UsuarioController.
A Classe controladora checará se deu tudo certo nesta operação e retornará o status.

EX.:
return usuarioLogin;

}
}

empty -> Retorna uma instância de Optional vazia, caso o usuário não seja encontrado.

EX.:
return Optional.empty();

}

____________________________________

Método Calcular Idade (maior de 18 anos)

EX.:
private int calcularIdade(LocalDate dataNascimento) {

return Period.between(dataNascimento,   LocalDate.now()).getYears();
}

____________________________________

Método Criptografar Senhas.

Instancia um objeto da Classe BCryptPasswordEncoder para criptografar a senha do usuário.

O método encode retorna a senha criptografada no formato BCrypt. Para mais detalhes, consulte a documentação do BCryptPasswordEncoder.

EX.:
private String criptografarSenha(String senha) {

BCryptPasswordEncoder encoder = new   BCryptPasswordEncoder();
return encoder.encode(senha);
}

____________________________________

Método Comparar Senhas.

Checa se a senha enviada, depois de criptografada, é igual a senha gravada no Banco de Dados.

Instancia um objeto da Classe BCryptPasswordEncoder para comparar a senha do usuário com a senha gravad no Banco de dados.

matches -> Verifca se a senha codificada obtida do banco de dados corresponde à senha enviada depois que ela também for codificada. Retorna verdadeiro se as
senhas coincidem e falso se não coincidem.

EX.:
private boolean compararSenhas(String senhaDigitada, String senhaBanco) {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
return encoder.matches(senhaDigitada, senhaBanco);
}

____________________________________

Método Gerar Basic Token

A primeira linha, monta uma String (token) seguindo o padrão Basic, através  da concatenação de caracteres que será codificada (Não criptografada) no formato Base64, através da Dependência Apache Commons Codec.

Essa String tem o formato padrão: <username>:<password> que não pode ser alterado

Na segunda linha, faremos a codificação em Base 64 da String.

Observe que o vetor tokenBase64 é do tipo Byte para receber o resultado da codificação, porquê durante o processo é necessário trabalhar diretamente com os bits (0 e 1) da String

Base64.encodeBase64 -> aplica o algoritmo de codificação do Código Decimal para Base64, que foi gerado no próximo método. Para mais detalhes, veja Codificação 64 bits na
Documentação.

Charset.forName("US-ASCII") -> Retorna o codigo ASCII (formato Decimal) de cada caractere da String. Para mais detalhes, veja a Tabela ASCII na Documentação.

Na terceira linha, acrescenta a palavra Basic acompanhada de um espaço em branco (Obrigatório), além de converter o vetor de Bytes novamente em String e concatenar tudo em uma única String.

O espaço depois da palavra Basic é obrigatório. Caso não seja inserrido, o Token não será reconhecido.

EX.:
private String gerarBasicToken(String usuario, String senha) {
String token = usuario + ":" + senha;
byte[] tokenBase64 = Base64.encodeBase64(token.getBytes(Charset.forName("US-ASCII")));
return "Basic " + new String(tokenBase64);
}
}

# data[].attributes.body
@Entity
@Table(name = "tb_usuarios")
public class Usuario {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@NotNull(message = "O atributo Nome é Obrigatório!")
private String nome;

@NotNull(message = "O atributo Usuário é Obrigatório!")
@Email(message = "O atributo Usuário deve ser um email válido!")
private String usuario;

A anotação @Size está definida apenas com o valor min
porque ao criptografar a senha a mesma terá uma tamanho
muito maior (em numero de caracteres) do que a senha
não ciptografada.

Exemplo: admin123 -> 8 caracteres
admin123 criptografado -> 60 caracteres

A anotação @NotBlank indica que o atributo não deve ser
nulo e/ou conter espaços em branco.

@NotBlank(message = "O atributo Senha é Obrigatório!")
@Size(min = 8, message = "A Senha deve ter no mínimo 8   caracteres")
private String senha;

private String foto;

A anotação @Column indica o nome que o atributo terá no Banco de dados
A anotação @JsonFormat formata a data para o mesmo padrão do MySQL

@Column(name = "data_nascimento")
@JsonFormat(pattern = "yyyy-MM-dd")
@NotNull(message = "O atributo Data de Nascimento é Obrigatório!")
private LocalDate dataNascimento;

CascadeType.REMOVE -> Ele propaga a operação de remoção de um objeto Pai para um objeto Filho.
Apenas quando remover a Entidade Usuario, também será removida todas as entidades
Postagens associadas. Nas demais operações não haverá a propagação.

CascadeType.ALL -> Ele propaga todas a operações (Inserir, Listar, Atualizar e Apagar) de um objeto Pai para um objeto Filho.

@OneToMany(mappedBy = "usuario", cascade =     CascadeType.REMOVE)
@JsonIgnoreProperties("usuario")
private List<Postagem> postagem;

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getNome() {
return nome;
}

public void setNome(String nome) {
this.nome = nome;
}

public String getUsuario() {
return usuario;
}

public void setUsuario(String usuario) {
this.usuario = usuario;
}

public String getSenha() {
return senha;
}

public void setSenha(String senha) {
this.senha = senha;
}

public String getFoto() {
return foto;
}

public void setFoto(String foto) {
this.foto = foto;
}

public LocalDate getDataNascimento() {
return dataNascimento;
}

public void setDataNascimento(LocalDate
dataNascimento) {
this.dataNascimento = dataNascimento;
}

public List<Postagem> getPostagem() {
return postagem;
}

public void setPostagem(List<Postagem> postagem) {
this.postagem = postagem;
}
}

# data[].attributes.body
A Classe UsuarioLogin não terá nenhuma annotation porque ela não irá gerar uma tabela no Banco de Dados.

A principal função desta classe é servir de apoio ao processo de login na api.

public class UsuarioLogin {

private Long id;

private String nome;

private String usuario;

private String senha;

private String foto;

private LocalDate dataNascimento;

private String token;

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getNome() {
return nome;
}

public void setNome(String nome) {
this.nome = nome;
}

public String getUsuario() {
return usuario;
}

public String getToken() {
return token;
}

public void setToken(String token) {
this.token = token;
}

public void setUsuario(String usuario) {
this.usuario = usuario;
}

public String getSenha() {
return senha;
}

public void setSenha(String senha) {
this.senha = senha;
}

public String getFoto() {
return foto;
}

public void setFoto(String foto) {
this.foto = foto;
}

public LocalDate getDataNascimento() {
return dataNascimento;
}

public void setDataNascimento(LocalDate dataNascimento) {
this.dataNascimento = dataNascimento;
}

public String getToken() {
return token;
}

public void setToken(String token) {
this.token = token;
}
}

# data[].attributes.body
@Repository
public interface UsuarioRepository extends JpaRepository<Usuario, Long> {

Método que busca um usuário pelo seu usuario (email).

select * from tb_usuarios where usuario = "usuario procurado"

public Optional<Usuario> findByUsuario(String usuario);
}

# data[].attributes.body
@RestController
@RequestMapping("/usuarios")
@CrossOrigin(origins = "*", allowedHeaders = "*")
public class UsuarioController {

Faz uma injeção de dependência da classe de Serviço UsuarioService para ter acesso aos métodos do CRUD com regras de negócio

EX.:
@Autowired
private UsuarioService usuarioService;

@Autowired
private UsuarioRepository usuarioRepository;

____________________________________

Buscando todos os Usuario

@GetMapping("/all")
public ResponseEntity <List<Usuario>> getAll(){

return ResponseEntity.ok(usuarioRepository.findAll());
}

____________________________________

Buscando Usuario por ID

@GetMapping("/{id}")
public ResponseEntity<Usuario> getById(@PathVariable Long id) {
return usuarioRepository.findById(id)
.map(resposta -> ResponseEntity.ok(resposta))
.orElse(ResponseEntity.notFound().build());
}

____________________________________

Fazendo o Login

Executa o método autenticarUsuario da classe de serviço para efetuar o login na api. O método da classe Controladora checa se deu certo e exibe as mensagens (Response Status) pertinentes.

Caso o login tenha sido bem sucedido, os dados do usuário e o token  são exibidos.

@PostMapping("/logar")
public ResponseEntity<UsuarioLogin> login(@RequestBody Optional<UsuarioLogin> usuarioLogin) {
return usuarioService.autenticarUsuario(usuarioLogin)
.map(resposta -> ResponseEntity.ok(resposta))
.orElse(ResponseEntity.status(HttpStatus.UNAUTHORIZED).build());
}

____________________________________

Cadastrando Usuário

Executa o método cadastrarUsuario da classe de serviço para criar um novo usuário na api. O método da classe Controladora checa se  deu certo e exibe as mensagens (Response Status) pertinentes.

Caso cadastro tenha sido bem sucedido, os dados do usuário são exibidos.

EX.:
@PostMapping("/cadastrar")
public ResponseEntity<Usuario> postUsuario(@Valid      @RequestBody Usuario usuario) {

return usuarioService.cadastrarUsuario(usuario)
.map(resposta ->    ResponseEntity.status(HttpStatus.CREATED).body(resposta))
.orElse(ResponseEntity.status(HttpStatus.BAD_REQUEST).build());
}

____________________________________

Atualizando Usuário

Executa o método atualizarUsuario da classe de serviço para atualizar os dados de um usuário na api. O método da classe Controladora checa se deu certo e exibe as mensagens (Response Status) pertinentes.

Caso a atualização tenha sido bem sucedida, os dados do usuário atualizados são exibidos.

EX.:
@PutMapping("/atualizar")
public ResponseEntity<Usuario> putUsuario(@Valid        @RequestBody Usuario usuario) {
return usuarioService.atualizarUsuario(usuario)
.map(resposta ->
ResponseEntity.status(HttpStatus.OK).body(resposta))
.orElse(ResponseEntity.status(HttpStatus.NOT_FOUND).build());
}

____________________________________

Deletando Usuario

@DeleteMapping("/{id}")
public ResponseEntity<?> deleteUsuario(@PathVariable Long id) {
return usuarioRepository.findById(id)
.map(resposta->{
usuarioRepository.deleteById(id);
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
})
.orElse(ResponseEntity.notFound().build());
}
}

# data[].attributes.body
@Service
public class PostagemService {

@Autowired
private PostagemRepository postagemRepository;

Método Curtir -> Soma 1 ao atributo curtir

public Optional<Postagem> curtir(Long id) {

if(postagemRepository.existsById(id)) {

Postagem postagem = postagemRepository.findById(id).get();

postagem.setCurtir(postagem.getCurtir() + 1);

return Optional.of(postagemRepository.save(postagem));

}

return Optional.empty();

}
}

# data[].attributes.body
@PutMapping("/curtir/{id}")
public ResponseEntity<Produto> curtirProdutoId (@PathVariable Long id){

return produtoService.curtir(id)
.map(resposta-> ResponseEntity.ok(resposta))
.orElse(ResponseEntity.badRequest().build());

}
}