Como crear un CRUD con Spring Framework 5.2.13 y Bootstrap 4.6 – Parte 3

Demo

En la Parte anterior llamada Como crear un CRUD con Spring Framework 5.2.13 y Bootstrap 4.6 – Parte 2, configuramos la base de datos, creamos una tabla llamda postres en donde almacenaremos los registros, asimismo realizamos la conexión a la base de datos en Spring Framework mediante el archivo application.properties, en donde realizamos otras configuraciones para que el proyecto funcione correctamente y comenzamos creando el modelo del sistema CRUD, basandonos en una estructura MVC (Modelo, Vista y Controlador). En esta 3ra parte vamos a trabajar en el controlador para el sistema CRUD, vamos con ello.

Partes

Antes de continuar con este Post, te invito a leer los siguientes artículos:

Asimismo, te invito a escuchar el Podcast: “Herramientas Online Para el Trabajo en Equipo” y “La Inteligencia Artificial (IA) y el Machine Learning (ML) Siempre Trabajan de la Mano” (Anchor Podcast): 

Spotify: Sound Cloud: Apple Podcasts Anchor Podcasts

Bien ahora continuemos con el Post: Como crear un CRUD con Spring Framework 5.2.13 y Bootstrap 4.6 – Parte 3.

Controlador

Vamos a comenzar creando el controlador, para esto creo un directorio llamado Controller y dentro de el creo un archivo con el nombre Controlador.java en sistemacrud > src > main > java > com > sistemacrud > sistemacrud > Controller > Controlador.java 

/sistemacrud 
  ├── /.mvn
  ├── /src
      ├── /main
          ├── /java  
              ├── /com 
                  ├── /sistemacrud  
                      ├── /sistemacrud  
                          ├── /Controller  // Creo este directorio 
                              ├── Controlador.java // Creo y Abro este Archivo 
                          ├── /Model 
                          ├── SistemacrudApplication.java 
  ├── /target
  ├── .gitignore
  ├── HELP.md
  ├── mvnw
  ├── mvnw.cmd 
  ├── porn.xml

Abro el archivo Controlador.java y e importo algunas librerías y utilidades necesarias para mi controlador.

package com.sistemacrud.sistemacrud.Controller;

import java.util.List;
import java.util.Optional;

import com.sistemacrud.sistemacrud.InterfaceService.InterfacePostreService;
import com.sistemacrud.sistemacrud.Model.Postre;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping; 

import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes; 

import org.springframework.util.StringUtils;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import org.springframework.web.bind.annotation.RequestMethod;

Paso seguido creo una clase publica con el nombre Controladory dentro de ella empiezo llamando a mi IntefacePostreService la cual crearemos mas adelante y una variable UPLOADS con la ruta en donde se guardarán las imagenes de cada registro.

NOTA: He colocado comentarios para explicar que hace cada línea de código.

@Controller
@RequestMapping
public class Controlador {

    @Autowired
    private InterfacePostreService service; 
    
    // Directorio a donde se subirán las imágenes 
    public static String UPLOAD = "src/main/resources/static/uploads/";
    
    // Acá va el resto del código 

}

Vista Principal (Read)

Creo mi método listar() en donde cargaremos una vista con una tabla HTML que contendrá todos los registros desde la base de datos:

// Vista Principal 
@GetMapping("/")
public String listar(Model model) {

  // Seleccionamos el modelo 'Postres' y listamos los registros desde la Base de datos 
  List < Postre > postres = service.listar();
  model.addAttribute("postres", postres);

  return "index";

}

Crear (Create)

Ahora creo un método llamado crear() que llamará a una vista con un formulario HTML para agregar un nuevo registro:

/ Crear Registro 
@GetMapping("/crear")
public String crear(Model model) {

  // Cargamos el modelo 'Postre' y mostramos un formulario para crear un nuevo registro 
  model.addAttribute("postres", new Postre());
  return "crear";

}

El método anterior sirve para mostrar un formulario para crear un registro, pero para el proceso de almacenamiento en la base de datos y la subida de la imágen al servidor voy a crear un método llamado guardar():

// Proceso para Guardar los datos en la Base de datos y subir la imágen al servidor 
@PostMapping("/guardar")
public String guardar(@Validated Postre p, Model model, @RequestParam("amp-img") MultipartFile multipartFile, RedirectAttributes redirAttrs) throws IOException {

  // Obtenemos el nombre la imagen
  String nombreImagen = StringUtils.cleanPath(multipartFile.getOriginalFilename());
  System.out.println(nombreImagen);
  p.setImagen(nombreImagen);

  // Subimos la imagen al servidor 
  byte[] bytes = multipartFile.getBytes();
  Path path = Paths.get(UPLOADS + multipartFile.getOriginalFilename());
  Files.write(path, bytes);

  // Guardamos los datos del formulario en la base de datos 
  this.service.save(p);

  // Enviamos un mensaje a la vista principal 
  redirAttrs.addFlashAttribute("success", "Creado Correctamente !");

  // Luego de realizar las tareas correspondientes, redireccionamos a la vista principal 
  return "redirect:/";

}

Leer (Read)

Voy a crear el método leer() que servirá para leer un item de la base de datos de manera independiente haciendo uso de su id:

// Vista para Leer un Registro     
@GetMapping("/leer/{id}")
@RequestMapping(value = "/leer/{id}", method = RequestMethod.GET)
public String leer(@PathVariable("id") int id, Model model) {

  // Recibimos el 'id' del registro a leer 
  Optional < Postre > postres = this.service.leer(id);

  if (postres.isEmpty()) {
    System.out.println("none");
  } else {
    System.out.println(postres.get().getNombre());
  }

  // Seleccionamos los datos de la tabla 'postres' 
  model.addAttribute("postres", postres);

  // Cargamos la vista para leer un registro 
  return "leer";

}

Actualizar (Update)

Creo el método actualizar() para mostrar un formulario HTML para actualizar los datos de un registro:

// Vista para Actualizar un Registro     
@GetMapping("/actualizar/{id}")
@RequestMapping(value = "/actualizar/{id}", method = RequestMethod.GET)
public String actualizar(@PathVariable("id") int id, Model model) {

  // Recibimos el 'id' del registro que se va Actualizar 
  Optional < Postre > postres = this.service.getId(id);

  // Seleccionamos los datos de la tabla 'postres' 
  model.addAttribute("postres", postres);

  // Luego de realizar las tareas correspondientes, redireccionamos a la vista principal 
  return "actualizar";

}

El método anterior sirve para mostrar un formulario para actualizar un registro, pero para el proceso de actualización en la base de datos y la subida de la imágen al servidor voy a crear un método llamado update():

// Proceso Para Actualizar un Registro 
@PostMapping("/update/{id}")
public String update(@Validated Postre p, @PathVariable("id") int id, Model model, @RequestParam("amp-img") MultipartFile multipartFile, RedirectAttributes redirAttrs) throws IOException, ClassNotFoundException {

  // Obtenemos el nombre la imagen
  String nombreImagen = StringUtils.cleanPath(multipartFile.getOriginalFilename());
  System.out.println(nombreImagen);

  // Verificamos si el usuario cargo una imagen en el formulario 
  if (nombreImagen == null || nombreImagen.length() == 0) {
    // Si el usuario no cargo una imagen en el formulario
    // Realizo una Conexión a la base de datos para obtener la imagen actual del registro
    // Recibimos el 'id' del registro a leer 
    Optional < Postre > postres = this.service.leer(id);

    if (postres.isEmpty()) {
      System.out.println("none");
    } else {
      System.out.println(postres.get().getImagen());

      // Mantenemos el mismo nombre de imagen actual 
      p.setImagen(postres.get().getImagen());
    }

    System.out.println("No se cargo una imagen");

  } else {
    // Si el usuario si cargo una imagen en el formulario
    // Seleccionamos el nombre de la imagen, el cual se guardará en la columna 'amp-img' 
    p.setImagen(nombreImagen);

    // Subimos la imagen al servidor 
    byte[] bytes = multipartFile.getBytes();
    Path path = Paths.get(UPLOADS + multipartFile.getOriginalFilename());
    Files.write(path, bytes);

    System.out.println("Si se cargo una imagen");

  }

  // Guardamos los datos del formulario en la base de datos 
  this.service.save(p);

  // Enviamos un mensaje a la vista principal 
  redirAttrs.addFlashAttribute("success", "Actualizado Correctamente !");

  // Luego de realizar las tareas correspondientes, redireccionamos a la vista principal 
  return "redirect:/";

}

Ahora pasemos al método para eliminar un registro de la base de datos.

Eliminar (Delete)

Por último vamos a necesitar un método para eliminar los registros, creo el método eliminar() para esta tarea:

// Eliminar un Registro 
@GetMapping("/eliminar/{id}")
public String delete(@PathVariable int id, Model model, RedirectAttributes redirAttrs) {

  // Recibimos el 'id' del registro a eliminar  
  this.service.delete(id);

  // Enviamos un mensaje a la vista principal 
  redirAttrs.addFlashAttribute("success", "Eliminado Correctamente !");

  // Luego de realizar las tareas correspondientes, redireccionamos a la vista principal 
  return "redirect:/";

}

A continuación el código completo del archivo Controlador.java:

package com.sistemacrud.sistemacrud.Controller;

import java.util.List;
import java.util.Optional;

import com.sistemacrud.sistemacrud.InterfaceService.InterfacePostreService;
import com.sistemacrud.sistemacrud.Model.Postre;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping; 

import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes; 

import org.springframework.util.StringUtils;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import org.springframework.web.bind.annotation.RequestMethod; 

@Controller
@RequestMapping
public class Controlador {

    @Autowired
    private InterfacePostreService service; 

    //private static String UPLOAD_FOLDER = "F://old_h_xampp//htdocs//xampp//nc//tutoriales//blog//sistemacrud//src//main//resources//static//uploads//";
    
    // Directorio a donde se subirán las imágenes 
    public static String UPLOADS = "src/main/resources/static/uploads/";     

    // Listar Registros  
    @GetMapping("/")
    public String listar(Model model){

        // Seleccionamos el modelo 'Postres' y listamos los registros desde la Base de datos 
        List<Postre> postres = service.listar();
        model.addAttribute("postres", postres); 

        return "index";
        
    }

    // Vista Para Crear un Registro 
    @GetMapping("/crear")
    public String crear(Model model){

        // Cargamos el modelo 'Postre' y mostramos un formulario para crear un nuevo registro 
        model.addAttribute("postres", new Postre());
        return "crear";

    }

    // Proceso para Guardar los datos en la Base de datos y subir la imágen al servidor 
    @PostMapping("/guardar")
    public String guardar(@Validated Postre p, Model model, @RequestParam("amp-img") MultipartFile multipartFile, RedirectAttributes redirAttrs) throws IOException {
         
        // Obtenemos el nombre la imagen
        String nombreImagen = StringUtils.cleanPath(multipartFile.getOriginalFilename());        
        System.out.println(nombreImagen); 
        p.setImagen(nombreImagen); 
                 
        // Subimos la imagen al servidor 
        byte[] bytes = multipartFile.getBytes();
        Path path = Paths.get(UPLOADS + multipartFile.getOriginalFilename());
        Files.write(path, bytes); 

        // Guardamos los datos del formulario en la base de datos 
        this.service.save(p); 

        // Enviamos un mensaje a la vista principal 
        redirAttrs.addFlashAttribute("success", "Creado Correctamente !");

        // Luego de realizar las tareas correspondientes, redireccionamos a la vista principal 
        return "redirect:/";

    } 

    // Vista para Leer un Registro     
    @GetMapping("/leer/{id}")   
    @RequestMapping(value="/leer/{id}", method = RequestMethod.GET) 
    public String leer(@PathVariable("id") int id, Model model){ 

        // Recibimos el 'id' del registro a leer 
        Optional<Postre> postres = this.service.leer(id); 

        if (postres.isEmpty()) {
            System.out.println("none");
        } else {
            System.out.println(postres.get().getNombre());
        }

        // Seleccionamos los datos de la tabla 'postres' 
        model.addAttribute("postres", postres);  

        // Cargamos la vista para leer un registro 
        return "leer";

    } 

    // Vista para Actualizar un Registro     
    @GetMapping("/actualizar/{id}")   
    @RequestMapping(value="/actualizar/{id}", method = RequestMethod.GET) 
    public String actualizar(@PathVariable("id") int id, Model model){ 

        // Recibimos el 'id' del registro que se va Actualizar 
        Optional<Postre> postres = this.service.getId(id);

        // Seleccionamos los datos de la tabla 'postres' 
        model.addAttribute("postres", postres); 

        // Luego de realizar las tareas correspondientes, redireccionamos a la vista principal 
        return "actualizar";

    } 

    // Proceso Para Actualizar un Registro 
    @PostMapping("/update/{id}")
    public String update(@Validated Postre p, @PathVariable("id") int id, Model model, @RequestParam("amp-img") MultipartFile multipartFile, RedirectAttributes redirAttrs) throws IOException, ClassNotFoundException {

        // Obtenemos el nombre la imagen
        String nombreImagen = StringUtils.cleanPath(multipartFile.getOriginalFilename());        
        System.out.println(nombreImagen); 

        // Verificamos si el usuario cargo una imagen en el formulario 
        if(nombreImagen == null || nombreImagen.length() == 0) { 
            // Si el usuario no cargo una imagen en el formulario
            // Realizo una Conexión a la base de datos para obtener la imagen actual del registro
            // Recibimos el 'id' del registro a leer 
            Optional<Postre> postres = this.service.leer(id); 

            if (postres.isEmpty()) {
                System.out.println("none");
            } else {
                System.out.println(postres.get().getImagen());
                
                // Mantenemos el mismo nombre de imagen actual 
                p.setImagen(postres.get().getImagen()); 
            }

            System.out.println("No se cargo una imagen");             

        }
        else {
            // Si el usuario si cargo una imagen en el formulario
            // Seleccionamos el nombre de la imagen, el cual se guardará en la columna 'amp-img' 
            p.setImagen(nombreImagen); 

            // Subimos la imagen al servidor 
            byte[] bytes = multipartFile.getBytes();
            Path path = Paths.get(UPLOADS + multipartFile.getOriginalFilename());
            Files.write(path, bytes);

            System.out.println("Si se cargo una imagen");            
            
        }           

        // Guardamos los datos del formulario en la base de datos 
        this.service.save(p); 

        // Enviamos un mensaje a la vista principal 
        redirAttrs.addFlashAttribute("success", "Actualizado Correctamente !");

        // Luego de realizar las tareas correspondientes, redireccionamos a la vista principal 
        return "redirect:/";

    }

    // Eliminar un Registro 
    @GetMapping("/eliminar/{id}") 
    public String delete(@PathVariable int id, Model model, RedirectAttributes redirAttrs){

        // Recibimos el 'id' del registro a eliminar  
        this.service.delete(id);

        // Enviamos un mensaje a la vista principal 
        redirAttrs.addFlashAttribute("success", "Eliminado Correctamente !");

        // Luego de realizar las tareas correspondientes, redireccionamos a la vista principal 
        return "redirect:/";

    }
    
}

Con esto ya tenemos nuestro controlador con todos los métodos necesarios para que el sistema CRUD funcione sin problemas.

Interface de Servicio

En Java necesitamos crear un interface de servicio que integrará el modelo Postres con ciertos métodos indispensable para el sistema CRUD. Entonces creo un directorio llamado InterfaceService y dentro de el creo el archivo InterfacePostreService.java en sistemacrud > src > main > java > com > sistemacrud > sistemacrud > InterfaceService > InterfacePostreService.java 

/sistemacrud 
  ├── /.mvn
  ├── /src
      ├── /main
          ├── /java  
              ├── /com 
                  ├── /sistemacrud  
                      ├── /sistemacrud  
                          ├── /Controller 
                          ├── /InterfaceService // Creo este directorio 
                              ├── InterfacePostreService.java // Creo y Abro este Archivo 
                          ├── /Model 
                          ├── SistemacrudApplication.java 
  ├── /target
  ├── .gitignore
  ├── HELP.md
  ├── mvnw
  ├── mvnw.cmd 
  ├── porn.xml

Abro el archivo InterfacePostreService.java y dentro de el agrego lo siguiente:

package com.sistemacrud.crudspringboot.InterfaceService;
import java.util.List;
import java.util.Optional;

import com.sistemacrud.crudspringboot.Model.Postre;

public interface InterfacePostreService {
    
    // Métodos 
    public List<Postre> listar();
    public Optional<Postre> getId(int id);
    public int save(Postre p);
    public void delete(int id);

}

Bien, hasta aquí llegamos con esta 3ra parte del tutorial en donde hemos creado nuestro controlador con sus métodos necesarios para realizar las operaciones CRUD (Create, Read, Delete y Update). Asimismo definimos una interface de servicio con ciertos métodos indispensables.

Ten Paciencia, lo que quiero es que conozcas bien como se crea este proyecto y no llenarte el capitulo de mucho contenido porque te puedes marear y no tendrás un óptimo aprendizaje. 

Nota (s)

  • En la siguiente parte vamos a configurar un repositorio y un servicio para nuestro proyecto.
  • Los pasos mencionados en este tutorial pueden cambiar en un futuro, esto no depende de mi, si no de la organización que da soporte a Spring Framework, que suele cambiar el orden y las opciones de su herramienta.
  • No olvides que debemos usar la Tecnología para hacer cosas Buenas por el Mundo.
 

Síguenos en nuestras Redes Sociales para que no te pierdas nuestros próximos contenidos.