Enjoy A New Student Discount All 55,000 Courses on sale for Only $12.99

Ends in 05h 23m 49s

Desarrollo de un CRUD con SpringBoot. Las validaciones

Si vamos a realizar un CRUD Restful con cara y ojos, indudablemente necesitaremos algunas validaciones; aunque muchas de ellas podríamos permitir que las hiciera Hibernate, hay otras que no, y, de cualquier forma, dado que en este desarrollo queremos incorporar explicaciones acerca de como trabajar con test (Junit5), he decidido empezar escribiendo una clase dedicada a validaciones, y, a continuación, hacer los test para asegurarnos que trabaja bien.

En cualquier caso, lo primero que tenemos que hacer, es iniciar el proyecto de Spring

Iniciando el proyecto

Si utilizamos STS, podemos indicar

O bien acudir a https://start.spring.io, que utilizaremos en alguna otra ocasión, en la pantalla que se nos ofrece, completaremos los datos que nos interesa para definir el package

y, tras darle NEXT, podremos indicar las dependencias que queremos incluir; en este momento, y, dado que también quiero mostrar como añadir las dependencias, escogeremos las mínimas… o casi

Ahora ya podemos seleccionar «Finish», con lo que nos generará el punto de partida para nuestro proyecto

De momento, no hemos pedido que se nos incluyera el entorno de Test, pero, dada la importancia que tiene, ha sido incluido de forma automática

Algunas cosas que necesitaremos

Puede que necesitemos una clase para guardar constantes, como por ejemplo, el formato de la fecha: para ello, crearé el package com.recursosformacion.lcs.util, y en él la clase

Constantes.java

package com.recursosformacion.lcs.util;

import java.time.format.DateTimeFormatter;



public class Constantes {	
	public final static String FORMATO_FECHA = "dd-MM-yyyy";
	public final static DateTimeFormatter FORMATO_FECHA_EU =  DateTimeFormatter.ofPattern(FORMATO_FECHA);
}

y ya iremos añadiendo lo que necesitemos.

La otra clase que podemos necesitar será una para comprobar errores, y, aunque la mayor parte de ellos, en la vida real los podríamos detectar de otra forma, por motivos de la demo, aquí escribiremos la clase Rutinas , en donde escribiremos las validaciones necesarias .

  • isVacio – recibe una string y devuelve true si es nula o esta vacia
        public static boolean isVacio(String prueba) {
		return prueba == null || prueba.equalsIgnoreCase("");
	}
  • isEmailValido – Comprobamos si el formato recibido en una string es el de correo electrónico
         private final static String EMAIL_PATTERN = "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";

        public static boolean isEmailValido(String email) {
		return !isVacio(email) && email.matches(EMAIL_PATTERN);
	}
  • nuevoSiNoVacio – Comprueba si el segundo parámetro es nulo o vacio, y, si es asi, devuelve el primero, si no, devuelve el segundo parámetro.
    Su firma con generico seria
    • T nuevoSiNoVacio(T a, T b)
        static public <T> T nuevoSiNoVacioG(T valorActual, T valorNuevo) {
		if (Objects.nonNull(valorNuevo) ) {
			return valorNuevo;
		} else {
			return valorActual;
		}
	}
  • isEmptyOrNull – Devuelve True si la coleccion recibida es nula o vacia
        public static boolean isEmptyOrNull(Collection<?> collection) {
		return (collection == null || collection.isEmpty());
	}
  • cumpleDNI – Esta funcion verifica que el DNI cumple el siguiente formato: xx.xxx.xxx-L y la longitud correcta
private final static String DNI_PATTERN = "\\d{2}\\.\\d{3}\\.\\d{3}-[a-zA-Z]";
private final static String LETRA_DNI = "TRWAGMYFPDXBNJZSQVHLCKE";
private final static int LONGITUD_DNI = 12;

            public static boolean cumpleDNI(String dni) {
		if (dni == null) {
			return false;
		}

		// si es un NIE se hacen las operaciones necesarias para poder calcular luego la
		// letra correcta

		if (dni.startsWith("X")) {
			dni = dni.replaceFirst("X", "0");
		} else if (dni.startsWith("Y")) {
			dni = dni.replaceFirst("Y", "1");
		} else if (dni.startsWith("Z")) {
			dni = dni.replaceFirst("Z", "2");
		}

		if (dni.length() != LONGITUD_DNI) {
			return false;
		}

		if (!dni.matches(DNI_PATTERN)) {
			return false;
		}

		String dniNumerico = dni.substring(0, dni.length() - 2).replace(".", "");
		int valorNumerico = Integer.parseInt(dniNumerico);

		Character letraDNI = Character.toUpperCase(dni.charAt(dni.length() - 1));

		if (LETRA_DNI.charAt(valorNumerico % 23) == letraDNI) {
			return true;
		} else {
			return false;
		}

	}
  • comparaFechas – Compara dos fechas en formato LocalDate, y devuelve -1. o 1 segun cual sea mayor o si son iguales. Si se produce algún error, devuelve 999(por ejemplo, alguna fecha es nula)
         public static int comparaFechas(LocalDate fecha, LocalDate min) {
		if (fecha != null && min != null) {
			return fecha.compareTo(min);
		}
		return 999;
	}
  • isGreater – Compara si una fecha es superior a otra
  • isGreaterOrEqual – fecha superior o igual a mínima
  • isLess – una fecha inferior a mínima
  • isLessOrEqual – fecha inferior o igual a minima
        public static boolean isGreater(LocalDate fecha, LocalDate min) {
		if (Rutinas.comparaFechas(fecha, min) == 1) {
			return true;
		}
		return false;
	}
        public static boolean isGreaterOrEqual(LocalDate fecha, LocalDate min) {
		if (Rutinas.comparaFechas(fecha, min) >= 0 ) {
			return true;
		}
		return false;
	}
        public static boolean isLess(LocalDate fecha, LocalDate min) {
		if (Rutinas.comparaFechas(fecha, min) == -1) {
			return true;
		}
		return false;
	}
        public static boolean isLessOrEqual(LocalDate fecha, LocalDate min) {
		if (Rutinas.comparaFechas(fecha, min) == -1 ||Rutinas.comparaFechas(fecha, min) == 0 ) {
			return true;
		}
		return false;
	}
  • esFechaValida – Recibe una fecha en string y compara si es un formato de fecha valido, revisando dias y meses
         public static boolean esFechaValida(String fecha) {
		if (isVacio(fecha)) {
			return false;
		}
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
		Optional<LocalDate> date = Optional.empty();
		try {
			date = Optional.of(LocalDate.parse(fecha, formatter));
			if (date.isPresent()) {
				return true;
			}
		} catch (DateTimeParseException e) {
		}
		System.out.println(fecha);
		return false;

	}
  • esPasswordValida – Comprueba si la cadena recibida cumple con las normas de contraseña que hayamos establecido
private static final String PASSWORD_PATTERN = "((?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%]).{6,20})";
public static boolean esPasswordValida(String password) {
		return !isVacio(password) && password.matches(PASSWORD_PATTERN);

	}

En este punto, nuestro árbol seria

y el módulo lo podéis recoger de mi repositorio en GitHub o copiarlo de aquí

package com.recursosformacion.lcs.util;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Collection;
import java.util.Objects;
import java.util.Optional;

public class Rutinas {

	private static final String PASSWORD_PATTERN = "((?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%]).{6,20})";
	/**
	 * Patron para validar el email, evitando puntos finales antes de la @ y que
	 * solo contenga caracteres alfanumericos
	 */
	private final static String EMAIL_PATTERN = "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";

	/**
	 * Permite verificar que un DNI cumple con el Patron XX.XXX.XXX-L
	 */
	private final static String DNI_PATTERN = "\\d{2}\\.\\d{3}\\.\\d{3}-[a-zA-Z]";

	/**
	 * Letras con las cuales se comprobara la validez del DNI
	 */
	private final static String LETRA_DNI = "TRWAGMYFPDXBNJZSQVHLCKE";

	/**
	 * Longitud que debe tener todo DNI pasado a la aplicacion.
	 */
	private final static int LONGITUD_DNI = 12;

	/**
	 * *******************************************************************************
	 * Devuelve true si la string pasada es nula o vacia
	 * 
	 * @param email String a comprobar
	 * @return true, en caso que el formato sea valido
	 * @date: Octubre 2023
	 * @author: Miguel Garcia
	 */
	public static boolean isVacio(String prueba) {
		return prueba == null || prueba.equalsIgnoreCase("");
	}

	/**
	 * *******************************************************************************
	 * Comprueba si el email tiene un formato que pueda ser valido.
	 * 
	 * @param email String a comprobar
	 * @return true, en caso que el formato sea valido
	 * @date: Octubre 2023
	 * @author: Miguel Garcia
	 * 
	 **************************************************************************************/
	public static boolean isEmailValido(String email) {
		return !isVacio(email) && email.matches(EMAIL_PATTERN);
	}

	/**
	 * *******************************************************************************
	 * Devuelve el valorNuevo si este no es nullo o vacio, si no, devuelve
	 * valorActual
	 *
	 * @param valorActual Valor que tiene el campo en la actualidad
	 * @param valorNuevo  Valor que llega para modificar el valor actual
	 * @return true, en caso que el formato sea valido
	 * @date: Octubre 2023
	 * @author: Miguel Garcia
	 */
	static public String nuevoSiNoVacio(String valorActual, String valorNuevo) {
		if (Objects.nonNull(valorNuevo) && !"".equalsIgnoreCase(valorNuevo)) {
			return valorNuevo;
		} else {
			return valorActual;
		}
	}
	
	static public <T> T nuevoSiNoVacioG(T valorActual, T valorNuevo) {
		if (Objects.nonNull(valorNuevo) ) {
			return valorNuevo;
		} else {
			return valorActual;
		}
	}

	static public int nuevoSiNoVacio(int valorActual, int valorNuevo) {
		if (Objects.nonNull(valorNuevo)) {
			return valorNuevo;
		} else {
			return valorActual;
		}
	}

	static public LocalDate nuevoSiNoVacio(LocalDate valorActual, LocalDate valorNuevo) {
		if (Objects.nonNull(valorNuevo)) {
			return valorNuevo;
		} else {
			return valorActual;
		}
	}

	static public Long nuevoSiNoVacio(long valorActual, long valorNuevo) {
		if (Objects.nonNull(valorNuevo)) {
			return valorNuevo;
		} else {
			return valorActual;
		}
	}

	static public Long nuevoSiNoVacio(Long valorActual, Long valorNuevo) {
		if (Objects.nonNull(valorNuevo)) {
			return valorNuevo;
		} else {
			return valorActual;
		}
	}

	static public Object nuevoSiNoVacio(Object valorActual, Object valorNuevo) {
		if (Objects.nonNull(valorNuevo)) {
			return valorNuevo;
		} else {
			return valorActual;
		}
	}

	/**
	 * **********************************************************************************
	 * Devuelve True si la coleccion recibida es nula o vacia
	 * 
	 * @param collection
	 * @return
	 */
	public static boolean isEmptyOrNull(Collection<?> collection) {
		return (collection == null || collection.isEmpty());
	}

	/**
	 * ***********************************************************************************
	 * Esta funcion verifica que el DNI cumple el siguiente formato: xx.xxx.xxx-L y
	 * la longitud correcta
	 * 
	 * @param dni String con DNI a ser validado
	 * @return true, si el DNI cumple el estandar nacional.
	 * @date: Octubre 2023
	 * @author: Miguel Garcia
	 * 
	 **************************************************************************************/
	public static boolean cumpleDNI(String dni) {
		if (dni == null) {
			return false;
		}

		// si es un NIE se hacen las operaciones necesarias para poder calcular luego la
		// letra correcta

		if (dni.startsWith("X")) {
			dni = dni.replaceFirst("X", "0");
		} else if (dni.startsWith("Y")) {
			dni = dni.replaceFirst("Y", "1");
		} else if (dni.startsWith("Z")) {
			dni = dni.replaceFirst("Z", "2");
		}

		if (dni.length() != LONGITUD_DNI) {
			return false;
		}

		if (!dni.matches(DNI_PATTERN)) {
			return false;
		}

		String dniNumerico = dni.substring(0, dni.length() - 2).replace(".", "");
		int valorNumerico = Integer.parseInt(dniNumerico);

		Character letraDNI = Character.toUpperCase(dni.charAt(dni.length() - 1));

		if (LETRA_DNI.charAt(valorNumerico % 23) == letraDNI) {
			return true;
		} else {
			return false;
		}

	}

	/**********************************************************************************
	 * Fechas
	 ***********************************************************************************/

	/**
	 * **********************************************************************
	 * Compara dos fechas
	 * 
	 * @param fecha Fecha a comprobar uno
	 * @param min   Fecha comparacion
	 * @return -1, 0 +1
	 * @date: Octubre 2023
	 * @author: Miguel Garcia
	 */
	public static int comparaFechas(LocalDate fecha, LocalDate min) {
		if (fecha != null && min != null) {
			return fecha.compareTo(min);
		}
		return 999;
	}

	/**
	 * *******************************************************************************
	 * Valida fecha superior a minima
	 * 
	 * @param fecha Fecha a comprobar uno
	 * @param min   Fecha comparacion
	 * @return True
	 * @date: Octubre 2023
	 * @author: Miguel Garcia
	 */
	public static boolean isGreater(LocalDate fecha, LocalDate min) {
		if (Rutinas.comparaFechas(fecha, min) == 1) {
			return true;
		}
		return false;
	}

	/**
	 * *******************************************************************************
	 * Valida fecha superior o igual a minima
	 * 
	 * @param fecha Fecha a comprobar uno
	 * @param min   Fecha comparacion
	 * @return True
	 * @date: Octubre 2023
	 * @author: Miguel Garcia
	 */
	public static boolean isGreaterOrEqual(LocalDate fecha, LocalDate min) {
		if (Rutinas.comparaFechas(fecha, min) == 1 || Rutinas.comparaFechas(fecha, min) == 0) {
			return true;
		}
		return false;
	}
	
	/**
	 * ****************************************************************************
	 * Valida una fecha inferior a minima
	 * 
	 * @param fecha Fecha a comprobar
	 * @param min   Fecha comparacion
	 * @return True
	 * @date: Octubre 2023
	 * @author: Miguel Garcia
	 */
	public static boolean isLess(LocalDate fecha, LocalDate min) {
		if (Rutinas.comparaFechas(fecha, min) == -1) {
			return true;
		}
		return false;
	}

	/**
	 * ****************************************************************************
	 * Valida una fecha inferior o igual a minima
	 * 
	 * @param fecha Fecha a comprobar
	 * @param min   Fecha comparacion
	 * @return True
	 * @date: Octubre 2023
	 * @author: Miguel Garcia
	 */
	public static boolean isLessOrEqual(LocalDate fecha, LocalDate min) {
		if (Rutinas.comparaFechas(fecha, min) == -1 ||Rutinas.comparaFechas(fecha, min) == 0 ) {
			return true;
		}
		return false;
	}
	
	
	/**
	 * *******************************************************************************
	 * esFechaValida Recibe una string con formato fecha dd/mm/aaaa y comprueba el
	 * formato
	 * 
	 * @param fecha
	 * @return
	 * @date: Octubre 2023
	 * @author: Miguel Garcia
	 */
	public static boolean esFechaValida(String fecha) {
		if (isVacio(fecha)) {
			return false;
		}
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
		Optional<LocalDate> date = Optional.empty();
		try {
			date = Optional.of(LocalDate.parse(fecha, formatter));
			if (date.isPresent()) {
				return true;
			}
		} catch (DateTimeParseException e) {
		}
		System.out.println(fecha);
		return false;

	}

	/**
	 * Comprueba que la cadena recibida cumpla con las normas de contraseña
	 * 
	 * @param password string con la contraseña introducida
	 * @return true si cumple con las especificaciones
	 */
	public static boolean esPasswordValida(String password) {
		return !isVacio(password) && password.matches(PASSWORD_PATTERN);

	}

}

Quiero destacar que este módulo no especula acerca de si algo esta bien o mal, se limita a dar resultados acerca de si la pregunta es cierta o falsa, y, es el programa que llama que deberá decidir acerca de la exactitud. Como veis, se trata de preguntar si el dato recibido tiene valor, o es null, y devuelve un True o un False

Conclusión

Todo este desarrollo lo teneis explicado con mas detalle en youTube, y, aunque es conveniente que intentéis escribirlo TODO vosotros, si queréis renunciar a ello, lo teneis tambien en GitHub

La explicación en YouTube:

Este desarrollo esta hecho para disponer de un fuente para explicar otros temas, tal y como se indica en Visión de conjunto con Spring

Deja un comentario

/*Si te ha gustado el artículo
no dudes en compartirlo*/

Facebook
Twitter
LinkedIn

Uso de cookies

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pinche el enlace para mayor información.plugin cookies

ACEPTAR
Aviso de cookies

Ver mi IP

Ver ip de mi máquina
tipo valor
Ip: 100.28.227.63
Proxy: 100.28.227.63
Remote host: ec2-100-28-227-63.compute-1.amazonaws.com
Remote port: 49108
** 100.28.227.63, 172.70.39.73