Mostrando entradas con la etiqueta Java. Mostrar todas las entradas
Mostrando entradas con la etiqueta Java. Mostrar todas las entradas

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.




domingo, 4 de octubre de 2020

Java 15 ya está aquí

 


Hace unos días que se ha liberado la versión 15 de nuestro lenguaje de programación favorito, y ya podemos probarla y actualizarnos a través de la versión OPENJDK.

Se puede consultar el estado y las novedades que contiene en la URL:  https://openjdk.java.net/projects/jdk/15


Y para descargarla podemos ir al siguiente enlace: https://jdk.java.net/15/

Para actualizarnos (en Windows), sólo tenemos que descargarnos el zip, descomprimirlo y actualizar nuestras variables de entorno:

  • Yo lo he descomprimido en C:\java\OpenJDK15

  • Y he actualizado las variables de sistema "JAVA_HOME":

  • Y "Path":

Para verificarlo, solo tenemos que lanzar un "java -versión" en nuestra consola ("cmd"):


Con esto, ya estamos listos para utilizar las mejoras que trae (tengo muchas ganas de probar los bloques de texto).

Para acabar he hecho un pequeño proyecto de consola para consumir URLs a través del verbo HEAD, con esto podremos controlar de manera rápida si esa URL existe, sin tener que consumirla y gastar recursos (nuestros y del servidor).

Podéis ver el pequeño proyecto en la siguiente URL: https://github.com/tecnificados/urlChecker

Lo iremos evolucionando en los próximos POSTS.

sábado, 18 de abril de 2020

Algoritmia III: divide y vencerás



Briefing: En estos días de confinamiento, me cuesta mucho sentarme y escribir algo para Tecnificados, entre unas cosas y otras no tengo tiempo, y el poco que me sobra estoy demasiado cansado como para redactar un artículo. En un ratillo, he conseguido escribir este, que es bastante sencillote...

Continuamos los diversos tipos de algoritmos, vamos a hablar de los famosos "divide y vencerás", su idea se basa en descomponer un problema en varios problemas más pequeños, resolver estos, y combinar sus soluciones. Normalmente, la recursividad nos acompañará en este tipo de soluciones.

Estos algoritmos se utilizan muchísimo en Big Data.

Este es el enunciado del problema que vamos a resolver usando este tipo de algoritmo:

   En el programa de la Casa de Empeños, hace unos días llevaron una bolsa de monedas de plata. Rápidamente llamaron a un experto, y este dijo que había una moneda falsa, pero para tasarla necesitaba saber si pesaba más o menos que las auténticas. En la oficina, solo tienen una balanza de dos pesas, para poder comparar el peso de una o varias monedas. 

  Vamos a diseñar un algoritmo y a implementar su solución, utilizando Divide y Vencerás. 

La solución en esta URL: La solución en nuestro repositorio: https://github.com/tecnificados/algoritmos/tree/master/divide

(Imagen Principal generada con https://es.cooltext.com/)

domingo, 1 de marzo de 2020

Ubuntu en Android 2: ahora con JAVA


En el anterior post (https://www.tecnificados.com/2020/02/ubuntu-en-android.html) os comentaba que acaba de descrubrir el emulador "Termux", y todas las cosas que en teoría se podían hacer con él.

Esta semana he estado probándolo, y en este artículo os quiero comentar todo lo que he hecho y el resultado final de las pruebas.

Mi objetivo como os comenté, era poder lanzar tareas programadas, por lo que vendría fenomenal utilizar "cron". Misteriosamente no venía instalado en la imagen que estamos utilizando, pero nada que no se arregle con los comandos: apt install cron y service cron start (arrancamos el servicio).

Una vez hecho ya tenía preparado el "ejecutor" de mis tareas.

Para probarlo bien, necesitaba lanzar una tarea periódica que actualizara datos continuamente, así se me ocurrió utilizar el IBEX 35, programe un pequeño script sh en Linux que descarga el json, y lo subía al repositorio.

Para esto también me instalé "curl" (apt install curl) y "git" (apt install git).

Después de esto, solo necesitaba programar cron con el comando crontab -e.

Añadí esta línea:


1,30 8-18 * * 1-5       /root/termuxTest/ibex35.sh

Y con esta expresión conseguí que el script se ejecutara en el minuto 1 y 30 desde las 8 hasta las 18 de lunes a viernes.

Las pruebas fueron todo un éxito:


Pensar que todos estos commits los hacía mi móvil mientras yo estaba en otra cosa.

Algunos me habéis preguntado por la batería, la verdad es que sí he notado que me gasta un poco más, pero como mucho un 10%.

Os dejo aquí el código del script que utilicé, por si os pudiera servir de algo:

cd "$(dirname "$0")"
date=$(date '+%Y-%m-%d %H:%M:%S')
echo $date
git pull
curl 'urlDondeConseguirLosDatosEnJSON'  > ibex35.json
git add .
git commit -m "Datos actualizados $date"
git push

Una vez que verifiqué esto funcionaba, me instale JAVAapt install openjdk-11-jre

También me instalé maven: apt install maven

Y después cloné mi repositorio evaluador (https://github.com/tecnificados/evaluador), me generé el jar y con este pequeño script:


rm -f datosgobes.csv
wget http://ondemand2.redes.ondemand.flumotion.com/redes/ondemand2/Datosabiertos/datosgobes.csv
java -jar evaluador.jar

Ya consigo ejecutar mi evaluador de Portales de Datos Abiertos desde el móvil. Podéis verlo en este vídeo:


Como conclusión final: puedo ahorrarme el servidor que tenía pensando contratar. Para tareas que no requieren mucha CPU, mi móvil tiene la potencia necesaria para realizar este tipo de tareas.

domingo, 6 de octubre de 2019

Procesando ficheros en JAVA



Con los últimos artículos que estoy escribiendo estoy sentando las bases de dos proyectos en JAVA.

El primero es más pequeño y se basa en una aplicación de consola, y de eso vamos a hablar hoy.

Voy a ir creando una pequeña aplicación de consola que lee todas las líneas de un fichero de texto.

Es bastante simple, pero lo que quiero hacer es crear un proyecto con todas las necesidades que puede tener una aplicación de consola:
  • Librerías externas
  • Sistema de log
  • Fichero externo de configuración
  • Multidioma
  • Generación de un ejecutable (jar) para su posterior uso
Todo el código y los pasos están en el siguiente repositorio: https://github.com/tecnificados/lector

El entorno de trabajo con el que estoy trabajando es el siguiente:
  • Sistema operativo: Windows 10
  • Openjdk version "12.0.2" 2019-07-16
  • IDE: Eclipse 2019-06 (4.12.0)
El primer paso es crear con Maven un proyecto "quickstart" dentro de Eclipse (File -> New -> Maven Project) :



Con esto ya tendremos nuestra estructura lista. Y éste va ser el segundo commit del proyecto: c04808759483432e185fae554a215e682b981af8

Por defecto Maven nos deja el compilador de JAVA con la versión 5.



Ya que estamos utilizando el Openjdk 12, vamos a subirla a esta versión añadiendo estas líneas en el fichero pom.xml:


<maven.compiler.target>1.12</maven.compiler.target>
<maven.compiler.source>1.12</maven.compiler.source>

Podéis ver el detalle del cambio en este commit: 6c483c4abc3f46c0aea1b5679605ac3db27d251a

Si hacemos un "Maven Update", nos debe aparecer la versión correcta en el proyecto.

Ahora vamos a buscar una librería que nos ayude a leer ficheros. Mi favorita es "commons-io" del proyecto Apache. La incluimos en el fichero pom.xml para que sus objetos estén disponibles. Otro commit: 5fa357852024488ab5a43080ee51c446ea7a3c1c

Ahora vamos a hacer una pequeña prueba, vamos crear un pequeño archivo "fichero.txt" que va a tener 10 líneas. Y vamos a escribir unas líneas de código para contar las líneas del fichero utilizando el objeto FileUtils de "commons-io".

El código que escribimos es el siguiente:


List<String> readedLines = new ArrayList<String>();
try {
     readedLines = FileUtils.readLines(new File("fichero.txt"),"utf-8");
     System.out.println("Lineas: "+readedLines.size());
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

Tenemos que meter un try/catch por si el método "readLines" lanza una excepción.

Si ejecutamos este código, nos debería aparecer esta salida:

Lineas: 10


Hago un commit con todos estos cambios: 1287bbeaaf2c21021ce5432b4fd094ea0426554d

Hasta ahora no hemos hecho nada con el contenido del fichero, pero tenemos una lista en la variable readedLines donde está el contenido de cada línea.

Vamos a añadir más información al fichero de prueba, y vamos hacer que el programa nos escriba en pantalla cada una de ellas.

Sé que es muy simple, pero me sirve para demostrar que estamos leyendo el fichero.

Añadiendo estas líneas podremos ver el contenido de cada línea leída:


for (String actual:readedLines)
{
     System.out.println("\t"+actual);
}

Las podéis ver en el commit: d65b491461ba90ed8a1cdef121a1b043985fc733

El funcionamiento básico ya no va a evolucionar más.

Ahora vamos a mejorar el programa para que tenga unas características más profesionales.

Sistema de log

Voy a añadir la librería "logback", antes era más de log4j, pero como muchos sabéis ha quedado sin mantenimiento.

Añadimos la librería al fichero "pom.xml", y en la aplicación nos creamos una variable estática con esta línea:


private static final Logger log = LoggerFactory.getLogger(App.class);

Ya tenemos el log a nuestra disposición.

A partir de ahora todo lo que sale por pantalla, en lugar de usar "system.out" lo hago con el sistema de log que acabamos de añadir.

En la excepción en lugar de usar "log.info" utilizo "log.error".

Todos los cambios del sistema de log están disponibles en este commit: 94d2d8ee44347ede47e67cef3a92ccedd48e9583

Fichero de configuración externo

Ahora mismo se está leyendo el fichero "fichero.txt" y el nombre del fichero está a nivel de código, una práctica que no es muy recomendable.

Vamos a crear un fichero "conf.properties" donde se va a configurar este parámetro.

A continuación voy a crear un método "configuration()" que será el que realice la lógica de leer el fichero de configuración y asignar su valor.

En este commit están todos estos cambios: e33d60eea78b23eca3e07229e856a5fd5d09a6c7

Multidioma

En aplicaciones de consola, es raro que nos soliciten multidioma, pero todo es posible.

Aquí eclipse nos echa un cable, con su asistente en botón derecho -> source -> externalize strings.

Este asistente nos crea una clase "Message" para realizar la sustitución dinámica de las cadenas que seleccionemos.

Antes de lanzar el asistente he generado unas cuantas constantes, para evitar problemas.

He creado tres ficheros con traducciones:
  • messages.properties: es la configuración por defecto (inglés)
  • messages_en_EN.properties: inglés de Inglaterra
  • messages_es_ES.properties: español de España

Voy a dejar fijado este último con la siguiente línea:


Locale.setDefault(new Locale("es_ES"));


Si fijáramos otro como "fr_FR", al no existir, cargaría el contenido del messages.properties.

El un con todos los cambios que acabamos de generar es: a6033bf9c31cbacae035ae69432b85919714c88b

Antes de continuar voy a refactorizar un poco, no me gusta mucho la estructura que me ha generado el asistente.

Voy a generar una clase Constant con todas las constantes, y un paquete Util con las clases y los ficheros nuevos.



Todos los cambios los tenemos en este commit: 80aa109d65ddfadda75e20228e84ce585afb2ed6

Ejecutable Jar Completo

Y para terminar vamos a decirle a Maven que cuando genere un empaquetado lo haga con todas las librerías que utiliza, y especificarle cuál es la clase principal.

Todo esto lo conseguimos gracias al plugin Shade de Maven, sólo hay que retocar unas cuantas líneas en el pom.xml, y añadir un par de plugins. Podéis ver en detalle estos cambios aquí: 86369ce3d028b405eed691a556a5e7fcf90148ef

Después de esto si lanzamos un mvn package tendremos un jar con todas las librerías que necesita, y está listo para ser invocado con el comando: "java -jar lector.jar"

Espero que os sea de utilidad, ha sido una entrada muy larga, pero he conseguido hacer todo lo que quería en sólo 11 commits.