Problema de Encoding UTF-8 en Spring MVC
CharacterEncodingFilter es un filtro que nos ayuda a especificar un tipo de codificación de caracteres concreto tanto para solicitudes y como para las respuestas.
Se puede configurar en el fichero web.xml de tu aplicación. De la siguiente forma:
encodingFilter org.springframework.web.filter.CharacterEncodingFilter encoding UTF-8 forceEncoding true encodingFilter /*
En el caso de que estés usando Spring Security, en lugar de configurar el CharacterEncodingFilter en el web.xml necesitas crear un filtro personalizado y añadirlo a la cadena de filtros en primer lugar. Puedes asegurarte que el filtro esté el primero si lo añades con el addFilterBefore en tu clase WebSecurityConfigurerAdapter. Ejemplo:
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { ... @Override protected void configure(HttpSecurity http) throws Exception { http.addFilterBefore(new EncodingFilter(), ChannelProcessingFilter.class); ... } } public class EncodingFilter extends GenericFilterBean { @Override public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); chain.doFilter(request, response); } }
Además, para que funcione el encoding, se debe tener en cuenta lo siguiente:
1 – Es necesario añadir en las jsps la siguiente definición.
< %@ page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8" % >
2 – En caso de estar utilizando Tomcat puede se sea necesario setear el valor URIEncoding en el fichero server.xml.
Utilización de Keycloak para Single Sign-On (SSO)
Single Sign-On se trata de un inicio de sesión unificado. Consiste en un procedimiento de autenticación que habilita a un usuario concreto acceso a distintos sistemas con una sola instancia de identificación.
Una herramienta sencilla que podemos utilizar para configurarnos un SSO que poder utilizar en nuestras aplicaciones se trata de Keycloak.
Ejemplo de uso:
Paso 1 – Ponemos iniciar keycloak mediante su imagen Docker mediante el siguiente comando:
docker run -p 8081:8080 -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=password jboss/keycloak -Dkeycloak.profile.feature.docker=enabled -b 0.0.0.0
Una vez iniciado podemos acceder a la aplicación mediante la url:
http://localhost:8081/auth/admin/master/console/
Paso 2 – Vamos a configurar un usuario y un cliente para poder probar el acceso:
Paso 2.1 – Crear Realm
Creación de un Realm
Pantalla de edición de un Realm
Paso 2.2 – Crear Client (es la aplicación que se va a conectar)
Creación de un cliente
Pantalla de edición de un cliente
Paso 2.3 – Crear User y Rol (Se trata del usuario que se va a conectar y un rol que va a tener asignado)
Creación de un rol
Creación de un usuario
Pantalla de asignación del rol al usuario creado
Paso 3 – Prueba obtención token.
curl --example --request POST 'http://localhost:8081/auth/realms/disastercode/protocol/openid-connect/token' --header 'Content-Type: application/x-www-form-urlencoded' --data-urlencode 'grant_type=password' --data-urlencode 'client_id=appClient' --data-urlencode 'client_secret=7YXN4WL8n3d0LUYejWGJWpG3xyJPUaPE' --data-urlencode 'username=admin' --data-urlencode 'password=admin'
Petición con postman
Dockers para Oracle, OpenLdap y JBoss
– Docker para la version de Oracle Standard Edition 12c Release 2 >>> https://github.com/MaksymBilenko/docker-oracle-12c
Este contenedor te permite utilizar una base de datos de oracle desde un contenedor. Esta en docker hub. Puedes ejecutarlo con el comando:
docker run -d -p 8080:8080 -p 1521:1521 quay.io/maksymbilenko/oracle-12c
Y los datos de acceso serían:
hostname: localhost port: 1521 sid: xe service name: xe username: system password: oracle
– Docker para la última version de OpenLdap >>> https://hub.docker.com/r/bitnami/openldap/
Contenemos que te permite ejecutar un OpenLDAP. Es muy sencillo de ejecutar ya que incluye variables de entorno que si las declaras te permiten configurar el LDAP que se ejecuta. Ejemplo de ejecución:
docker run -p 1389:1389 -e LDAP_ROOT="dc=disastercode,dc=com,dc=es" --name openldap bitnami/openldap:latest
– Docker para utilización de Jboss 7.2 >>> https://hub.docker.com/r/daggerok/jboss-eap-7.2
Obtener la IP de un contenedor de Docker
La forma más rápida de saber la ip asignada a un contenedor de docker es utilizar el comando docker inspect. Un ejemplo sería el siguiente:
LDAP con Apache Directory Studio
Una forma rápida de montar un LDAP para tus aplicaciones de desarrollo sería utilizar la herramienta Apache Directory Studio. Esta herramienta aparte de servir como cliente para conectarte a ldaps externos te permite montar uno en local de una forma bastante amigable.
Paso 1/ Creamos el servidor LDAP
Paso 2/ Configuramos el servidor LDAP. Lo vamos a dejar por defecto.
Paso 3/ Probamos a conectarnos a través del propio cliente.
Exportar e Importar claves GPG
Si tienes en tu equipo creadas claves GPG y quieres poder pasarlas a otro equipo. Puedes hacer los siguiente:
A la hora de importar la clave privada te saltará un popup que te pide la frase secreta con la que fue creada inicialmente.
Utilizar GPG para encriptación de ficheros
GNU Privacy Guard (GnuPG ) o GPG permite: cifrar y firmar sus datos/comunicaciones. Utilizando para ello sistema de gestión de claves.
A continuación expongo un ejemplo de como encriptar un fichero y luego desencriptarlo usando para ello GPG.
Paso 1/ Generamos una clave privada y pública.
Paso 2/ Encriptamos un fichero Prueba.txt
Paso 2/ Desencriptamos el fichero Prueba.txt.gpg que se nos había creado anteriormente.
Uso de Profiles en Spring-boot
Distintas formas de manejar de los profiles con spring-boot para personalizar las ejecuciones:
1 – Establecer el profile en la property spring.profiles.active. Esto lo que hace es que si por ejemplo le establecemos el profile prof1 la aplicación irá a buscar la configuración al application-prof1.properties.
//file: application.properties spring.profiles.active = prof1
2 – Podemos en ejecución decirle a una clase que utilice un profile distinto al marcado. Utilizando para ello la anotación @ActiveProfiles
@SpringBootTest @ActiveProfiles("prof2") class Example2ProfileTest { ... }
3 – Puedes definir beans en función de un profile utilizando la anotacion @Profile en la clase que vas a definirlos.
A continuación, un ejemplo de como se genera un bean en función de si el profile es prof3 u otro con un test de prueba.
@Profile("prof3") @Configuration public class Prof3Configuration { @Bean public String helloWorld() { return "Hello World prof3"; } } @SpringBootTest @ActiveProfiles("prof3") class Example3ProfileTest { @Resource(name = "helloWorld") private String helloWorld; @Test void dummyTest() { Assertions.assertEquals(helloWorld, "Hello World prof3"); } }
@Profile("!prof3") @Configuration public class NotProf3Configuration { @Bean public String helloWorld() { return "Hello World other not prof3"; } } @SpringBootTest @ActiveProfiles("other") class ExampleNot3ProfileTest { @Autowired private String helloWorld; @Test void dummyTest() { Assertions.assertEquals(helloWorld, "Hello World other not prof3"); } }
4 – Se puede utilizar la property spring.profile.include para incluir profiles adicionales a la ejecución:
//application.properties spring.profiles.include=prof4a,prof4b //application-prof4a.properties custom.hello.world.4a=Hello World prof4a custom.hello.world.4b=x //application-prof4b.properties custom.hello.world.4b=Hello World prof4b
@SpringBootTest class Example4ProfileTest { @Value("${custom.hello.world.4a}") private String customHelloWorld4a; @Value("${custom.hello.world.4b}") private String customHelloWorld4b; @Test void dummyTest() { Assertions.assertEquals(customHelloWorld4a, "Hello World prof4a"); Assertions.assertEquals(customHelloWorld4b, "Hello World prof4b"); } }
5 – Uso de profiles de maven junto con los de Spring-Boot
prof1 true prof1 prof5 prof5 ... src/main/resources true
//application.properties spring.profiles.active=@spring.profiles.active@
@SpringBootTest class Example5ProfileTest { @Value("${custom.hello.world}") private String customHelloWorld; @Value("${spring.profiles.active}") private String profileActive; @BeforeEach public void beforeMethod() { assumeTrue( profileActive.equals("prof5")); } @Test void dummyTest() { Assertions.assertEquals(customHelloWorld, "Hello World prof5"); } }
Al contruir con maven podemos indicar un profile definido en el pom.xml o bien no poner ninguno y que coje el indicado como default «prof1»
mvn clean test -Pprof5
Cifrado de contraseñas en Spring-Boot con Jasypt
Jasypt se trata de una herramienta de cifrado simplificado de Java. Te permite agregar funciones básicas de cifrado a los proyectos sin mucha complejidad.
Un ejemplo de uso muy sencillo con Spring-Boot, sería tal que así:
1 – Incorporamos la dependencia al pom.xml.
com.github.ulisesbocchio jasypt-spring-boot-starter 3.0.4
2 – Podemos incorporar el plugin de maven para jasypt que nos va permitir ejecutarlo via mvn.
com.github.ulisesbocchio jasypt-maven-plugin 3.0.4
# Encriptamos 'theValueYouWantToEncrypt' con la contraseña 'the password' mvn jasypt:encrypt-value -Djasypt.encryptor.password="the password" -Djasypt.plugin.value="theValueYouWantToEncrypt" [INFO] ENC(MQoklieA16Tq1gTsyuaGm63ii3skRWMaWyAyObD8Ca7Nqx/SouDq3J4HigJUKDn90xxMIrZQmoQ7hDW7HjNDaQ==) [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 2.361 s [INFO] Finished at: 2022-03-04T08:11:23-08:00 [INFO] ------------------------------------------------------------------------ # Desencriptamos la clave 'MQoklieA16Tq1gTsyuaGm63ii3skRWMaWyAyObD8Ca7Nqx/SouDq3J4HigJUKDn90xxMIrZQmoQ7hDW7HjNDaQ==' con la contraseña 'the password' mvn jasypt:decrypt-value -Djasypt.encryptor.password="the password" -Djasypt.plugin.value="MQoklieA16Tq1gTsyuaGm63ii3skRWMaWyAyObD8Ca7Nqx/SouDq3J4HigJUKDn90xxMIrZQmoQ7hDW7HjNDaQ==" [INFO] theValueYouWantToEncrypt [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 1.801 s [INFO] Finished at: 2022-03-04T08:12:45-08:00 [INFO] ------------------------------------------------------------------------
3 – Configuración
Jasypt tiene una serie de propiedades para su configuración. Todas tienen un valor por defecto a excepción de jasypt.encryptor.password que contiene la contraseña que se va utilizar para la encriptación.
Por otro lado, a las propiedades encriptadas se les debe poner como valor el prefijo ENC( y el sufijo ) (esto también es configurable).
Para un ejemplo sencillo voy definir unicamente en el application.properties la password de encriptación y la propiedad encriptada:
jasypt.encryptor.password=the password prop.encrypt=ENC(m2laknHcOeMybfARtNAPY6E8490/XBNFovqcaX1cvlcNt+roju7RF0IaE1XByYTKXxfQD39F5e/UfYBHLyWjwA==)
3 – Test de prueba
@SpringBootTest @EnableEncryptableProperties class ExampleJasyptApplicationTests { @Autowired Environment environment; @Test void encryption_test() { assertEquals( "theValueYouWantToEncrypt", environment.getProperty("prop.encrypt")); } }
Medición de tiempo de ejecución con StopWatch
StopWatch es un simple cronómetro que permite medir el tiempo de las tareas. Expone el tiempo total de ejecución y el tiempo de ejecución de cada tarea nombrada.
Documentación Oficial – StopWatch
A continuación, se exponen una serie de formas de utilizarlo con Spring-Boot:
Medición tests configurando el StopWatch en las fases ( @AferAll, … )
@SpringBootTest class StopwatchApplicationTests { static StopWatch stopWatch = new StopWatch(); @BeforeAll static void setUp() { stopWatch = new StopWatch(); } @BeforeEach void timeSetUp(TestInfo testInfo) { stopWatch.start( testInfo.getTestMethod().get().getName()); } @AfterAll static void setDown() { System.out.print( stopWatch.prettyPrint() ); } @AfterEach void timeSetDown() { stopWatch.stop(); } @Test void test_one() throws InterruptedException { Thread.sleep(2000); } ... }
Resultado obtenido
StopWatch '': running time = 6011364520 ns --------------------------------------------- ns % Task name --------------------------------------------- 2008182259 033 % test_one 2001327545 033 % test_two 2001854716 033 % test_three
Medición de los test utilizando un TestExecutionListener
Es necesario crear un listener que extienda de AbstractTestExecutionListener, el cuál nos permitirá sobreescribir los métodos beforeTestClass, afterTestClass, afterTestMethod,…
public class ExecutionTimeTestListener extends AbstractTestExecutionListener { private StopWatch stopWatch; @Override public void beforeTestClass(TestContext testContext) throws Exception { super.beforeTestClass(testContext); stopWatch = new StopWatch(testContext.getTestClass().getSimpleName()); } @Override public void beforeTestMethod(TestContext testContext) throws Exception { super.beforeTestMethod(testContext); stopWatch.start(testContext.getTestMethod().getName()); } @Override public void afterTestMethod(TestContext testContext) throws Exception { if (stopWatch.isRunning()) { stopWatch.stop(); } super.afterTestMethod(testContext); } @Override public void afterTestClass(TestContext testContext) throws Exception { System.out.println(stopWatch.prettyPrint()); super.afterTestClass(testContext); } }
Forma de utilización:
@ExtendWith(SpringExtension.class) @TestExecutionListeners({DependencyInjectionTestExecutionListener.class, ExecutionTimeTestListener.class}) class StopwatchWithListenerApplicationTest { @Test void test_one() throws InterruptedException { Thread.sleep(2000); } ... }
Resultado obtenido
StopWatch 'StopwatchWithListenerApplicationTest': running time = 6017421650 ns --------------------------------------------- ns % Task name --------------------------------------------- 2013933526 033 % test_one 2001191940 033 % test_two 2002296184 033 % test_three
Configuración utilizando Aspectj
Se crea un aspecto para que capture todas las ejecuciones del paquete service. Ademas se le pone el @Around para que envuelva el método que captura. Así podemos poner el StopWatch para que medir el tiempo que tarda en ejecutarlo.
Requiere añadir la dependencia spring-boot-starter-aop.
org.springframework.boot spring-boot-starter-aop
@Aspect @Component public class StopWatchAOP { @Around("execution(* es.com.disastercode.examplesspringboot.stopwatch.service.*.*(..))") public Object measureMethod(ProceedingJoinPoint pjp) throws Throwable { StopWatch sw = new StopWatch(); Object retVal; try { sw.start(pjp.getTarget()+"."+pjp.getSignature()); retVal = pjp.proceed(); } catch (Throwable e) { throw e; } finally { sw.stop(); System.out.println(sw.prettyPrint()); } return retVal; } }
Ejemplo de test.
@SpringBootTest class StopwatchWithAopApplicationTests { @Autowired private ProductService productService; @Test void test_one() throws InterruptedException { assertEquals("name 2", this.productService.findNameProductById(2)); } }
Resultado obtenido
StopWatch '': running time = 2050920963 ns --------------------------------------------- ns % Task name --------------------------------------------- 2050920963 100 % es.com.disastercode.examplesspringboot.stopwatch.service.ProductServiceImpl@3d20e575.String es.com.disastercode.examplesspringboot.stopwatch.service.ProductServiceImpl.findNameProductById(Integer)
Categorias
- adobe (2)
- agile (1)
- Alfresco (1)
- Android (26)
- Angular (6)
- angularjs (10)
- apache (1)
- axis (2)
- Bases de datos (14)
- Bootstrap (1)
- C# (3)
- Cámara (1)
- chrome (3)
- Codeigniter (2)
- Control de Versiones (2)
- CSS (25)
- CVS (1)
- Django (9)
- Django Rest Framework (1)
- DNS (1)
- Docker (3)
- dominio (1)
- eclipse (5)
- Entity Framework (2)
- ETL (1)
- Firefox (6)
- flash (1)
- freecad (1)
- Git (12)
- GitHub (4)
- gpg (2)
- Groovy (1)
- Handlebars (1)
- hibernate (4)
- hosting (1)
- HTML (50)
- HTML 5 (26)
- Impresión 3D (9)
- Inkscape (1)
- IOS (2)
- ireports (3)
- Java (44)
- Javascript (55)
- JBoss (5)
- JPA (2)
- JQuery (20)
- Json (7)
- JSP (6)
- Keycloak (1)
- Lamp (1)
- LDAP (2)
- lean (1)
- linkedin (1)
- LINQ (1)
- linux (13)
- Livecycle (1)
- log (1)
- microcontroladores (1)
- MongoDB (4)
- MySQL (8)
- Node.js (5)
- OC4J (1)
- Openshift (2)
- Oracle (6)
- Patrones de Diseño (1)
- Photoshop (2)
- php (20)
- PostgreSQL (1)
- python (19)
- rabbitmq (1)
- Raspberry PI (13)
- Raspherry PI (5)
- React (6)
- seguridad (3)
- Selenium (3)
- Sencha Touch (1)
- Sin categoría (29)
- Spring (17)
- spring-boot (3)
- SQL (7)
- SQLServer (1)
- SSO (1)
- struts (2)
- SVN (1)
- Talend (1)
- Tomcat (6)
- unity (3)
- Visual Studio Code (2)
- vmware (5)
- Web Services (11)
- windows (18)
- wordpress (10)
- Xiaomi (1)
- xml (2)
Trabajos Realizados
- App Android – Autoka Fr
- App Android – Cartelera Cántabra
- App Android – Gramática y Vocabulario Ingles
- App Android – Hoja de Gastos
- App Android – Hotel Torre Cristina
- App Android – OcioEnjoy
- App Android – Visor CardBoard
- App Firefox – Managapp
- DiamanteBomba – DisasterCode
- Generador de Partes de Trabajo
- GitHub – Android Web Generator
- GitHub – Dynamic Angular Gallery
- GitHub – Dynamic React Gallery
- GitHub – Sotilizator
- GitHub – SpringAngularJS
- GitHub – Swiper Dynamic Angular Gallery
- HazParejas – DisasterCode
- RompeCabezas – DisasterCode
- Unity Game – English Couple
- Unity Game – Kill Wasp
- WordPress – El Buen Apicultor
- WordPress – El Cajón de los Retales
- WordPress – El Vestidito Azul
- WordPress – Feuchas
- WordPress – Fragua de Navajas Ponce
- WordPress – Humor a las Tres
- WordPress – Photo Places