Controlador
package com.trifulcas.SpringBootVistas.controller; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; 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 com.trifulcas.SpringBootVistas.model.Autor; import com.trifulcas.SpringBootVistas.repository.AutorRepository; // La anotación nos indica que es un controlador normal, que requerirá una vista @Controller // Nos indica la ruta de entrada general a este controlador @RequestMapping("/autor") public class AutorController { // Necesitamos acceder a los datos por lo tanto creamos el repositorio // el autowired nos hace inyección de dependencia automática @Autowired AutorRepository autorRepository; // Aquí especificamos que accedemos vía get @GetMapping("") // Pongo el parámetro Model que nos permita pasar datos a la vista public String getAutores(Model model) { try { // Obtengo los datos como en la API rest List<Autor> autores = autorRepository.findAll(); // Paso la información a la vista vía model // La vista tendrá una variable 'autores' con la lista de autores model.addAttribute("autores", autores); // Le digo que me cargue la vista 'autores' la buscará en templates return "autores"; } catch (Exception ex) { System.out.println(ex.getMessage()); return "error"; } } // Mapeo que me pasen un parámetro id @GetMapping("/{id}") // Tengo el parámetro id que me pasan y el model para pasar datos a la vista public String getAutor(Model model, @PathVariable Integer id) { try { // Recupero el autor Autor autor = autorRepository.findById(id).orElse(null); if (autor != null) { // Lo paso a la vista model.addAttribute("autor", autor); // Devuelvo la vista return "autor"; } else { // Me he creado una vista para mostrar un error return "error"; } } catch (Exception ex) { System.out.println(ex.getMessage()); return "error"; } } // El primer mapeo es con get para simplemente mostrar la vista @GetMapping("/add") // Pasamos como parámetro el autor para que la vista lo pueda tener disponible public String addAutor(Autor autor) { // Simplemente mostramos la vista return "addautor"; } // Cuando desde la vista nos añaden el autor entramos por 'POST' @PostMapping("/add") // Con @Validated recuperamos los datos y los metemos dentro de una entidad, // spring lo hace solo // En result se guardan los datos de la validación, es decir ¿Lo que nos mandan // son datos válidos? Si es que sí, no dará error, en caso contrario // en result tenemos la lista de errores public String addAutorDatos(@Validated Autor autor, BindingResult result) { System.out.println(autor); System.out.println(result); try { // Si hay algún error volvemos a mostrar la vista y además // fields.error tendrá la información de los errores if (result.hasErrors()) { return "addautor"; } // Si no hay ningún error guardamos el autor autorRepository.save(autor); // Y en vez de devolver una vista, redirigimos al índice return "redirect:/autor"; } catch (Exception ex) { System.out.println(ex.getMessage()); return "error"; } } @GetMapping("/edit/{id}") // Usamos el model porque tenemos que recuperar al autor public String addAutor(@PathVariable Integer id, Model model) { try { // Primero, buscamos el autor que se quiere editar Autor autor = autorRepository.findById(id).orElse(null); if (autor != null) { // Añadimos el autor al modelo model.addAttribute("autor", autor); return "updateautor"; } else { return "error"; } } catch (Exception ex) { System.out.println(ex.getMessage()); return "error"; } } @PostMapping("/update/{id}") public String updateAutor(@PathVariable Integer id, @Validated Autor autor, BindingResult result) { System.out.println(autor); try { if (result.hasErrors()) { return "updateautor"; } autorRepository.save(autor); return "redirect:/autor"; } catch (Exception ex) { System.out.println(ex.getMessage()); return "error"; } } }
Vistas
autores
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Lista de autores</title> <!-- Latest compiled and minified CSS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"> <!-- Latest compiled JavaScript --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script> </head> <body> <h2>Autores</h2> <!-- El th:each es como un bucle foreach, en este caso le estamos diciendo que recorra la variable autores y lo guarde en una variable llamada autor --> <a class="btn btn-success" th:href="@{/autor/add}">Añadir autor</a> <div class="card w-50" th:each="autor: ${autores}"> <!-- Si yo estoy guardando cada elemento en una variable llamada 'autor' puedo acceder a sus propiedades y mostrarlas Pongo un enlace al detalle del autor --> <div class="card-header"><a class="btn btn-primary" th:href="@{/autor/{id}(id=${autor.idautor})}"><span th:text="${autor.idautor}"></span></a></div> <!-- Cuando accedemos a la propiedad nombre spring boot busca el getter Es decir, intentará acceder a getNombre() --> <div class="card-body"><span th:text="${autor.nombre}"></span> <a class="btn btn-secondary" th:href="@{/autor/edit/{id}(id=${autor.idautor})}">Editar</a></div> </div> </body> </html>
addautor
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Añadir Autor</title> <!-- Latest compiled and minified CSS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"> <!-- Latest compiled JavaScript --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script> </head> <body> <h2>Añadir Autor</h2> <!-- Lo primero es hacer un formulario con los campos de autor, en este caso el nombre --> <form th:action="@{/autor/add}" th:object="${autor}" method="POST"> <label for="name">Nombre</label> <!-- el campo hace referencia a la propiedad nombre --> <input type="text" th:field="*{nombre}" id="nombre" placeholder="Nombre"> <!-- Si hay algún error lo mostramos (viene de result) --> <span th:if="${#fields.hasErrors('nombre')}" th:errors="*{nombre}"></span> <input class="btn btn-success" type="submit" value="Añadir"> </form> </body> </html>
updateautor
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Editar Autor</title> <!-- Latest compiled and minified CSS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"> <!-- Latest compiled JavaScript --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script> </head> <body> <h2>Editar Autor</h2> <!-- Lo primero es hacer un formulario con los campos de autor, en este caso el nombre --> <form th:action="@{/autor/update/{id}(id=${autor.idautor})}" th:object="${autor}" method="POST"> <input type="hidden" th:field="*{idautor}" id="idautor"> <label for="name">Nombre</label> <!-- el campo hace referencia a la propiedad nombre --> <input type="text" th:field="*{nombre}" id="nombre" placeholder="Nombre"> <!-- Si hay algún error lo mostramos (viene de result) --> <span th:if="${#fields.hasErrors('nombre')}" th:errors="*{nombre}"></span> <input class="btn btn-success" type="submit" value="Modificar"> </form> </body> </html>
autor
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Autor</title> <!-- Latest compiled and minified CSS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"> <!-- Latest compiled JavaScript --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script> </head> <body> <h2>Autor</h2> <!-- El th:each es como un bucle foreach, en este caso le estamos diciendo que recorra la variable autores y lo guarde en una variable llamada autor --> <div class="card w-50"> <!-- Si yo estoy guardando cada elemento en una variable llamada 'autor' puedo acceder a sus propiedades y mostrarlas --> <div class="card-header"><span th:text="${autor.idautor}"></span></div> <!-- Cuando accedemos a la propiedad nombre spring boot busca el getter Es decir, intentará acceder a getNombre() --> <div class="card-body"><span th:text="${autor.nombre}"></span></div> </div> <table class="table table-striped"> <thead> <tr> <th>Id</th> <th>Titulo</th> <th>Páginas</th> </tr> </thead> <tbody> <!-- Puedo acceder a la propiedad libros porque mi entidad autor tiene un getLibros() que me devuelve los libros y los recorro con el each --> <tr th:each="libro: ${autor.libros}"> <td><span th:text="${libro.idlibro}"></span></td> <td><span th:text="${libro.titulo}"></span></td> <td><span th:text="${libro.paginas}"></span></td> </tr> </tbody> </table> <a class="btn btn-primary" th:href="@{/autor}">Ir al índice</a> </body> </html>