Java con un poco de SpringBoot2

En esta entrada vamos a presentar un poco el framework SpringBoot2 para Java, es un software que como objetivo tiende a sustituir y eliminar los tediosos archivos XML del framework de Spring por las anotaciones, que básicamente son clases programadas que modifican el comportamiento de las clases, métodos y parámetros sobre los que están puestos, y se distinguen en el código por tener una @ delante del nombre de la anotación.

Tenemos decenas de anotaciones en el framework que nos van a ayudar a la hora de implementar un proyecto de forma muy rápida sin tener que reescribir el código necesario para que todo funcione, parece magia ya que todo es transparente para el programador, aunque nos obliga a formarnos, tiene una curva de aprendizaje muy rápida y sus funcionalidades pueden ayudarnos a la hora de integrar la lógica de la aplicación.

@anotaciones

@Autowired // Instancia una variable y sus @Beans
@Bean // Crea una instancia singleton
@SpringBootApplication // Instancia una aplicación SpringBoot2
@Controller // Clase controlador
@Service // Clase servicio
@Repository // Clase repositorio
@SpringBootTest // Instancia una bateria de pruebas
@RequesMapping // Prepara un método para un endpoint
@GetMapping // Mismo que el anterior HTTP GET
@PostMapping // Mismo que el anterior HTTP POST
@Async // Clase asíncrona
@EnableAsync // Instancia una aplicación asíncrona

Las anotaciones son muy potentes, nos permiten añadir funcionalidad al código sin tener que implementarla, podemos pasar parámetros de entrada en la anotación entre paréntesis () o varios entre llaves ({}) eso dependerá según para lo que esté programada la anotación.

@GetMapping({ "/", "/index" }) // dos parámetros
@PostMapping("/new") // un parámetro
@GetMapping("/{id}/edit") // podemos especificar parámetros enlazados con variables de entrada

Como vemos con estas herramientas fácilmente podríamos implementar una aplicación con el patrón MVC y añadir las funcionalidades necesarias como un simple CRUD

Spring Initializr para SpringBoot2

Para iniciar una aplicación en SpringBoot2 vamos a la web start.spring.io y seleccionamos el tipo de proyecto que vamos a desplegar y las librerías que vamos a utilizar

Una vez terminamos nos descargamos el proyecto y lo descomprimimos en el workspace para empezar a trabajar con el IDE que más os guste

Espero haber animado a usar este framework que cada día se utiliza más en aplicaciones, y ofrece características como la asincronía o la programación reactiva que no deja indiferente a la hora de poner aplicaciones en producción con altas cargas de peticiones.

Aquí os dejo un pom.xml de prueba

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.8.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>demo</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-webflux</artifactId>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>io.projectreactor</groupId>
			<artifactId>reactor-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

Saludos

Modificadores de acceso en Java

Este post es un resumen de los modificadores de Java. Pensado para las personas que estén preparándose los exámenes de grado superior a modo de guía rápida.

Los modificadores de acceso permiten el encapsulamiento. El cual busca la forma controlar el acceso a los datos de un objeto o instancia.

Los modificadores dan seguridad a las aplicaciones limitando el acceso a diferentes atributos, métodos, constructores asegurando una “ruta” especificada acceder a la información.

Si nuestra aplicación es usada por programadores. Con modificadores de acceso aseguramos que un valor no será modificado incorrectamente. Para eso usaremos el acceso a los atributos con los métodos get y set.

  • Private

Este modificador solo nos permitirá acceder desde la misma clase. En caso de un método solo se podrá llamar internamente. Para los atributos, se crearan métodos públicos GETTERS y SETTERS.

package app.ejemplo;
public class Ejemplo1
{
	// Atributo y sus metodos
	private int atributo;

	public int getatributo()
	{
	  return atributo;
	}

	public void setAtributo(int atributo)
	{
	  this.atributo = atributo;
	}

	// Metodo
	private int metodo(){
	  //code;
	}
}
  • Default

Este acceso por defecto que permite que tanto la propia clase como las clases del mismo paquete.

package app.ejemplo;
public class Ejemplo2
{
    static int atributo = 0;
}
package app.ejemplo2;
public class Ejemplo2_1
{
    public static int getAtributo()
    {
            return Ejemplo2.atributo;
    }
}
  • Protected

Nos permite acceder a las propiedades de la clase padre, cuando estemos haciendo herencias. Fuera de las clases hijas es equivalente a private.

package app.ejemplo;
public class Ejemplo3
{
    protected static int atributo = 0;    
}
package app.ejemplo3_1;
import app.ejemplo3.Ejemplo3;
public class Ejemplo3_1 extends Ejemplo3
{
    public static void main(String[] args)
    {
        System.out.println(atributo)
    }
}
  • Public

Es el mas permisivo. Cualquier clase tendra acceso a el sin importar paquete o procedencia.

package app.ejemplo4;
public class Ejemplo4
{
    public static int atributo = 0;

    public static void metodo()
    {
        System.out.println("Metodo Publico");
    }
}
package otro.paquete;
import app.ejemplo4.Ejemplo4;

public class OtraExterna
{
    public static void main(String[] args)
    {
        System.out.println(Ejemplo4.atributo);
        Ejemplo4.metodo(); 
    }
}
  • La directiva Static

Static es una directiva no un modificador de acceso, pero por utilidad vamos desarrollarla un poco.

Una clase, método o campo declarado como estático puede ser accedido o invocado sin la necesidad de tener que instanciar un objeto de la clase. Uno de los ejemplos típicos de uso de métodos y variables estáticas es la clase java.lang.Math.

public class MathTest {
     public static void main(String[] args) {
        double floorOfPi = Math.floor(Math.PI);
        System.out.println(floorOfPi);
    }
}

Empezando con Docker

docker

¿Qué es Docker?

Docker es un proyecto de código abierto que automatiza el despliegue de aplicaciones dentro de contenedores de software, proporcionando una capa adicional de abstracción y automatización de virtualización de aplicaciones en múltiples sistemas operativos.

Docker utiliza características de aislamiento de recursos del kernel Linux, tales como cgroups y espacios de nombres (namespaces) para permitir que “contenedores” independientes se ejecuten dentro de una sola instancia de Linux, evitando la sobrecarga de iniciar y mantener máquinas virtuales.

¿Qué NO es Docker?

Docker no es como otros sistemas de virtualización completa de un sistema operativo, no emula el hardware necesario para arrancarlo, utiliza el de la máquina anfitriona compartiendo los recursos de la misma entre los contenedores.

En resumen Docker es una herramienta que nos da la capacidad de trabajar con contenedores (máquinas virtuales) que comparten un mismo Kernel.

Vamos a ver un poco las partes básicas de Docker para hacer funcionar un sistema, y luego explicaremos como podemos automatizarlo con docker-compose.

Contenedores

Es el espacio donde se almacenan los datos de la máquina virtual, contiene todos los archivos necesarios para funcionar independientemente del sistema anfitrión. Un contenedor es una instancia de una imagen.

Imagen

Es un prototipo de un contenedor, así como una clase es el prototipo de un objeto y este una instancia de la misma, un contenedor es una instancia de una imagen. Varios contenedores pueden compartir una imagen, pero una imagen solo se corresponde con un contenedor.

Volumen

Es un espacio de almacenamiento que comparte el contenedor con la máquina anfitriona para tener persistencia de los datos, los volúmenes pueden ser de varios tipos como los internos (que los gestiona Docker) o pueden usarse mayormente carpetas compartidas.

Red

Las interfaces de red pueden configurarse según se necesite, tenemos varias como host, que comparte con la máquina anfitriona, el bridge que genera un puente de red o null que no tiene red.

Automatizar Docker con docker-compose

Docker compose es una herramienta creada por Docker, que permite crear una pila de contenedores intercomunicados, partiendo de distintas imágenes.

Docker compose se basa en un fichero con extensión yml donde vamos a indicar que imagen queremos desplegar, cómo se va a configurar y de qué depende.

version: '3'
services:
  web:
    build: .
    ports:
    - "80:80"
    volumes:
    - ./html:/var/www/html
    networks:
      net:

networks:
  net:

En el anterior ejemplo vemos como se crea un contenedor que compila un Dockerfile de la carpeta local, que comparte el volumen de la carpeta local html y también crea la configuración de red.

Conclusión

Las principales ventajas de la virtualización basada en contenedores son:

  • Menos recursos, ahorro en costes. En una misma máquina pueden desplegarse más contenedores que máquinas virtuales tradicionales. Las exigencias en el proceso de inicio y espacio en disco son menores y más rápidas.
  • Gestión TI más fácil, aumento de la productividad TI. La creación de contenedores permite estandarizar los despliegues ya que son entornos repetibles para tareas de desarrollo, prueba y producción. La compatibilidad con todos los sistemas de implantación elimina un valioso tiempo de configuración. Son elementos totalmente portables. Con Docker la implementación se realiza en segundos.
  • Múltiples aplicaciones independientes en un mismo host. Cada aplicación se ejecuta en su contenedor o clúster de contenedores de forma independiente, sin entrar en conflicto con el resto de aplicaciones que aloje el host que ejecutarán mediante sus propios contenedores. Esto garantiza un entorno seguro y eficiente.

Cuando una aplicación ya no es necesaria, simplemente se elimina su contenedor sin dejar huella en el sistema donde se ejecutaba.

Resumen PL/SQL

Este post es un resumen de PL/SQL. Pensado para las personas que estén preparándose los exámenes de grado superior a modo de guía rápida.

PL/SQL nos permite un pequeño ámbito de programación dentro de las bases de datos. Enfocado a administración, eventos o tareas en la misma.

La éxtasis para ejecutar un código arbitrario:

DECLARE 
   <declarations section> 
BEGIN 
   <executable command(s)>
[EXCEPTION
   exception_section]
END;

Un hola mundo seria:

DECLARE 
   message  varchar2(20):= 'Hello, World!'; 
BEGIN 
   dbms_output.put_line(message); 
END; 
/ 

Se usa “/” para declarar que hemos terminado la ejecución de código.

Un delimitador es un símbolo con un significado especial. La siguiente es la lista de delimitadores en PL/SQL:

Como en cualquier lenguaje tendremos procedimientos:

---- Procedimiento
-- Sintaxis 
CREATE [OR REPLACE] PROCEDURE procedure_name 
[(parameter_name [IN | OUT | IN OUT] type [, ...])] 
{IS | AS} 
BEGIN 
  < procedure_body > 
[EXCEPTION
   exception_section]
END procedure_name; 
-- Ejemplo
CREATE OR REPLACE PROCEDURE greetings 
AS 
BEGIN 
   dbms_output.put_line('Hello World!'); 
END; 
/

Y funciones:

---- Función
-- Sintaxis
CREATE [OR REPLACE] FUNCTION function_name 
[(parameter_name [IN | OUT | IN OUT] type [, ...])] 
RETURN return_datatype 
{IS | AS} 
BEGIN 
   < function_body > 
END [function_name];
-- Ejemplo
CREATE OR REPLACE FUNCTION totalCustomers 
RETURN number IS 
   total number(2) := 0; 
BEGIN 
   SELECT count(*) into total 
   FROM customers; 
    
   RETURN total; 
END; 

Lo mejor de PL/SQL es que permite controlar los datos a través de los eventos o triggers:

---- Triggers
-- Sintaxis
CREATE [OR REPLACE ] TRIGGER trigger_name  
{BEFORE | AFTER | INSTEAD OF }  
{INSERT [OR] | UPDATE [OR] | DELETE}  
[OF col_name]  
ON table_name  
[REFERENCING OLD AS o NEW AS n]  
[FOR EACH ROW]  
WHEN (condition)   
DECLARE 
   Declaration-statements 
BEGIN  
   Executable-statements 
EXCEPTION 
   Exception-handling-statements 
END;
-- Ejemplo
CREATE OR REPLACE TRIGGER display_salary_changes 
BEFORE DELETE OR INSERT OR UPDATE ON customers 
FOR EACH ROW 
WHEN (NEW.ID > 0) 
DECLARE 
   sal_diff number; 
BEGIN 
   sal_diff := :NEW.salary  - :OLD.salary; 
   dbms_output.put_line('Old salary: ' || :OLD.salary); 
   dbms_output.put_line('New salary: ' || :NEW.salary); 
   dbms_output.put_line('Salary difference: ' || sal_diff); 
END;

Se recomienda la lectura del siguiente link, con toda la documentación oficial en ingles.

Resumen de SQL

Este post es un resumen de los comandos SQL. Pensado para las personas que estén preparándose los exámenes de grado superior a modo de guía rápida.

  • DDL

Los comandos DDL, son los que nos permiten crear y denominar las tablas, indices y todos aquellos componentes de la estructura de las bases de datos y sus tablas.

---- CREATE
-- Crear tabla:
CREATE TABLE tablename (
   column1 datatype(size) constraint[optional], 
   column2 datatype(size) constraint[optional]
);

---- ALTER
-- Añadir columna a tabla existente:
ALTER TABLE tablename ADD column_name datatype(size);
-- Cambiar tipo a columna a tabla existente:
ALTER TABLE tablename MODIFY column_name datatype(size);
-- Borrar columna en una tabla:
ALTER TABLE tablename DROP column_name ;

---- DROP
-- Borrar una tabla:
DROP TABLE tablename;

---- RENAME
-- Cambiar nombre a una tabla:
RENAME existing_column_name to new_column_name;

---- TRUNCATE
-- Vaciar contenido de una tabla:
TRUNCATE TABLE tablename;

  • DML

Aquí se agrupan los comando que sirven para añadir, modificar o eliminar datos en las tablas.

---- SELECT
-- Mostramos toda las filas y columnas de una tabla: 
SELECT * FROM table_name;
-- Mostramos todas las fila pero solo las columnas declaradas: 
SELECT column1, column2 FROM table_name;
-- Buscamos filas que coincidan en la condición y mostramos todas las columnas:
SELECT * FROM table_name WHERE some_column=some_value
-- Buscamos filas que coincidan en la condición y mostramos las columnas declaradas:
SELECT column1, column2 FROM table_name WHERE some_column=some_value

---- UPDATE
-- Actualizamos las filas que cumplan las condiciones:
UPDATE table_name SET column1=value, column2=value2,... WHERE some_column=some_value

---- DELETE
-- Borramos las filas que cumplan las condicion
-- https://www.youtube.com/watch?v=i_cVJgIz_Cs
DELETE FROM table_name [WHERE condition];

  • DCL

Este es el apartado donde agruparemos los comandos relacionados con permisos de usuarios. Básicamente dos comandos GRANT(Añadir permiso) y REVOKE(Revocar permisos).

---- GRANT
-- Permite crear sesión al usuario 
GRANT CREATE SESSION TO username;
-- Permite al usuario crear tablas
GRANT CREATE TABLE TO username;
-- En ocasiones, el usuario no puede crear tablas con nombres reservados para las tablas del sistema
GRANT CREATE ANY TABLE TO username 
-- Permite al usuario borrar tablas
GRANT DROP ANY TABLE TO username

---- ALTER
-- Cambia la cuota que puede usar el usuario.
ALTER USER username QUOTA UNLIMITED ON SYSTEM;

---- REVOKE
-- Revocamos al usuario 
REVOKE CREATE TABLE FROM username

  • TCL

En este grupo no nos vamos a extender. Pues no se suele pedir en los grados superior. Pero está bien tener en cuenta el comando COMMIT. Que nos asegura que los comandos que introdujimos antes que él. Se sincronicen con el servidor. Ya que existe la posibilidad de que algunos comando, sobretodo los relacionados con permisos de usuario. No se hagan efectivos al ejecutarlos y el servidor espera a reiniciar o a dicho comando.

---- COMMIT
-- Confirma que se guarden los cambios efectuados referentes a permisos de usuario:
COMMIT;

Map, filter y reduce (JavaScript)

javascript

Hola, en esta entrada vamos a explicar un poco los métodos nativos map, filter y reduce, que encontramos en los objetos Arrays de JavaScript y como pueden ayudar a hacer más eficiente la implementación, ya que son más rápidos que los bucles tradicionales.

  • map([🌽, 🐮, 🐔], cook) => [🍿, 🍔, 🍳]
  • filter([🍿, 🍔, 🍳], isVegetarian) => [🍿, 🍳]
  • reduce([🍿, 🍳], eat) => 💩

Map

El método map() devuelve un nuevo Array como resultado de la función que se está aplicando a cada elemento del Array. Esto significa que cada elemento del Array va a ser devuelto en la misma posición del Array resultante pasando por la función del método map(), como lo haría un iterador.

// Declaramos un Array
> var a = new Array(1, 2, 3) || [1, 2, 3]
// Mapeamos el Array con una función para elevar al cuadrado el contenido
> var resultado = a.map(elemento => Math.pow(elemento, 2))
// Se imprime el resultado
> console.log(resultado)
> [1, 4, 9]

Finalmente el método map() devuelve un nuevo Array de la misma dimensión que el original pero modificando cada elemento por el de la salida de la función que estemos aplicando, por lo que no se modifica el Array original.

Filter

El método filter() del objeto Array, como su nombre indica se utiliza para filtrar los elementos del Array con las condiciones lógicas que se tenga en la función que implementa, si la condición no pasa el filtro este elemento no es devuelto en el Array resultante, quedando una dimensión menor que el original.

// Declaramos un Array
> var a = new Array(1, 2, 3) || [1, 2, 3]
// Filtramos el Array con una función para obviar el número 2
> var resultado = a.filter(elemento => elemento !== 2)
// Se imprime el resultado
> console.log(resultado)
> [1, 3]

Vemos como el filtro ignora el número 2 ya que la condición es que sea distinto del número 2, por lo que este número si se encuentra en el Array no es devuelto en el resultante y su posición se obvia, tampoco se modifica el Array original.

Reduce

El método reduce() del objeto Array, este método reduce el Array a un único elemento, ejecuta la función que tiene el método en cada uno de los elementos del Array y el resultado de cada elemento se almacena en un acumulador que será el resultado total.

// Declaramos un Array
> var a = new Array(1, 2, 3) || [1, 2, 3]
// Reducimos el Array a un solo elemento sumando los cuadrados de los elementos del Array
> var resultado = a.reduce((acumulador, elemento) => acumulador + Math.pow(elemento,2))
// Se imprime el resultado
> console.log(resultado)
> 14

Como vemos el resultado en este caso no es un nuevo Array sino el acumulador de la función que apliquemos, tampoco se modifica el Array original.

Conclusiones

Para terminar añadir que ninguno de estos tres métodos utiliza un elemento que no esté definido, en caso de que sea undefined o null se obvia la función aplicada.

Es una buena práctica utilizar los métodos nativos de los Arrays en vez de los bucles tradicionales, ya que son mucho más rápidos a la hora de iterar y si estamos aplicando funciones se hace todo con una sola instrucción y es más limpio.

Los mapas de Elixir tienen una sintaxis incorporada para actualizar

Esto es una traducción de un post de Marin Abernethy  en el blog dockyard.com. En modo de homenaje y agradecimiento. Con la intención de que la comunidad hispana pueda disfrutarlo en su idioma nativo.

En Elixir a menudo, encontramos que hay muchas formas de implementar una sola tarea. Por ejemplo, cuando queremos actualizar un valor clave en un mapa, tenemos varias opciones por delante…

Dado,    expenses = %{groceries: 200, rent: 1000, commute: 70}  podría emplear:

  • Si deseamos actualizar varios pares de valores clave y / o varios nuevos.
# Sintaxis
Map.merge(map1, map2)
# Ejemplo
Map.merge(expenses, %{ rent: 1200, comcast: 100 }) 
  • Si actualizamos o agregamos un solo valor de clave.
# Sintaxis
Map.put(map, key, val)
# Ejemplo
Map.put(expenses, :booze, 100) 
  •  Si queremos incrementar un valor en cierto grado.
# Sintaxis
Map.update(map, key, initial, fun)
# Ejemplo
Map.update(expenses, :misc, 300, &(&1 * 2)) 
  • Si queremos actualizar un valor en una estructura anidada.
# Sintaxis
Kernel.put_in(data, keys, value) 
# Ejemplo
expenses = %{groceries: %{milk: 5}, apartment: %{rent: 1000, comcast: 100}}
put_in(expenses, [:rent, :comcast], "too much")
  • Sin embargo, los mapas vienen con una sintaxis integrada para actualizar uno o más valores clave.
%{expenses | groceries: 150, commute: 75}