CRUD con Spring Boot + JPA + PostgreSQL + Pagination + Validator + Swagger

En este post les mostrare como realizar un CRUD en Spring Boot, usaremos una base de datos relacional de PostgreSQL, la cual correremos en local.

Anteriormente ya habia realizado un CRUD en Spring Boot, pero este es una version mejorada del anterior.

Sobre los temas que abordaremos en este proyecto seran:

  • JPA
  • Pagination o paginacion: nos permite paginar nuestros resultados de base de datos.
  • Validators: validadores en Spring Boot, los permiten validar campos vacios o nulos de una entidad o modelo de datos.
  • PostgreSQL: la base de datos open source mas popular.
  • Gradle: con gradle podremos administrar dependencias y contruccion de nuestros poyectos de manera mas rapida.
  • Java 17
  • Spring Boot 2.5.6
  • Lombok
  • Swagger
Tabla de contenido
  1. Estructura del proyecto
    1. Controller
    2. Model
    3. Repository
    4. Service
    5. Dependencias
    6. Archivo properties
  2. Video-tutorial

Estructura del proyecto

Este sera un proyecto sencillo con las operaciones basicas de CRUD. Veamos la estructura general del proyecto.

estructura proyecto crud yo androide spring boot

Controller

Controlador rest que administra o recibe las peticiones HTTP.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import xyz.yoandroide.crud.model.Student;
import xyz.yoandroide.crud.service.StudentService;

import javax.validation.Valid;
import java.util.Optional;

@RestController
@RequestMapping("/student")
public class StudentController {

    @Autowired
    private StudentService studentService;


    @PostMapping
    public ResponseEntity<Student> saveStudent (@Valid @RequestBody Student student){
        return ResponseEntity.status(HttpStatus.CREATED).body(studentService.saveStudent(student));
    }


    @GetMapping
    public ResponseEntity<Page<Student>> getAllStudent (
            @RequestParam(required = false, defaultValue = "0") Integer page,
            @RequestParam(required = false, defaultValue = "10") Integer size,
            @RequestParam(required = false, defaultValue = "false") Boolean enablePagination
    ){
        return ResponseEntity.ok(studentService.getAllStudent(page, size, enablePagination));
    }

    @DeleteMapping(value = "/{id}")
    public ResponseEntity deleteStudent(@PathVariable ("id") Long id){
        studentService.deleteStudent(id);
        return ResponseEntity.ok(!studentService.existById(id));
    }

    @GetMapping(value = "/{id}")
    public ResponseEntity<Optional<Student>> findStudentById(@PathVariable ("id") Long id){
        return ResponseEntity.status(HttpStatus.OK).body(studentService.findById(id));
    }

    @PutMapping
    public ResponseEntity<Student> editStudent (@Valid @RequestBody Student student){
        return ResponseEntity.status(HttpStatus.CREATED).body(studentService.editStudent(student));
    }


}

Model

Es el pequete donde se guardan los modelos de los objetos u entidades.

import lombok.Data;

import javax.persistence.*;
import javax.validation.constraints.NotBlank;

@Data
@Entity
@Table(name = "Student")
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @NotBlank
    private String name;
    @NotBlank
    private String lastName;
    private Integer age;
}

Repository

Interfaces con la conexion al repositorio de JPA.

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import xyz.yoandroide.crud.model.Student;

@Repository
public interface IStudentRepository extends JpaRepository<Student, Long> {
}

Service

Logica del negocio.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import xyz.yoandroide.crud.model.Student;
import xyz.yoandroide.crud.repository.IStudentRepository;

import java.util.Optional;

@Service
public class StudentService {
    @Autowired
    private IStudentRepository iStudentRepository;


    public Student saveStudent (Student student){
        if (student.getId() == null){
            return iStudentRepository.save(student);
        }
        return null;
    }

    public Page<Student> getAllStudent (Integer page, Integer size, Boolean enablePagination){
        return iStudentRepository.findAll(enablePagination ? PageRequest.of(page, size): Pageable.unpaged());
    }

    public Optional<Student> findById(Long id){
        return iStudentRepository.findById(id);
    }

    public void deleteStudent(Long id){
        iStudentRepository.deleteById(id);
    }

    public Student editStudent (Student student){
        if (student.getId() != null && iStudentRepository.existsById(student.getId())){
            return iStudentRepository.save(student);
        }
        return null;
    }

    public boolean existById(Long id) {
        return iStudentRepository.existsById(id);
    }
}

Dependencias

Este es un proyecto gradle, asi que aqui te dejo las dependencias y configuracion usada.

plugins {
	id 'org.springframework.boot' version '2.5.6'
	id 'io.spring.dependency-management' version '1.0.11.RELEASE'
	id 'java'
}

group = 'xyz.yoandroide'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	runtimeOnly 'org.postgresql:postgresql'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	implementation 'org.springframework.boot:spring-boot-starter-validation:2.5.6'

	compileOnly 'org.projectlombok:lombok:1.18.22'
	annotationProcessor 'org.projectlombok:lombok:1.18.22'

	testCompileOnly 'org.projectlombok:lombok:1.18.22'
	testAnnotationProcessor 'org.projectlombok:lombok:1.18.22'

	// https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-ui
	implementation group: 'org.springdoc', name: 'springdoc-openapi-ui', version: '1.5.12'

}

test {
	useJUnitPlatform()
}

Archivo properties

Esta es la configuracion para acceder a la base de datos. Cabe resaltar que debes tener creada una base de datos en PostgreSQL en local para que el proyecto funcione.

Recomendado:   DECLARAR Y AGREGAR ELEMENTOS A UNA MATRIZ EN JAVA | EJEMPLOS

Este es el arcivo application.properties

spring.jpa.database=POSTGRESQL
spring.datasource.platform=postgres
spring.datasource.url=jdbc:postgresql://localhost:5432/crud
spring.datasource.username=postgres
spring.datasource.password=password
spring.jpa.show-sql=true
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true

Nota: no olvides comentar la linea spring.jpa.generate-ddl=true y spring.jpa.hibernate.ddl-auto=create-drop una vez que se haya construido la base de datos, de lo contrario, se te eliminara la base de datos cada que vuelvas a correr el proecto.

Video-tutorial

Aqui te dejo un video-tutorial explicando paso a paso como fue que se construyo este CRUD. El video esta alojado en el canal de Youtube Yo Androide.

Subir