sábado, 13 de marzo de 2021

Spring Boot: Trabajando con bases de datos

Este es el tercer artículo de la serie sobre Spring Boot que comenzamos hace el mes pasado, los anteriores los tienes aquí:
El proyecto con el que estamos trabajando esta en GitHub en la siguiente URL:  https://github.com/tecnificados/boot

Hoy vamos a empezar a trabajar con bases de datos, la configuración ya la establecimos en el anterior post, así que hoy vamos empezar a utilizar esa conexión.

Los cambios que vamos a comentar se corresponden con los commits del 12 de Marzo de 2021:



Clases de acceso a datos, modelo, servicio y script de BBDD (Commit 92a6848)

El objetivo de hoy es crear un tabla y trabajar con ella (insertando, borrando,...), así que lo primero que tenemos que hacer es crear esa tabla a través de un script, lo tenéis en el fichero 'incidencia.sql' en la carpeta 'scripts':

CREATE TABLE incidencia ( 
 id int(11) NOT NULL, 
 titulo varchar(255) DEFAULT NULL, 
 descripcion varchar(2000) DEFAULT NULL, 
 estado int(20) NOT NULL, 
 autor varchar(50) NOT NULL ); 

ALTER TABLE incidencia ADD PRIMARY KEY (id);

Ahora vamos a crear las clases necesarias para trabajar con esa tabla, gracias al framework que utilizamos la cantidad de código que utilizamos es muy pequeña, pero no os asustéis que funciona. Estas son las clases que necesitamos:


Empezamos por el modelo, la clase 'Incidencia.java' es la clase que se corresponde con nuestra tabla. A nivel de código no hay mucho misterio, tiene los atributos que se corresponden con nuestras columnas, y los métodos get y set, un bean de los de toda la vida, pero con anotaciones:

@Entity
public class Incidencia {

@Id
private Long id;

@Column
private String titulo;

@Column
private String descripcion;

@Column
private Integer estado;

@Column
private String autor;

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getTitulo() {
return titulo;
}

public void setTitulo(String titulo) {
this.titulo = titulo;
}

public String getDescripcion() {
return descripcion;
}

public void setDescripcion(String descripcion) {
this.descripcion = descripcion;
}

public Integer getEstado() {
return estado;
}

public void setEstado(Integer estado) {
this.estado = estado;
}

public String getAutor() {
return autor;
}

public void setAutor(String autor) {
this.autor = autor;
}

}


Ahora vamos a ver la clase DAO (Data Access Object), esta es la clase que encarga de realizar las comunicaciones directamente con la Base de Datos.

public interface IncidenciaDAO extends CrudRepository<Incidencia, Long> {

@Query(value = "SELECT coalesce(max(id), 0) FROM Incidencia")
Long getMaxTransactionId();

}

Como podéis ver no tiene casi código ya que a través de la clase que hereda ya obtiene las operaciones básicas.

He añadido el método "getMaxTransactionId()" que se corresponde con la consulta que se puede leer. Lo que hace es sacar el id más alto de la tabla, en caso de no existir devuelve 0.

Ahora tenemos que ver las clases que están dentro del paquete "service". Estas clases son las encargadas de trabajar con las DAO. La verdad es que no tienen mucho que explicar, os recomiendo que las veáis siguiendo este orden:
  1. GenericService.java: interfaz genérica (que nos sirve para cualquier tabla).
  2. GenericServiceImp.java: implementación de la anterior.
  3. IncidenciaService.java: interfaz para Incidencia (aquí nos definimos las particularidades de nuestra clase).
  4. IncidenciaServiceImpl.java: implementación.
Ya tenemos las clases listas para operar con nuestra tabla.

Configuración del pool de conexiones (Commit 1b9d186)

Este es un cambio rápido: vamos a activar el pool de conexiones. 

Necesitamos configurarlo para que haya más de una conexión disponible, de manera que si tenemos más de un usuario, haya conexiones para todos y no se ralentice nuestra aplicación en caso de llevar parada mucho tiempo y que de repente aparezcan varios usuarios a la vez.

Se configura muy fácilmente añadiendo estas líneas en nuestro 'application.properties':

#Configuración del Pool de conexiones
spring.datasource.initial-size=10
spring.datasource.max-active=20
spring.datasource.max-idle=5
spring.datasource.min-idle=1

Cambios en el controlador que utilizan la BBDD (Commit e55a9aa)

En este cambio lo que hemos hecho es cambiar nuestro controlador inicial con nuevos métodos y modificando el inicial para trabajar con BBDD.

El cambio fundamental son estas líneas:

@Autowired
private IncidenciaService incidenciaService;

Gracias a ellas se inyecta el servicio que nos permite trabajar con nuestra tabla.

El método inicial ahora se llama index(), y hace una llamada al listado de incidencias, pasando el resultado al modelo:

        @RequestMapping(DEFAULT)
public ModelAndView  index() {

List<Incidencia> list = incidenciaService.getAll();
ModelAndView model = new ModelAndView();
model.addObject("list", list);
model.setViewName("index");

return model;
}

DEFAULT es una constante que se corresponde con "/" que es la página por defecto: localhost:8080

He añadido el método add() que añade una incidencia (siempre la misma) cada vez que se le invoca:

        @RequestMapping(ADD)
@ResponseBody
public String  add() {
Long id=incidenciaService.maxId()+1;
Incidencia incidencia = new Incidencia();
incidencia.setId(id);
incidencia.setAutor("Juan Carlos");
incidencia.setTitulo("Incidencia "+incidencia.getId());
incidencia.setDescripcion("La aplicación no arranca");
incidencia.setEstado(0);
incidenciaService.save(incidencia);

return "added";
}
ADD es una constante que se corresponde con "/add": localhost:8080/add

Con @ResponseBody indicamos que lo que se devuelve y debe aparecer directamente en la salida html.

El método empty() lo que hace es borrar todas incidencias creadas, siguiendo la misma lógica.

Para que todo funcione hay que añadir las nuevas operaciones en nuestro 'WebSecurityConfig' e indicarle que no requieren autenticación:

         .antMatchers(StartController.DEFAULT,
StartController.ADD,
StartController.EMPTY,
"/login",
/resources/**").permitAll()
.anyRequest().authenticated()


Cambios en la página inicial para mostrar la información de Incidencias (Commit 8a10cf3)

En este commit solo hemos modificado la JSP para que en caso de existir incidencias en la tabla las muestre en la página inicial, en caso contrario nos indicará que no hay incidencias:




Ahora con logs (Commit f342578)

Y para terminar, he añadido un sistema de log en la aplicación, realmente ya estaba, solo lo he añadido como atributo estático en el controlador:

    Logger logger = LoggerFactory.getLogger(StartController.class);

Y un fichero de configuración (logback-spring.xml) para elegir, si consola, fichero o ambos. 

En este punto ya tenemos nuestra aplicación trabajando con BBDD, ahora lo ideal sería generar un CRUD con diferentes pantallas y securizando el acceso a través de una página de login. Veremos como hacerlo próximamente.

Nos vemos pronto.