Executando verificação de segurança...
4

CRUD Spring Boot + Login

Olá, Tudo bom? Meu nome é Diego, tenho 18 anos e estou indo para o 3°Semestre de SI.
Acompanho o Felipe a um bom tempo e com o lançamento da plataforma não podia ficar sem testar, vou explicar o meu projeto CRUD de Spring, principalmente para quem quer começar a aprender de maneira mais rápida e simplificada, pelos olhos de quem está a pouco tempo também, comparado com um Sênior rs.

Nesse Projeto irei usar o Spring Tool Suite 4 e MySQL.
Projeto completo: GitHub

Criação do Projeto

Crie um novo projeto na opção Spring Starter Project com as especificações que colocarei aqui.
Criação do Projeto
Nas dependências iremos usar além das dependências padrões do Spring, usaremos a dependência do MySQL e também do Lombok (Resumidamente serve para diminuir as linhas de código, como por exemplo ao invés de colocar os getters e setters, é só colocar @Data).
Criação de Dependências

Criando as Entidades

Projeto criado, iremos criar uma classe chamada Usuario no package br.com.back.model, essa classe recebera a anotação @Entity que significa que a classe será automaticamente mapeada à tabela com o mesmo nome (classe Usuario tabela Usuario), e todos os atributos serão respectivas colunas.

Logo após isso definiremos tudo o que um usuario terá, nossa tabela por enquanto terá apenas id, nome, cpf, data de nascimento e senha (mais para frente neste tópico adicionarei a classe cargo). Definiremos nosso id com a anotação @Id que definira que essa é a nossa chave primária, e com a anotação @GeneratedValue será usada para definir como a coluna id será gerada. Nos outros atributos iremos colocar @Column(nullable= false) que significa que o atributo é uma coluna e que ele não pode ser nulo(@Column(unique=true) significa que não pode ser repetido).
Criação da Entidade Usuario

Criando Repositório

Com a classe model criada, o próximo passo é criar a interface repositório que irá nos fornecer métodos como save, findId, findAll e etc, que usaremos no controller.

@Repository
public interface UsuarioRepository extends JpaRepository<Usuario, Long> {}

Criando Controller

O controller basicamente ele é o responsável por controlar as requisições indicando quem deve receber as requisições para quem deve respondê-las.

A anotação @RestController contém as anotações @Controller e @ResponseBody. (Caso tenha interesse em ler tudo completo irei deixar um link de um livro no final do post)
A anotação @RequestMapping("/usuarios") indica que a URL da API desse controller começa com /usuarios, isso significa que se pode acessar usando a URL http://localhost:8080/usuarios.

@RequestMapping(value = "/usuarios")
public class UsuarioController {
	
	@Autowired
	private UsuarioRepository usuarioRepository;
	
	@Autowired
	private UserService userService;
        
        //Métodos aqui 
      }

Explicação rápida em vídeo @Autowired
Não irei falar de Services, mas o resumo do resumo é para deixar nosso controller mais limpo e enxuto, caso queira criar um é só olhar meu GitHub com o projeto completo.

Métodos GET, POST, PUT, DELETE

Método GET localhost:8080/usuarios

    @GetMapping
public List<Usuario> listarUsuario() {
	return usuarioRepository.findAll();
}

O método findAll da interface JpaRepository quando chamado faz um select * from usuarios na tabela Usuario.
A anotação @GetMapping significa a mesma coisa que @RequestMapping(value="/usuarios", method=RequestMethod.GET).

Método GET para achar ID localhost:8080/usuarios/1

@GetMapping(path = {"/{id}"})
public ResponseEntity<Usuario> buscarIdUsuario(@PathVariable long id) {
	return usuarioRepository.findById(id).map(record -> ResponseEntity.ok().body(record))
			.orElseThrow(() -> new ResourceNotFoundException("Não existe este id de usuario :" + id));
}

Para ficar mais rapido a compreensão "A anotação @PathVariable vincula o parâmetro passado pelo método com a variável do path. Note que o parâmetro long id tem o mesmo nome do path declarado em @GetMapping(path = {"/{id}"}).", e o findById ele basicamente faz um select * from usuarios where id = ? que irá retornar HTTP 200 caso ele ache o Id (ResponseEntity.ok()) ou retornara uma exception que no caso ali é ResourceNotFoundException("Não existe este id de usuario :" + id));

Método POST localhost:8080/usuarios

@PostMapping
public Usuario adicionarUsuario(@RequestBody Usuario) {
	return usuarioRepository.save(usuario);
}

Não tem muito o que explicar, ele basicamente chama o método save da interface JpaRepository e cria o registro na tabela.

Método PUT localhost:8080/usuarios/1

@PutMapping({"/{id}"})
    public ResponseEntity<Usuario> atualizarUsuario(Long id, Usuario usuarioDetalhes){
	Usuario = usuarioRepository.findById(id)
			.orElseThrow(() -> new ResourceNotFoundException("Não existe este id de usuario :" + id + " Confirme os dados inseridos!!"));
	
	usuario.setNome(usuarioDetalhes.getNome());
	usuario.setCpf(usuarioDetalhes.getCpf());
	usuario.setSenha(usuarioDetalhes.getSenha());
	usuario.setCargo(usuarioDetalhes.getCargo()); //não foi criado ainda
	usuario.setDataNascimento(usuarioDetalhes.getDataNascimento());
	
	Usuario atualizausuario = usuarioRepository.save(usuario);
	return ResponseEntity.ok(atualizausuario);
}

Aqui no PUT ele é parecido com o método de encontrar um id especifico, pois você terá que informar qual vai ser o ID no caminho da URL. O processo não será muito diferente de quando você estava criando um usuario, caso ele não ache o id que você inseriu na URL ele trará a exception ResourceNotFoundException("Não existe este id de usuario :" + id + " Confirme os dados inseridos!!"));

Metodo DELETE localhost:8080/usuarios/1

@DeleteMapping(path ={"/{id}"})
    public ResponseEntity<Object> deleteUsuarioService(@PathVariable long id) {
	return usuarioRepository.findById(id).map(record -> {
		usuarioRepository.deleteById(id);
		return ResponseEntity.ok().build();
	}).orElseThrow(() -> new ResourceNotFoundException("Não existe este id de usuario :" + id));
}

Ele segue a mesma lógica dos outros, ao inserir o id que deseja deletar na url ele retornara ou HTTP 200 indicando sucesso ou a exception.

configurando acesso do Spring ao MySQL

spring.datasource.url=jdbc:mysql://localhost:3306/crudback
spring.datasource.username=crudback
spring.datasource.password=

spring.jpa.hibernate.ddl-auto=update

Com isso você já terá seu CRUD de Spring pronto para rodar. Deixarei alguns links que vão ser uteis para um aprendizado mais aprofundado, lembrando a ideia desse tópico é ajudar pessoas que estão começando agora a ver Spring, sem tanta "enrolação".

Links para se aprofundar em Spring Boot
https://www.baeldung.com/
https://www.baeldung.com/rest-api-spring-guide

Canais do Youtube em Português:
https://www.youtube.com/@loianegroner/featured Loiane ensina Java, Angular e recentemente está com um projeto explicando Spring com Angular.
https://www.youtube.com/@algaworks AlgaWorks tem foco principalmente em Spring e tem muitos vídeos que podem te ajudar.

#Bonus LOGIN Spring

@PostMapping("/login")
    public Usuario loginUsuarioService(Usuario usuario) throws UserNotFoundException {
	String cpfT = usuario.getCpf();
	String senhaT = usuario.getSenha();
	Usuario usuarioObjeto = null;
	if(cpfT != null && senhaT != null) {
		usuarioObjeto = usuarioRepository.acharIdESenha(cpfT, senhaT);
	}
	if(usuarioObjeto == null) {
		throw new UserNotFoundException();
	}
	return usuarioObjeto;
}

Repository

@Repository
public interface UsuarioRepository extends JpaRepository<Usuario, Long> {

	@Query(nativeQuery = true, value = "select u.* from usuario u where u.cpf = :cpf and u.senha = :senha")
	public Usuario acharIdESenha(@Param("cpf") String cpfT, @Param("senha") String senhaT);

}
Carregando publicação patrocinada...
2

Conteudo legal, uma sugestão que vejo como boa prática atualmente é a injeção dos Beans do spring serem feitas através do construtor da classe. Isso trás uma maior coesão ao código produzido além de facilitar a implementação de testes unitários.

Um exemplo disso seria alterar o código de:

    @RequestMapping(value = "/usuarios")
    public class UsuarioController {

            @Autowired
            private UsuarioRepository usuarioRepository;

            @Autowired
            private UserService userService;

            //Métodos aqui 
          }

Para:

    @RequestMapping(value = "/usuarios")
    public class UsuarioController {

            private UserService userService;
            
            //Injeção de dependência pelo construtor da classe
            public UsuarioController(UserService userService) {
                this.userService = userService;
            }

            //Métodos aqui 
          }
1
1
1

Basicamente você joga lá no controller o metodo loginUsuarioService caso não tenha implementado o service, e copie o metodo acharIdESenha no UsuarioRepository.
Basicamente o que o método esta fazendo é o seguinte, pegando a senha e o cpf que o usuario digitou e procurando no banco de dados se existe ou não, seria a mesma coisa de você escrever "select u.* from usuario u where u.cpf = :cpf and u.senha = :senha" no banco de dados.