Por 9.99€ al mes tendrás acceso completo a todos los cursos. Sin matrícula ni permanencia.
Nota importantísima. Toda la estructura de paquetes de SpringBoot debe colgar de un paquete base que hemos definido en el initializer de la lección anterior. Si creamos clases que esten en un paquete que no es hijo del paquete base, el código no funcionará.
Configuración básica
Vista
./src/main/webapp/index.html
<form action="/createPersona">
<button name="nombre">Enviar
</button>
</form>
Descargar Proyecto
Controlador
com.pablomonteserin.prueba.controller.PersonaController
@Controller
public class PersonaController {
@Autowired // Esta anotación hace que sea SpringBoot quien gestiona la inyección de dependencias, lo que se traduce en una mejor gestión de los recursos del sistema y comodidad para el programador
private PersonaRepository personaRepository;
// @PostMapping("/createPersona")
@GetMapping("/createPersona")
public String indexGET(@ModelAttribute("persona") Persona persona) throws IOException {
personaRepository.save(persona);
return "forward:/index.html";
}
}
Modelo
com.pablomonteserin.prueba.persistence.repository.PersonaRepository
public interface PersonaRepository extends CrudRepository<Persona, Integer> {
}
Conexión a la base de datos
com.pablomonteserin.prueba.application.properties
#debug=true
#server.port=8080
#spring.mail.host=smtp.gmail.com
#spring.mail.username=
spring.datasource.url=jdbc:mysql://localhost:3306/persona?serverTimezone=UTC&createDatabaseIfNotExist=true
spring.datasource.username=root
spring.datasource.password=
spring.jpa.show-sql=true
spring.jpa.generate-ddl=true
Redireccionando desde un método del controlador a otro método del controlador
com.pablomonteserin.prueba.controller.LibroConroller
@GetMapping("/")
public String selectLibros(Model model) {
// ...
return "consulta";
}
@GetMapping("/create-libro")
public String createLibro(@ModelAttribute("libro") Libro libro) {
// ...
return "redirect:/";
}
Añadiendo la clase Servicio para la lógica de negocio
com.pablomonteserin.prueba.services.PersonaService
public interface PersonaService {
void save(Persona persona);
}
com.pablomonteserin.prueba.services.impl.PersonaServiceImpl
//@Transactional
@Service
public class PersonaServiceImpl implements PersonaService {
@Autowired
private PersonaRepository personaRepository;
@Override
public void save(Persona persona) {
personaRepository.save(persona);
}
}
Usando Thymeleaf
Si quieres que un método del controlador no cargue una plantilla de thymeleaf y redireccione directamente a un html ubicado en webapp, usaremos:
return "forward:index.html";
Cargar una imagen
Las imágenes deben estar ubicadas en la carpeta src/main/resources/static.
Carga de una imagen proveniente de una variable dinámica y ubicada en la raíz del servidor:
<img th:src="|/${equipo.foto_escudo}|" />
Recuperando datos
Recuperando un parámetro de un enlace del tipo https://example.com/equipo/5
<a th:href="|/equipo/${equipo.equipo_cod}|">
@GetMapping("/equipo/{equipo_cod}")
public String selectEquipo(@PathVariable Integer equipo_cod, Model model) {
// ...
return "equipo";
}
Recuperando parámetros de un formulario enviado por get
public String createPaciente(@RequestParam("nombre") String nombre, @RequestParam("apellidos") String apellidos,
@RequestParam("fecha_alta") String fechaAlta) {
Leer una colección de datos en la vista
com.pablomonteserin.prueba.controller
@GetMapping("/consultaInvitados")
public String selectInvitados( Model model) {
List<Invitado> invitados = invitadoRepository.findAll();
model.addAttribute("invitados", invitados);
return "consulta";
}
src/main/resources/templates/consulta.html
<div th:each="invitado : ${invitados}">
<td th:text="${invitado.id}"></td>
<td th:text="${invitado.nombre}"></td>
<td th:text="${invitado.descripcion}"></td>
</div>
Parsear una fecha
<input type="date" name="fecha_alta" th:value="${#dates.format(paciente.fecha_alta, 'yyyy-MM-dd')}" />
Utilizar layouts
El contenido de la etiqueta identificada con layout:fragment=»content» va a cargarse dentro del layout.html, en el fragment identificado como content.
index.html
<!DOCTYPE html>
<html layout:decorate="~{layout/layout}" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<title></title>
</head>
<body>
<div layout:fragment="content">
<p>Contenido de index.html</p>
</div>
</body>
</html>
Dentro de layout.html cargaremos los módulos top.thml y footer.html.
layout.html
<!DOCTYPE html>
<html lang="es" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head></head>
<body>
<div th:replace="~{include/top :: top}"></div>
<div layout:fragment="content"></div>
<div th:replace="~{include/footer :: footer}"></div>
</body>
</html>
top.html
<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head></head>
<body>
<div th:fragment="top">
<h3>TOP</h3>
</div>
</body>
</html>
footer.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head></head>
<body>
<div th:fragment="footer">
<h3>PIE DE PÁGINA</h3>
</div>
</body>
</html>
Definiendo nuevos métodos en el modelo
public interface EquipoRepository extends CrudRepository<Equipo, Integer> {
@Query("SELECT e FROM Equipo e WHERE e.equipo_cod=:id")
Equipo findEquipoByEquipoCod(@Param("id")int id);
List<Equipo> findAll();
@Transactional
void deleteByNombre(String nombre);
}