Anotações: Spring Boot
Prefácio
Antes de tudo: estudar Spring Boot parece uma bagunça sem fim, e você não está errado. Estudar Spring Boot é uma bagunça!
Porém, mesmo com minhas dificuldades eu dei meu jeito. Trago aqui todas as minhas anotações relacionadas ao framework que me ajudaram na compreensão dos conceitos menos intuitivos que o framework necessita que o programador saiba para construir uma API de qualidade.
Não achei a documentação do framework tão boa para aprender como dizem, então tive que fuçar internet á fora para achar conteúdos que me ajudassem de fato a compreender os conceitos que fundamentam a estrutura de uma aplicação de API RESTful em Spring Boot + Spring Security.
Pode soar meio confuso de começo entender a estrutura correta para se seguir dentro do framework ao construir aplicações web com API’s RESTful - e realmente, é um pouco confuso.
Porquê
Estou desenvolvendo um projeto mobile, e nele preciso montar um backend robusto com muitas regras de negócio, o Java com Spring é a alternativa mais simples para implementação das ideias.
O projeto consiste em um “gerenciador” de imóveis, onde donos de imóveis & pessoas que alugam imóveis são capazes de registrar essas propriedades; o aplicativo deve ser capaz de devolver todos os impostos a serem pagos pelo usuário de acordo com as cláusulas de contrato, juntamente com os reajustes anuais.
Conceitos iniciais
Nesse projeto achei mais pertinente programar tudo usando a arquitetura de Web Services, que pode ser explicada da seguinte forma:

Princípios
O uso dessa arquitetura tem o intuito de encapsular melhor as responsabilidades de cada componente do projeto.
Nessa arquitetura temos um alta coesão e baixo acoplamento; utilizamos bastante de arquitetura em camadas, injeção de dependências e princípios do SOLID - onde são definidos princípios de design para criação de códigos mais manunteníveis, flexíveis e escaláveis.
- Controller: serve como um proxy que comunica o cliente com a aplicação. Ele intercepta a comunicação e identifica se o request é ou não válido antes de passar para as outras camadas da aplicação. Nessa aplicação estamos usando um intermediário para comunicação de dados, chamado de DTO - Data Transfer Object.
- Service: opera como armazenador das regras de negócio da aplicação, aqui operamos e tratamos os dados que o cliente enviou na requisição HTTP.
- Repository: é responsável por comunicar o service com o banco de dados da aplicação, por estar usando o Spring Data JPA todas as operações SQL são feitas por debaixo dos panos.
A visão de arquitetura é importante para definir o caminho á ser trilhado pelo programador, não ter essas visões pode deixar toda a compreensão do framework muito confusa.
Posteriormente vou colocar exemplos de código de cada classe para exemplificação de como um projeto Spring Boot é montado.
Organização
📦 com.example.demo
├─ DemoApplication
├─ model/
│ └─ UserModel
├─ controller/
│ └─ AuthenticationController
├─ service/
│ └─ UserService
├─ repository/
│ └─ UserRepository
└─ config/
└─ SecurityConfig
©generated by Project Tree Generator
Model
No package model colocamos todas as classes de entidades do projeto.
O Spring Boot utiliza de “annotations” para avisar ao framework as responsabilidades das classes que o programador cria. No exemplo abaixo utilizei as anotações de @Entity e @Table na classe em si para avisar que ela é uma entidade, e uma tabela no banco de dados.
@Entity
@Table(name = "tb_users")
public class UserModel {
@Id
@GeneratedValue(strategy = GenerationType.UUID)
private UUID id;
@Column(nullable = false, unique = true)
private String username;
@Column(nullable = false, unique = true)
private String email;
@Column(nullable = false)
private String password;
}
Repository
O repository serve como um comunicador, que leva e trás informações de um ponto A até um ponto B - pense que ele age como um carteiro.
Na aplicação em desenvolvimento estou usando o Spring Data JPA, então não preciso escrever SQL nas transações, só sendo necessário instanciar a interface e os métodos customizados, caso o programa necessite.
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByEmail(String email);
}
Service
Os services atuam como um intermediário dentro do controller e do repository, dentro dele colocamos toda a burocracia da aplicação, ou seja, as regras de negócio.
public class UserService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
public Optional<User> getUserByEmail(String email) {
return userRepository.findByEmail(email);
}
public User createUser(RegisterDto registerDto) {
var user = new User();
user.setUsername(registerDto.username());
user.setEmail(registerDto.email());
user.setPassword(passwordEncoder.encode(registerDto.password()));
return userRepository.save(user);
}
}
Controller
Dentro da controller colocamos todas as operações que vão ocorrer por intermédio de usuário e serviço, servindo como um proxy nessas interações.
@RestController
@RequestMapping("/auth") // anotação para mapeamento de rota
public class AuthenticationController {
private final AuthenticationService authenticationService;
private final UserService userService;
//injeção de dependências
public AuthenticationController(AuthenticationService authenticationService, UserService userService) {
this.authenticationService = authenticationService;
this.userService = userService;
}
@PostMapping("/register")
public ResponseEntity<String> register(@RequestBody RegisterDto user) {
try {
if(userService.getUserByEmail(user.email()).isPresent()) {
return ResponseEntity.status(HttpStatus.CONFLICT).body("Email já cadastrado!");
}
userService.createUser(user);
return ResponseEntity.status(HttpStatus.CREATED).body("Usuário cadastrado com sucesso!");
} catch (Exception e) {
e.printStackTrace();
return ResponseEntity.badRequest().body("Erro ao cadastrar usuário.");
}
}
@PostMapping("/login")
public ResponseEntity<String> login(@RequestBody LoginDto user) {
return null;
}
}
Conclusão
Tendo tudo o que foi falado como base já conseguimos desenvolver uma aplicação em Java Spring Boot; porém ainda temos de pensar na questão da segurança da aplicação. Futuramente vou escrever outro artigo falando sobre segurança em aplicações Spring Boot usando Spring Security de forma mais prática.
Você obviamente deve saber os conceitos teóricos envolvendo todo o código, assim como foi embasado nas explicações acima, isso acaba que por gerar uma compreensão enorme do código que está sendo escrito. Pelo fato do Java ser uma linguagem muito verbosa, pode ser difícil decorar o código e aprender apenas através de exemplos, portanto o melhor dos dois mundos é ter embasamento teórico e prático.
