Configuración de la base de datos en SpringBoot

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);
}

Por 9.99€ al mes tendrás acceso completo a todos los cursos. Sin matrícula ni permanencia.