domingo, 18 de septiembre de 2022

Límites en Geoboundaries


Allá por el 2015 nos presentamos al concurso de Datos Abiertos de Castilla y León con un pequeño juego, que consistía en ir conquistando los diferentes municipios de esa autonomía. Para el desarrollo del juego tuvimos que tratar con datos de diferentes fuentes nacionales para conseguir los polígonos de los pueblos y ciudades, así como los datos del padrón, etc.

Unos años más tarde evolucionamos un poco el juego, y ampliamos el territorio a toda la península Ibérica. Pero lo que yo realmente quería hacer era conseguir llegar a nivel mundial. Pero imaginaros el trabajo que supondría ir territorio a territorio consiguiendo sus limites administrativos...

Y hace unas semanas descubrí esta URL: https://www.geoboundaries.org/

Dentro podemos encontrar todos los polígonos de cada país a nivel mundial, existen en diversos niveles por cada unos de ellos. En España, el más pequeño es el de los municipios. Es lo que queremos.

Podemos descargar los territorios que nos interesan uno por uno, o utilizar su API para realizar una descarga masiva.

Con esta llamada: https://www.geoboundaries.org/api/current/gbOpen/ALL/ALL/ conseguimos el listado en JSON de todos los países con los diferentes formatos y niveles de descarga.

La idea es descargar todo en formato GEOJSON, así que he hecho un pequeño script de Linux para realizar la descarga:

curl https://www.geoboundaries.org/api/current/gbOpen/ALL/ALL/ > allFilesToDownload.json
curl https://www.geoboundaries.org/api/current/gbOpen/ALL/ALL/ | json_pp > allFilesToDownload.json
grep gjDownloadURL allFilesToDownload.json > downloadAll.sh
sed -i 's/      \"gjDownloadURL\" : \"/wget /g' downloadAll.sh
sed -i 's/\",//g' downloadAll.sh


Este script genera otro script que al ejecutarlo descargará todos los ficheros en GEOSJON para poderlos cargar fácilmente (en MongoDB por ejemplo) y poder trabajar con ellos.

En total, han salido 665 descargas, algunos no son muy grandes, pero los que tienen mucha información superan los 100 MB.

Para validar que la información que estamos descargando no interesa, podemos visualizar cualquiera de los ficheros en la siguiente URL: https://geojson.io

Después de pegar el GEOJSON que se corresponde con el nivel 0 de India se puede visualizar así:



Es de las mejores páginas que hay para poder trastear con ficheros GEOJSON.

De momento voy a seguir descargándome todos los datos. Próximamente veremos que hacer con los datos que tenemos descargados.

Recordar que los datos proceden de Geoboundaries y si los usas, hay que mencionarlos:

Administrative boundaries courtesy of geoBoundaries

Nos vemos pronto.

domingo, 11 de septiembre de 2022

Año sabático



Estos últimos 12 meses han sido un autentico no parar, y aunque parezca un tópico no he tenido tiempo para sentarme y escribir.

La semana pasada incluso me plantee dar de baja el dominio y posponer el blog indefinidamente.

Pero de repente encontré esta definición de año sabático (Gap Year en inglés): es un tiempo dedicado al autoconocimiento y la satisfacción de intereses personales tras un periodo de esfuerzo. 

La verdad es que encaja con mi situación personal de los años 2019 y 2020.

Así que ahora, que ya me he recuperado un poco, he encontrado/retomado un par de temas sobre los que escribir y en breve me pondré con ellos.

Nos vemos pronto.

domingo, 24 de octubre de 2021

La regla del Boy Scout


 
Los Boy Scouts tienen una regla sobre el lugar donde acampan, siempre hay que dejar la zona del campamento en mejor estado de como se encontró al llegar.

Si esto lo extrapolamos al mundo de la Calidad del Software, se podría decir que siempre que realicemos cualquier modificación intentemos mejorar el código que nos encontramos.

Todos los que llevamos tiempo programando sabemos que con el paso del tiempo, si estamos evolucionando un proyecto el código se va deteriorando. La culpa de esto normalmente es nuestra (de los desarrolladores), que por diversas causas (presión, incidencias bloqueantes,...) empezamos a hacer que el código se degrade.

Si conseguimos aplicar esta regla, podremos mejorar un poco la calidad de nuestro software. Por supuesto esto solo es posible si no estamos trabajando bajo presión, y es posible dedicar un poco de tiempo a realizar estas mejoras.

Os voy a poner un pequeño ejemplo a mejorar. Supongamos que tenemos la siguiente función:

public boolean restoreFilters()
{
	if (filter.status!=filter.InitialState)
	{
		filter.restore();
	}        
	return filter.status==filter.InitialState;
}

¿Hay algo que no os cuadre?

En teoría se encarga de restaurar unos filtros a su estado inicial, pero parece que por alguna razón ahora también comprueba si los filtros se encuentran en su estado inicial.

El Principio de Responsabilidad Única nos dice que una función deber hacer una sola cosa (y hacerla bien).

Una posible mejora sería dividir la función en dos:

public void restoreFilters()
{
	if (filter.status!=filter.InitialState)
	{
		filter.restore();
	}        
}

public boolean checkFiltersInitialState()
{    
	return filter.status==filter.InitialState;
}

Después de esto tendríamos que buscar dónde se llama a la primera función, y ver cuando se necesita comprobar el estado de los filtros para adaptar estos cambios.

Con esto habríamos aplicado la regla del Boy Scout, y dejaríamos el código un poco mejor que en el estado inicial.

Nos vemos pronto.


Imagen inicial del  libro "Boy Scout Handbook"


domingo, 15 de agosto de 2021

Recargando

Cuando llega Agosto normalmente estoy muy sobrecargado y necesito tomarme unas semanas para respirar y descansar del mundo informático. Normalmente aprovecho este mes para “desconectar” e intentar retomar antiguos (y saludables) hábitos.

Además este año ha sido “diferente”, mi vida laboral ha pegado un giro de 180 grados, y todavía me estoy acostumbrando. A veces necesito enfocar toda mi atención en otra cosa, sin tener pensamientos en segundo plano, y este verano me propuse resolver el cubo de Rubik.

También he conseguido recuperar dos buenas costumbres:

La lectura: me gusta mucho leer, pero hace unos años, de repente, dejé de hacerlo. Últimamente al año me leía sólo dos o tres libros. Gracias a “Good Reads” y “EBiblio”, he conseguido retomar la lectura. Este año llevo más de 20 libros.

Jugar al ajedrez: me encanta el ajedrez, y ¿sabéis cuánto tiempo llevaba sin jugar? Más de diez años... Estuve buscando una aplicación con vídeos para que mis peques aprendieran de forma amena los movimientos, y encontré “Chess.com”

Aquí debajo os comento un poco sobre las diferentes aplicaciones:

Good Reads: es una red social de lectura, vas actualizando el progreso de lectura de tus libros, te permite establecer un desafío de lectura al año, te recomienda libros según tus intereses, puedes ver lo que tus amigos están leyendo, puntuar libros leídos,...




EBiblio: es la aplicación que te da acceso a los libros de las bibliotecas públicas de España. Además de libros, hay audiolibros, revistas, películas,... El complemento perfecto a la anterior. Te permite reservar libros y te avisa cuando están disponibles. Para usarlo solo necesitas tener tu carnet de la biblioteca de tu municipio actualizado.


Chess.com: aplicación para jugar al ajedrez online, contra oponentes humanos o robots con diferentes niveles de dificultad. Además te analiza las partidas, tiene tutoriales,... Intento jugar una partida al día.


Y para acabar os dejo un vídeo donde se ve cómo resuelvo el cubo de Rubik.



¡¡¡Reto conseguido!!!

lunes, 12 de julio de 2021

Lectura para el verano

Este verano he decidido cerrar el portátil y aprovechar para leer.

Me he decidido por "Código Limpio" que es un repaso a las bases de la programación (la puerta de entrada al mundo de QA).

Para ser un libro técnico se lee muy bien, y está escrito con muchos ejemplos. Ideal para leer con este calor.

Me está ayudando a corregir algunos pequeños vicios y ya he empezado a programar siguiendo algunos de sus consejos.

Ya llevo casi la mitad del libro y estoy muy contento, así que os lo recomiendo sin dudarlo.

Y vosotros, ¿me recomendáis algún libro técnico?

sábado, 26 de junio de 2021

Tests dinámicos con JUnit5

 


Hoy os quiero hablar de los test dinámicos.

Cuando pensamos en realizar test, normalmente tenemos muy claro las funcionalidades que queremos comprobar, pero a veces esas funcionalidades varían con el paso del tiempo, y nuestras pruebas tienen que adaptarse a estos cambios.

Aquí es donde entran en juego los test dinámicos.

Os voy a poner un par de ejemplos de este tipo de test:

  1. Imaginaros que tenéis que chequear un menú dentro de una pagina web, y ese menú actualmente tiene 4 opciones. Puede pasar que dentro de unos meses las opciones aumenten. Un test dinámico, primero leerá todas las opciones que tiene el menú, y después realizará las pruebas establecidas por cada una de ellas.
  2. Pensar en una base de datos que se carga todos los días a las 03:00 AM, y a las 04:00 AM se lanzan una serie de consultas de BBDD para verificar que la información es correcta. Imaginaros que algunas consultas se leen de un directorio que contiene ficheros *.QRY en los cuales están las consultas y el número de registros que se deben devolver. Un test dinámico primero procesará el directorio, para leer cada fichero, después lanzará tantos test como consultas haya leído en cada fichero.
Espero que con esto os hayáis hecho una idea.

Ahora vamos con un ejemplo funcionando con JUnit5.

En este repositorio hemos creado un proyecto con este tipo de Test: 


En concreto en la clase Dynamic_Basic_Test.

Si le echáis un ojo veréis que sólo tenemos dos métodos.

getData()

private Integer[] getData() 
{
	List<Integer> list = new ArrayList<Integer>();
	list.add(1);
	list.add(0);
	list.add(1);
	Integer[] array = list.toArray(new Integer[0]);
	return array;
}


Es el encargado de ir a por la información a testear en este caso, genera un array de 0 y 1. 

dynamicTestsFromCollection()

Stream<DynamicNode> dynamicTestsFromCollection() 
{
	return Stream.of(getData())
		.map(number -> DynamicContainer.dynamicContainer("True or False Test" + number, Stream.of(
			DynamicTest.dynamicTest("is  " + number + " true?", () -> assertTrue(Util.checkOne(number))),
			DynamicTest.dynamicTest("is  " + number + " false?", () -> assertFalse(Util.checkOne(number))))));
}

Esta es la factoría que se va encargar de realizar los test por cada uno de los elementos generados en getData().

En este caso hemos hecho que por cada elemento chequee si es true y si false. Es decir por dos pruebas.

Como estamos haciendo que devuelva [1,0,1] se generan 6 test:
  1. Test OK (1 es true)
  2. Test KO (1 es false)
  3. Test KO (0 es true)
  4. Test OK (0 es false)
  5. Test OK (1 es true)
  6. Test KO (0 es false)
Espero que os sean muy útil, ya os digo que por aquí los utilizamos un muchísimo y ahora con JUnit 5 el código a utilizar se ha reducido bastante.

Nos vemos pronto.

domingo, 30 de mayo de 2021

Apache Derby vs. SQLite


Hoy os traigo un pequeño análisis para contaros las diferencias entre dos bases de datos que nos pueden venir muy bien para proyectos pequeños o para infraestructuras con un tamaño inicial reducido.

La primera se llama SQLite (https://www.sqlite.org), y es un sistema de base de datos que se encuentra dentro de muchas aplicaciones que utilizamos normalmente como navegadores o aplicaciones del móvil.

Es muy ligera, cada base de datos se gestiona dentro de un solo fichero y es ideal para procesos que no necesitan acceso concurrente. Por ejemplo para una aplicación de consola que se ejecuta periódicamente, y lo único que necesita es actualizar la información a través de un solo hilo en cada ejecución.

La otra se llama Apache Derby (https://db.apache.org/derby/), esta base de datos también se ejecuta en memoria, ocupa muy poquito espacio, y la mayor diferencia es que está preparada para procesos concurrentes. Por ejemplo una aplicación web donde varios hilos pueden escribir/consultar a la vez. Oracle la distribuye como JAVA DB

Como lo mejor en estos casos es hacer una pequeña prueba, próximamente voy a intentar hacer un pequeño proyecto con Apache Derby.

Nos vemos pronto.

miércoles, 21 de abril de 2021

Procesando ficheros grandes en JAVA


Llevamos unas semanas con varias filtraciones de datos, hace unas semanas hubo una de Facebook, y hoy hemos tenido otra con datos de una empresa de telefonía...

Cuando nos enteramos de estas cosas, nos gustaría saber si se han filtrado nuestros datos, pero para eso hay que tener los datos (algo que a veces es difícil de encontrar) y después tener las herramientas para abrir esos ficheros.

En los dos casos que he comentado, los ficheros eran texto plano, en formato CSV.

El primero ocupaba 800 MB y el segundo 5,36 GB

Yo no he conseguido abrir ninguno con las herramientas habituales.

Así que he escrito un pequeño programa que lee línea a línea cualquier fichero, busca en cada línea la cadena que nos interese, y las coincidencias que encuentra las escribe en otro fichero.

Podéis acceder a ese desarrollo desde aquí: https://github.com/tecnificados/bigFileOpps

Espero que os sea útil.

Nos vemos pronto.

Muchas gracias a  Hugo y a Valandil por su ayuda consiguiendo los datos.




domingo, 18 de abril de 2021

Spring Boot: un CRUD hecho y derecho

 


Este es el quinto (y último) artículo de la serie sobre Spring Boot que comenzamos el mes de Febrero. Estos son los anteriores:

El proyecto con el que estamos trabajando esta en GitHub y esta es su URL:  https://github.com/tecnificados/boot

Hoy vamos a coger todo lo que hemos aprendido y transformar nuestras diferentes pruebas en un CRUD de Incidencias. 

Antes de nada, ¿qué es eso? CRUD es un acrónimo de CREATE, READ, UPDATE Y DELETE. Cuando alguien nos habla de este término, a lo que se refiere es a un proyecto que permite realizar estas operaciones sobre una o más entidades.

En los diferentes commits que he hecho estos dos días he ido añadiendo operación por operación los diversos cambios en un nuevo Controlador (IncidenciasController), y añadiendo las diferentes JSPs:


Creo que se pueden seguir muy fácilmente, por lo que esta vez no voy a comentar nada del código utilizado.

En el último commit, he eliminado todas las páginas y código que ya no se utilizan, son las que creamos en las primeras entregas para repasar conceptos básicos.

Aunque seguiremos basándonos en este proyecto en futuros artículos, no realizaremos cambios sobre él. Las modificaciones serán a través de forks, así siempre tendremos el ejemplo de un CRUD básico funcionando.




Si tenéis cualquier duda o problemas podéis contactar conmigo por el correo de contacto habitual: tecnifica2@gmail.com

Nos vemos pronto.

lunes, 29 de marzo de 2021

Spring Boot: Seguridad básica

Este es el cuarto artículo de la serie sobre Spring Boot que comenzamos el mes de Febrero. Estos son los anteriores:

El proyecto con el que estamos trabajando esta en GitHub, esa es su URL:  https://github.com/tecnificados/boot

Hoy vamos a empezar a trabajar con Spring Security a nivel muy básico.

Los cambios que vamos a comentar se corresponden con algunos commits del 28 de Marzo de 2021:



Hasta ahora hemos tocado la seguridad muy de refilón, solo hemos dicho que las páginas que hemos ido creando no requerían ningún tipo de seguridad.

Ahora vamos a crear una página que sí requiera estar identificado, y para realizar esa autenticación vamos a crear una página simple de login.

Una de las características que trae de serie Spring Security es protección contra CSRF: entre otras cosas nos garantiza que nadie nos manipula el código de nuestras páginas cuando estamos trabajando con un formulario (algo muy fácil de hacer gracias a las herramientas de depuración de los navegadores).

A continuación vamos repasar los cambios mas importantes en los commits:

Usuario Tecnificado (Commit 69e7131)

Por defecto la configuración de usuarios se encuentra en memoria (más adelante lo cambiaremos para que utilice la base de datos para persistir esta información). En este commit lo que hacemos es añadir al usuario "Tecnificado" con password "iroman" a la lista de usuarios. Lo hacemos con estas líneas en la clase WebSecurityConfig:

@Bean
@Override
public UserDetailsService userDetailsService() {
	UserDetails user =
		 User.withDefaultPasswordEncoder()
			.username("Tecnificado")
			.password("ironman")
			.roles("USER")
			.build();

	return new InMemoryUserDetailsManager(user);
}

Página de login y Lógica (Commit 2615f63)

En este commit hemos hecho dos cambios importantes:

En el primero, configuramos que nuevas vistas vamos a añadir y sus URLs. Lo hacemos en la clase MvcConfig:

public void addViewControllers(ViewControllerRegistry registry) {
	registry.addViewController("/hello").setViewName("hello");
	registry.addViewController("/login").setViewName("login");
}

En la aplicación ya está configurado que la página de login es "login", así que no hay que hacer nada.

Toda la lógica de la página de login, tampoco la necesitamos implementar, Spring sabe lo que tiene que hacer.

Y para acabar añadimos la JSP, una hoja de estilos y el logo.

Lo más importante de estos cambios es el "input hidden" del formulario, ya que sin esto Spring Security no permitirá identificarnos:

<form class="form-signin" action="<c:url value='/login' />" method="post">
	<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />

Esto hay que añadirlo dentro de todos los formularios que se utilicen en la aplicación.

Página Hello y retoques (Commit 38fea25)

Aquí terminamos añadiendo el código de la página que requiere la autenticación: un HTML simple que recupera el nombre del usuario y nos lo muestra en pantalla.

También he añadido un botón desconectar (con formulario) que nos devuelve a la página de login.

En la página inicial (index) he añadido un enlace a la nueva pagina en la parte superior, si pulsamos en ella nos aparecerá la página de login para poder acceder:







En este punto ya tenemos nuestra aplicación trabajando con una seguridad básica. Ya podemos plantearnos empezar con las pantallas del CRUD y trabajar más en serio con la Base de Datos, aunque a lo mejor hacemos algún cambio antes de continuar.

Nos vemos pronto.

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.

sábado, 27 de febrero de 2021

Spring Boot: Página inicial con Bootstrap

 

Este es el segundo artículo de la serie sobre Spring Boot que comenzamos hace dos semanas, si quieres ver el primero puedes acceder pulsando aquí.

En el primer artículo vimos cómo descargar nuestro proyecto configurado para nuestros intereses y listo para ser importado en nuestro IDE (nosotros usaremos Eclipse).

Lo primero que vamos a hacer es importar el proyecto:

  1. File -> Import
  2. Existing Maven Projects
  3. Seleccionamos el fichero pom.xml en la carpeta donde lo hemos descomprimido y esperamos unos segundos
Cuando acabe la importación, esta es la estructura que nos aparecerá:



Con Spring Boot no necesitamos configurar el servidor, ya se encarga él de facilitarnos la vida. Lo único que tenemos que hacer es arrancar la clase BootApplication.java, que se encargará de arrancar Tomcat y dejar nuestra aplicación funcionando en el puerto 8080. 

Y si todo fuera bien, podríamos acceder a través de la URL: http://localhost:8080/

Pero ahora mismo tenemos un error de conexión con base de datos que nos impide que la aplicación arranque.

Vamos a empezar a hacer unas cuantas modificaciones para que todo empiece a funcionar.

Para poder seguir todos los cambios he creado este repositorio en Githubhttps://github.com/tecnificados/boot 

Ahora mismo tiene los siguientes commits:


Los tres primeros commits son la creación del repositorio y la subida del código que descargamos de https://start.spring.io/

El cuarto commit es una corrección para que no nos dé problemas la configuración con la base de datos, si no añadimos estas líneas en el pom.xml, nuestro desarrollo será incapaz de conectarse con la base de datos. 

 <plugin> 

 <groupId>org.apache.maven.plugins</groupId> 

 <artifactId>maven-resources-plugin</artifactId>

 <version>3.1.0</version>

 </plugin>

Los dos últimos commits son los que quiero revisar con vosotros, ya que son los que nos van permitir hacer que la aplicación arranque y trabajar con JSPs, JSTL y añadir Bootstrap a través de sus recursos (css y js).

Cambios para poder trabajar con JSPs (Commit 757e5f2)

Lo primero que vamos a hacer es arreglar el problema con la base de datos. Debemos configurarla. Vamos a utilizar MySQL. Puedes instalarlo directamente, o utilizar la máquina virtual que subimos a Mega hace unas semanas (aquí el artículo). 

No hace falta tener ninguna tabla, simplemente que el servicio esté funcionando.

Vamos a editar el fichero application.properties y dejarlo con la configuración de conexión a BBDD:

#nivel de log en la aplicación
logging.level.root=info

#Configuración de Base de Datos
 
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
 
#Url donde está el servicio de tu mysql y el nombre de la base de datos
spring.datasource.url=jdbc:mysql://localhost:3306/boot_demo?useSSL=false&serverTimezone=Europe/Madrid
 
#Usuario y contrasena para tu base de datos descrita en la línea anterior
spring.datasource.username=boot_demo
spring.datasource.password=boot_demo
 
#[opcional]Imprime en tu consola todo el SQL.
spring.jpa.show-sql = true

Si todo está bien ya podremos arrancar nuestro proyecto con la clase BootApplication.java

Y al acceder a través de http://localhost:8080/ veremos lo siguiente:


¿Qué es esto? Spring Security en nuestra aplicación, todo va bien.

Apagamos y vamos a decirle a Spring Security que de momento no proteja algunas páginas.

Para eso vamos a crear la clase WebSecurityConfig.java y añadiremos el siguiente contenido:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
    .authorizeRequests()
.antMatchers("/", "/login", "/resources/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
    .loginPage("/login")
    .permitAll()
    .and()
    .logout()
    .permitAll();
}
}

Con esta clase entre otras cosas configuramos el acceso libre a las rutas:
  1. /: la pagina inicial
  2. /resources/**: ruta donde estarán nuestros recursos estáticos
  3. /login: nuestra página de acceso

En el fichero application.properties añadiremos estas líneas:

spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp

Así se configura la ruta a nuestras JSPs.

Ahora vamos a crear un controlador (StartController.java), que será el encargado de capturar las peticiones a la página inicial.

@Controller
public class StartController {
 
    @RequestMapping("/")
    public String mensaje() {
         
        return "index";
    }
}

Lo único que le decimos es que capture las peticiones a la página por defecto y las mande a la JSP index.jsp, que va a tener el siguiente contenido: 

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hola</title>
</head>
<body>
Hola con Spring Boot
</body>
</html> 

Y para acabar este punto vamos a necesitar añadir la dependencia que permite ejecutar JSPs en nuestro fichero pom.xml:

<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>


Si ahora arrancamos de nuevo y accedemos a nuestro http://localhost:8080/ ahora deberíamos ver un saludo como este:

Es un poco simple, pero es un comienzo.

Cambios para desarrollar con recursos. Bootstrap añadido (Commit 37cfa22)

Este commit es muy importante, ya que vamos a crear la clase de configuración del proyecto (MvcConfig), donde vamos a poder ir añadiendo 'piezas' según las vayamos necesitando. Y la primera pieza a añadir es decirle a Spring que nos permita servir recursos estáticos como CSS y ficheros JS.

Para empezar vamos a ir por esos recursos, nos vamos a la web oficial de Bootstrap y nos descargamos la versión que nos interese (4.6 por ejemplo): https://getbootstrap.com/docs/4.6/getting-started/download/

Esto nos descargará un zip, vamos a descomprimir su contenido en la carpeta:  "src\main\webapp\resources"

Ahora ya tenemos que ya tenemos los recursos vamos a decirle a Spring dónde están y que nos permita acceder a ellos. Para esto creamos la clase MvcConfig.java


@Configuration
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}

@Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}

En el método addResourceHandlers configuramos dónde están nuestros recursos y con InternalResourceViewResolver configuramos dónde están nuestras JSPs. Esto último lo habíamos escrito en las primeras líneas del application.properties, como ahora debe estar aquí, lo borramos de ese fichero.

Ahora vamos a añadir dos dependencias nuevas a nuestro fichero pom.xml:


<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>jakarta.servlet.jsp.jstl</artifactId>
<version>1.2.6</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>

La primera es para poder usar las etiquetas JSTL en nuestras JSPs (los recursos los añadiremos con c:url) y la segunda es para que si hacemos modificaciones en nuestras páginas, Spring detecte los cambios sin tener que reiniciar.

Y para terminar vamos a modificar nuestra página de inicio para añadir acceso a los recursos que necesitamos y darle un formato un poco más llamativo.

Aquí os dejo un par de ejemplos para que veáis cómo se insertan recursos estáticos:


<script src="<c:url value="/resources/js/vendor/jquery.slim.min.js"/>"></script>

<link rel="stylesheet" href="<c:url value="/resources/css/bootstrap.min.css"/>" >


La página inicial la he modificado basándome en el ejemplo Jumbotron de Bootstrap

De modo que ahora nuestra página de inicio, tiene un aspecto bastante diferente del anterior:


En este punto ya tenemos lista nuestra aplicación para interactuar con nuestra base de datos y poder aplicar seguridad a diferentes páginas. Y lo iremos viendo poco a poco en los siguientes artículos de la serie.

Nos vemos pronto.

sábado, 13 de febrero de 2021

Spring Boot: Introducción

 


Este el primero de una serie de artículos donde nos vamos a meter en Spring Boot.

Aquí en Tecnificados llevamos años trabajando con Spring, así que os voy a contar un poco de qué se trata.

Spring es un framework de desarrollo que contiene muchos proyectos (o módulos) que nos ayudan en el desarrollo de aplicaciones JAVA.

Por ejemplo, el más conocido es Spring MVC, que nos ayuda a generar aplicaciones web siguiendo el Modelo Vista Controlador, ayudado por la inyección de dependencias, que es la autentica revolución de este framework.

También podemos usar Spring Data para ayudarnos con las conexiones de BBDD, o Spring Security para securizar nuestra aplicación de diversas formas,... Si queréis profundizar más acerca de los diferentes proyectos, podéis acceder a esta página: https://spring.io/projects

Volviendo a Spring Boot, vamos a hacer un pequeño repaso a las fase de creación de un proyecto web sin utilizarlo:

  1. Seleccionaríamos las librerías (JARs) que necesitamos.
  2. Empezamos a codificar.
  3. Desplegamos en un servidor web (Tomcat normalmente).

Estas tres fases, normalmente no paran de iterar en un desarrollo, y a veces tenemos pequeños problemas que nos hacen perder tiempo (interacciones con el servidor sobre todo...)

Con Spring Boot esto no pasa, solo te tienes que centrar en la codificación, ya que con un pequeño paso inicial se establecen los parámetros iniciales (librería y servidor), y ya te puedes olvidar de ellos.

Pero no os asustéis, durante el desarrollo se pueden añadir más librerías (algo muy común), o cambiar de servidor (esto menos común).

Hoy os quiero enseñar a dar ese primer paso inicial. Para esto los desarrolladores de Spring han creado una herramienta online, que te permite generar la estructura inicial de tu proyecto con Spring Boothttps://start.spring.io/

Nosotros en la parte de la derecha hemos seleccionado estas opciones:


Las dependencias serán gestionadas con Maven, el desarrollo será en JAVA, utilizaremos la versión 2.4.2 de Spring Boot, y le ponemos nombre a nuestro desarrollo.



Seleccionamos War porque es una aplicación web, y por último seleccionamos JAVA 11.

En la parte de la derecha vamos a elegir nuestras dependencias iniciales:


Para empezar hemos elegido:
  1. Spring Web: desarrollo web, con Spring MVC que además nos permite realizar desarrollos REST.
  2. Spring Security: vamos a añadir una seguridad básica a nuestra aplicación, y controlar que las llamadas REST sean internas.
  3. Spring Data:  toda la gestión de conexión con BBDD la realizará este módulo
  4. MySQL Driver: esta será nuestra BBDD.

En la parte de abajo pulsaremos el botón "GENERATE"


Y esto nos descargará un fichero "boot.zip", para poder abrirlo con nuestro IDE favorito (el mío es eclipse).

Y de momento lo dejamos aquí, nos vemos pronto.