Curso de Spring Boot

En este capítulo construiremos un proyecto real completo utilizando todo lo aprendido en el curso.

El objetivo es crear una API REST profesional con:

  • Spring Boot
  • PostgreSQL
  • JWT
  • DTOs
  • validación
  • Swagger
  • arquitectura limpia

Este proyecto servirá como plantilla para aplicaciones reales.


20.1 Descripción del proyecto

Crearemos un sistema de gestión de cursos.

Funcionalidades:

1usuarios
2registro
3login
4crear cursos
5listar cursos
6matricular usuarios

Arquitectura:

1Frontend
23API REST
45Spring Boot
67PostgreSQL

20.2 Estructura del proyecto

1com.example.courseapp
2
3config
4controller
5service
6repository
7entity
8dto
9security
10exception

20.3 Entidades

Usuario

1@Entity
2public class User {
3
4    @Id
5    @GeneratedValue
6    private Long id;
7
8    private String username;
9
10    private String email;
11
12    private String password;
13
14}

Curso

1@Entity
2public class Course {
3
4    @Id
5    @GeneratedValue
6    private Long id;
7
8    private String title;
9
10    private String description;
11
12}

Matriculación

1@Entity
2public class Enrollment {
3
4    @Id
5    @GeneratedValue
6    private Long id;
7
8    @ManyToOne
9    private User user;
10
11    @ManyToOne
12    private Course course;
13
14}

20.4 Repositories

1@Repository
2public interface UserRepository extends JpaRepository<User,Long> {
3
4    Optional<User> findByEmail(String email);
5
6}

1@Repository
2public interface CourseRepository extends JpaRepository<Course,Long> {
3
4}

1@Repository
2public interface EnrollmentRepository extends JpaRepository<Enrollment,Long> {
3
4}

20.5 DTOs

Crear usuario

1public class RegisterDTO {
2
3    @NotBlank
4    private String username;
5
6    @Email
7    private String email;
8
9    @Size(min=6)
10    private String password;
11
12}

Crear curso

1public class CourseDTO {
2
3    private Long id;
4
5    private String title;
6
7    private String description;
8
9}

20.6 Servicio de usuarios

1@Service
2public class UserService {
3
4    private final UserRepository repository;
5
6    public UserService(UserRepository repository) {
7        this.repository = repository;
8    }
9
10    public User register(RegisterDTO dto) {
11
12        User user = new User();
13
14        user.setUsername(dto.getUsername());
15        user.setEmail(dto.getEmail());
16        user.setPassword(dto.getPassword());
17
18        return repository.save(user);
19
20    }
21
22}

20.7 Servicio de cursos

1@Service
2public class CourseService {
3
4    private final CourseRepository repository;
5
6    public CourseService(CourseRepository repository) {
7        this.repository = repository;
8    }
9
10    public List<Course> getCourses() {
11        return repository.findAll();
12    }
13
14}

20.8 Controller de usuarios

1@RestController
2@RequestMapping("/users")
3public class UserController {
4
5    private final UserService service;
6
7    public UserController(UserService service) {
8        this.service = service;
9    }
10
11    @PostMapping("/register")
12    public User register(@Valid @RequestBody RegisterDTO dto) {
13
14        return service.register(dto);
15
16    }
17
18}

20.9 Controller de cursos

1@RestController
2@RequestMapping("/courses")
3public class CourseController {
4
5    private final CourseService service;
6
7    public CourseController(CourseService service) {
8        this.service = service;
9    }
10
11    @GetMapping
12    public List<Course> getCourses() {
13
14        return service.getCourses();
15
16    }
17
18}

20.10 Matricular usuario en curso

1@PostMapping("/enroll")
2public Enrollment enroll(@RequestParam Long userId,
3                         @RequestParam Long courseId) {
4
5    User user = userRepository.findById(userId).orElseThrow();
6    Course course = courseRepository.findById(courseId).orElseThrow();
7
8    Enrollment enrollment = new Enrollment();
9
10    enrollment.setUser(user);
11    enrollment.setCourse(course);
12
13    return enrollmentRepository.save(enrollment);
14
15}

20.11 Seguridad JWT

Endpoint login.

1@PostMapping("/login")
2public String login(@RequestBody LoginDTO dto) {
3
4    User user = repository.findByEmail(dto.getEmail())
5            .orElseThrow();
6
7    if(user.getPassword().equals(dto.getPassword())) {
8
9        return jwtService.generateToken(user.getEmail());
10
11    }
12
13    throw new RuntimeException("Credenciales inválidas");
14
15}

20.12 Documentación Swagger

Añadimos dependencia:

1<dependency>
2 <groupId>org.springdoc</groupId>
3 <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
4 <version>2.5.0</version>
5</dependency>

Acceso:

1http://localhost:8080/swagger-ui.html

20.13 Base de datos

Configuración:

1spring.datasource.url=jdbc:postgresql://localhost:5432/courseapp
2spring.datasource.username=postgres
3spring.datasource.password=1234
4
5spring.jpa.hibernate.ddl-auto=update

20.14 Flujo completo

Registro:

1POST /users/register

Login:

1POST /users/login

Listar cursos:

1GET /courses

Matricular usuario:

1POST /courses/enroll

20.15 Arquitectura final

1Controller
23Service
45Repository
67Database

Con componentes adicionales:

1DTO
2Security
3Validation
4ExceptionHandler
5Swagger