RSS

Archivo de la categoría: JavaEE

Java EE: Lo básico

Hoy vamos a hacer algo muy simple. Estos días he estado escuchando discusiones sobre que los proyectos hechos en Java EE requieren muchos ficheros, configuraciones y demás, y la verdad, es que me temo que no estoy nada de acuerdo. Quizás antiguas versiones J2EE lo requerian, pero ahora Java EE nos permite centrarnos en el negocio y la única complejidad que se añade se debe a este. Así que he decidido implementar un ejemplo muy básico con ellos para ver cuanta complejidad obtenía implementando un pequeño servicio REST sin BBDD.

Lo primero que tenemos que hacer es crear un proyecto maven en nuestro IDE favorito, en mi caso yo usaré Eclipse. Este proyecto maven será con el arquetipo básico o sin arquetipo. El contenido del fichero pom.xml sera:

<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.wordpress.infow</groupId>
	<artifactId>MostBasicJavaEEApp</artifactId>
	<version>1.0</version>
	<packaging>war</packaging>
	<name>MostBasicJavaEEApp</name>
	
	<properties>
		<maven.compiler.source>1.8</maven.compiler.source>
		<maven.compiler.target>1.8</maven.compiler.target>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<failOnMissingWebXml>false</failOnMissingWebXml>
	</properties>
	
	<dependencies>
	
		<!-- Java EE 7 -->
		<dependency>
			<groupId>javax</groupId>
			<artifactId>javaee-api</artifactId>
			<version>7.0</version>
			<scope>provided</scope>
		</dependency>
	
	</dependencies>
	
	<build>
		<finalName>basic</finalName>
	</build>
</project>

Lo siguiente es crear el servicio REST para esto necesitamos la clase que nos configura REST en nuestra aplicación, cuyo contenido será:

package com.wordpress.infow.basic.rest;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/rs")
public class ApplicationConfig extends Application {

}

Como podéis ver, muy simple.

Y ahora creamos nuestros servicio REST:

package com.wordpress.infow.basic.rest;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;

import com.wordpress.infow.basic.boundary.BasicStuff;

@Path("/sessions")
public class Session {

	@GET
	public String getSession() {
		return "Jonh Doe";
	}
}

Con esto, ya podremos arrancar nuestro servidor, yo estoy usando GlassFish 4, y accediento a la URL correcta podremos ver el resultado.

Lo siguiente es añadir el servicio al que el servicio REST va a invocar e injectar este en nuestro código REST.

package com.wordpress.infow.basic.boundary;

import java.util.Date;

import javax.ejb.Stateless;
import javax.inject.Inject;

import com.wordpress.infow.basic.entity.BasicEntity;

@Stateless
public class BasicStuff {

	public String getDate() {
		return new Date().toString();
	}
}
package com.wordpress.infow.basic.rest;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;

import com.wordpress.infow.basic.boundary.BasicStuff;

@Path("/sessions")
public class Session {

	@Inject
	BasicStuff bs;

	@GET
	public String getSession() {
		return "Jonh Doe" + this.bs.getDate();
	}
}

Con esto ya tenemos nuestro servicio REST invocando a la lógica de negocio de nuestra aplicación, y sin un xml todavía ni nada raro.

El siguiente paso será añadir la entidad que debería conectar con la BBDD.

package com.wordpress.infow.basic.entity;

public class BasicEntity {

	public String getStatus() {
		return "OK";
	}
}
package com.wordpress.infow.basic.boundary;

import java.util.Date;

import javax.ejb.Stateless;
import javax.inject.Inject;

import com.wordpress.infow.basic.entity.BasicEntity;

@Stateless
public class BasicStuff {

	@Inject
	BasicEntity be;

	public String getDate() {
		return new Date().toString() + " - " + this.be.getStatus();
	}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
                           http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
       version="1.1" bean-discovery-mode="all">
</beans>

Vaya, aquí s’i que hemos tenido que añadir un xml para permitir al contenedor web la injección de todos los objectos.

Y ahora, vamos a… Ummm, espera, ya está todo. No necesitamos hacer nada más.

Como se ve Java EE nos deja centrarnos en la lógica de negocio y los problemas derivados de está, en vez de, en complejas configuraciones.

Podeís encontrar el código del proyecto como siempre en mi repositorio:

MostBasicJavaEEApp

Nos vemos.

 
Deja un comentario

Publicado por en 4 septiembre, 2014 en JavaEE

 

JavaEE: QuoteWall

La primera aplicación publicada en el nuevo repositorio mencionado anteriormente, se trata de una simple aplicación implementada en Java EE 7. En ella se puede observar el uso de varias tecnologías como:

  • JPA (MySQL)
  • JAX-RS
  • JAX-WS
  • EJB
  • JSF (PrimeFaces)
  • I18N y L10N
  • Bootstrap
  • Maven y Git

Toda ellas ha sido desplegada en un servidor GlassFish durante su desarrollo, con un DataSource configurado en él.

Como podréis ver echándole un rápido vistazo al código, es una aplicación muy simple que consiste únicamente en un muro de citas famosas dichas por personajes famosos o anónimos. No lleva ningún tipo de seguridad, ni gestión de usuarios ni nada por el estilo. El objetivo  de la aplicación no era más que usar algunas de las tecnologías de Java EE 7 y practicar un poco con Bootstrap, que siendo un desarrollado de Back-end, nuca está de más.

Para el que no lo sepa, Bootstrap es un Framework para front-end muy popular a día de hoy, y que nos hace muy fácil maquetar nuestras páginas y maquetarlas en diferentes dispositivos,

La aplicación la podéis encontrar en el repositorio de ejemplos java ee bajo el nombre de QuoteWall.

La aplicación tiene el típico esquema de directorios que nos aporta el usar maven, aunque en este caso, no ha sido creada a partir de un arquetipo, sino que se ha generado un fichero pom.xml vacío, y se le ha añadido el contenido necesario, incluyendo las dependencias necesarias para correr nuestra aplicación.

Como ya he comentado para las conexiones con base de datos se ha usado un servidor MySQL, y se ha creado en el servidor de aplicaciones GlassFish un DataSource llamado “jdbc/quoteWall”. Por lo demás, es un proyecto bastante estándar que podéis tomar como referencia para la implementación y creación de otros más grandes.

Como plus, se ha añadido otro proyecto más al repositorio: QuoteWallNoSQL, el cual es exactamente el mismo proyecto, pero con los cambios necesarios para hacerlo funcionar con una base de datos NoSQL, en este caso, MongoDB, de lo cual ya escribimos una par de artículos anteriormente aquí en el blog. Si no los habéis visto, os remito a la serie de artículos de NoSQL.

Bueno, hasta aquí todo. Nos vemos.

 
Deja un comentario

Publicado por en 30 marzo, 2014 en JavaEE

 

Interceptores

La siguiente tecnología incluida en Java EE 7 de la que vamos a hablar son los interceptores, los cuales nos permites realizar alguna acción antes de que los métodos sean llamados. Aunque está mal usar la palabra definida en la definición, es un modo de interceptar invocaciones a métodos para de esta forma poder realizar alguna tarea previa a su ejecución o posterior a ella. También se pueden encadenar interceptores para realizar varias tareas diferentes. Un uso muy común suele ser para realizar tareas como generar logs de los métodos ejecutados.

Existen cuatro tipos de interceptores:

  • Interceptores a nivel del constructor: @AroundConstruct
  • Interceptores a nivel de método: @AroundInvoke
  • Interceptores asociados a timeout de métodos: @AroundTimeout (solo se usan en EJB con servicios de timer)
  • Interceptores a nivel de ciclo de vida: @PostConstruct y @PreDestroy

Para el primer ejemplo vamos a mostrar uno a nivel de método que es el más simple e intuitivo (no significa que los demás sean complejos):

public class MyService {
    @Inject
    private Logger logger;

    public void actionOne(MyObject obj) { ... }

    public void actionTwo(MyObject obj) { ... }

    @AroundInvoke
    private Object logMethod(InvocationContext ic) throws Exception {
        logger.entering(ic.getTarget().toString(), ic.getMethod().getName());
        try {
            return ic.proceed();
        } finally {
            logger.exiting(ic.getTarget().toString(), ic.getMethod().getName();
        }
    }
}

La primera cosa en la que tenemos que prestar atención es en la utilización de la anotación para marcar cual es el método que se va a utilizar como interceptor, la segunda, e igualmente importante, es que el prototipo del método utilizado como interceptor debe ser:

[public|private|protected] Object <methodName>(Invocationcontext ic) throws Exception;

Y dicho prototipo ni puede ser static o final.

Básicamente cuando alguna clase invoque alguno de los métodos de nuestra clase, esta llamada será interceptada por nuestro interceptor. La secuencia de ejecución para una llamda al método “actionOne” será:

  1. Llamada a “actionOne”
  2. Interceptación. Llamada a “logMethod”.
  3. Escritura del log: “entering”.
  4. Ejecución del método invocado: “proceed”.
  5. Escritura del log: “exiting”.

Mostrar un ejemplo del resto de tipos de interceptores no tiene mucho sentido, ya que no es más que seleccinar la anotación adecuada y colocarla de igual modo que hemos hecho con “@AroundInvoke”.

Lo que si que va a resultar interesante, y seguro que más de uno ya ha pensado es, ¿y tengo que crear un interceptor por cada clase para poder escribir en el log (nuestro caso particular)? Pues bien, la respuesta es no. Podemos crear un interceptor genérico y aplicarlos a las clases o métodos que deseemos. Para ello vamos a crear este interceptor genérico y luego ver como usarlo con los siguientes ejemplo:

Interceptor genérico:

public class LoggingInterceptor {
    @Inject
    private Logger logger;

    @AroundConstruct
    private void init(InvocationContext) throws Exception {
        logger.fine("My logging interceptor constructor: Entering");
        try {
            ic.proceed();
        } finally {
            logger.fine("My logging interceptor constructor: Exiting");
        }
    }

    @AroundInvoke
    public Object logMethod(InvocationContext) throws Exception {
        logger.entering(ic.getTarget().toString(), ic.getMethod().getName());
        try {
            return ic.proceed();
        } finally {
            logger.exiting(ic.getTarget().toString(), ic.getMethod().getName();
        }
    }
}

Usándolo en una clase a nivel de método, tendríamos el siguiente resultado:

public class MyService {
    @Interceptors(LoggingInterceptor.class)
    public void actionOne(MyObject obj) { ... }

    public void actionTwo(MyObject obj) { ... }
}

Con esto nuestro inerceptor sería llamada cada vez que el método “actionOne” sea invocado, pero no al llamar al método “actionTwo”.

También podemo asignar el interceptor a nivel de clase, donde todos los método llamados de esa clase invocarían a nuestro interceptor:

@Interceptors(LoggingInterceptor.class)
public class MyService {
    public void actionOne(MyObject obj) { ... }

    public void actionTwo(MyObject obj) { ... }
}

E incluso si tenemos muchos métodos en una clase y queremos que alguno de ellos no invoque a nuestro interceptor, pero los demás sí, podemos excluir este método:

@Interceptors(LoggingInterceptor.class)
public class MyService {
    public void actionOne(MyObject obj) { ... }

    public void actionTwo(MyObject obj) { ... }

	@ExcludeClassInterceptors
	public void actionTree(MyObject obj) { ... }
}

Como añadido a esto, y para potenciar aún más el uso de interceptores, estás anotaciones nos permiten mucha más versatilidad aún, como la de invocar varios y diferentes interceptores según necesitemos, pudiendo hacer cosas como estas:

@Interceptors({Int1.class, Int2.class})
public class MyService {
    public void actionOne(MyObject obj) { ... }

    @Interceptors({Int3.class, Int4.class})
    public void actionTwo(MyObject obj) { ... }

	@ExcludeClassInterceptors
	public void actionTree(MyObject obj) { ... }
}

Aunque no lo parezca, el orden en el que aparecen los interceptores en la anotación es importante, ya que será este el orden en el que se invocarán.

Pero si pensabais que aquí habíamos terminado, estáis equivocados. Aún nos queda una forma más de declarar nuestros interceptores, por suerte, es una forma muy similar a la que se definen los “Qualifiers” que vimos en el artículo anterior. Se suele conocer como “Interceptor Binding”, y aquí si que lo siento, porque no he encontrado ninguna traducción que me haya convencido. Decir antes de empezar, que para poder utilizar este tipo necesitamos de forma obligatoria tener el soporte para CDI activado. De esta forma podremos hacer cosas como estas:

Interceptor Binding:

@InterceptorBinding
@Target({METHOD, TYPE})
@Retention(RUNTIME)
public @interface Loggable { }

Interceptor:

@Interceptor
@Loggable
public class LoggingInterceptor {
    @Inject
    private Logger logger;

    @AroundInvoke
    public Object logMethod(InvocationContext ic) throws Exception {
        ...
    }
}

Nuestro servicio:

@Loggable
public class MyService {
    public void actionOne(MyObject obj) { ... }

    public void actionTwo(MyObject obj) { ... }

	@ExcludeClassInterceptors
	public void actionTree(MyObject obj) { ... }
}

Se puede utilizar tanto a nivel de clase como de método.

En este punto tenemos que añadir que estos interceptores están deshabilitados por defecto, con lo cual tenemos que añadir en nuestro “bean.xml” explicitamente que queremos usarlos. Esto sería añadiendo al fichero el siguiente nodo:

<interceptors>
    <class>org.example.LoggingInterceptor</class>
</interceptors>

Y ya por fín, lo último. Utilizando este último tipo de interceptores perdemos la posibilidad de ordenar estos según el orden de ejecución que deberían seguir. Para paliar esta desventaja se ha introducido el concepto de prioridad, pudiendo asignar un valor numérico positivo a cada interceptor. Cuanto más bajo sea el valor, antes se ejecutará el interceptor.

En nuestro ejemplo, el código del interceptor quedaría algo como:

@Interceptor
@Loggable
@Priority(100)
public class LoggingInterceptor {
    @Inject
    private Logger logger;

    @AroundInvoke
    public Object logMethod(InvocationContext ic) throws Exception {
        ...
    }
}

Bueno, hasta aquí hemos llegado. Espero que os haya sido de utilidad y que os haya quedado claro toda esta parte de los interceptores. Nos vemos.

 
Deja un comentario

Publicado por en 6 febrero, 2014 en JavaEE

 

Inyección de dependencias y “Qualifiers”

El artículo de hoy va ser un poco técnico y enfocado a Java EE 7. Vamos a hablar sobre la inyección de dependencias. Imagino que a estas alturas no habrá un solo desarrollador Java/Java EE que no sepa lo que es esto. Para aquellos despistados añadiré, que la inyección de dependencias es un patrón en el que se le suministran objetos a una clase, en lugar de que la clase los cree. Para el que aún no sepa lo que es, le recomiendo que lo mire antes de proseguir leyendo porque el objetivo del artículo es solo dejar unos breves apuntes sobre la parte técnica, y no el de dar una amplia explicación sobre este concepto.

Para empezar, vamos a ver un ejemplo de como crearíamos un dependencia sin utilizar inyección. Esto sería utilizando la palabra reservado “new” como se ha hecho durante mucho tiempo. Para los ejemplos, vamos a utilizar una especie de sistema bancario de tarjetas, el cual adaptaremos a nuestras necesidades para la explicación.

Bien, pues aquí tenemos el primer ejemplo de dependencias sin inyección:

public class CustomerService {
    private Card card;

    public CustomerService() {
        this.card = new DebitCard();
    }

    public Customer createCustomer(String name, String surname) {
        Customer customer = new Customer(name, surname);
        customer.setCardNumber(card.generateNumber());

        return customer;
    }
}

Esto sería el modo tradicional de la creación de un objeto y el manejo de este. En caso de tener varios tipos de tarjetas, podríamos utilizar el constructor para crear un tipo u otro:

public class CustomerService {
    private Card card;

    public CustomerService(Card card) {
        this.card = card;
    }

    public Customer createCustomer(String name, String surname) {
        Customer customer = new Customer(name, surname);
        customer.setCardNumber(card.generateNumber());

        return customer;
    }
}

CustomerService customerService = new CustomerService(new DebitCard());
CustomerService customerService = new CustomerService(new CreditCard());

Con esto vemos como podemos pasar el tipo de tarjeta a nuestro servicio según cual necesitemos en cada momento.

Ahora bien, para ahorrarnos esto, la injección de dependencias viene en nuestra ayuda pudiendo hacer cosas como la que vemos a continuación y donde será nuestro contenedor el que maneje el objeto y se encargue de hacer el “new”:

public class CustomerService {
    @Inject
    private Card card;

    public Customer createCustomer(String name, String surname) {
        Customer customer = new Customer(name, surname);
        customer.setCardNumber(card.generateNumber());

        return customer;
    }
}

public DebitCard implements Card {
    public String generateNumber() {
        ...
    }
}

Existen varias formas de hacer la inyección del objeto (varios puntos de inyección): en la propiedad, en el constructor o en el método “set”. Técnicamente no hay una mejor o una peor, esto queda un poco a gusto del desarrollador. Los ejemplo de cada una de ellas serían los siguientes:

@Inject
private Card card;
@Inject
public CustomerService(Card card) {
    this.card = card;
}
@Inject
public void setCard(Card card) {
    this.card = card;
}

Ahora bien, más de uno se estará preguntando en este punto que sucedería en caso de haber más de una clase que implementara el interfaz “Card”. Pues bien, aquí es donde los “Qualifiers” cobran su importancia, permitiéndonos establecer que clase es la que debe ser inyectada. Como ejemplo, vamos a crear los “Qualifiers” de nuestras tarjetas de crédito y débito:

@Qualifier
@Retention(RUNTIME)
@Target({FIELD, TYPE, METHOD})
public @interface Debit { }
@Qualifier
@Retention(RUNTIME)
@Target({FIELD, TYPE, METHOD})
public @interface Credit { }

Que usaríamos en las clases correspondientes:

@Debit
public DebitCard implements Card {
    public String generateNumber() {
        ...
    }
}

@Credit
public CreditCard implements Card {
    public String generateNumber() {
        ...
    }
}

Y a la hora de la inyección el código quedaría tal que así:

public class CustomerDebitService {
    @Inject @Debit
    private Card card;

    public Customer createCustomer(String name, String surname) {
        Customer customer = new Customer(name, surname);
        customer.setCardNumber(card.generateNumber());

        return customer;
    }
}

public class CustomerCreditService {
    @Inject @Credit
    private Card card;

    public Customer createCustomer(String name, String surname) {
        Customer customer = new Customer(name, surname);
        customer.setCardNumber(card.generateNumber());

        return customer;
    }
}

Pero claro, esto con solo dos clases está muy bien y es manejable, pero imaginemos ahora que sacamos más modelos de tarjetas: normal, online, endMonthPay y premium. Y además, todas ellas pueden ser de débito o de crédito. Está claro que se volvería inmanejable además de complicar innecesariamente con clases extras nuestra aplicación. Para evitar esto, en los “Qualifiers” podemos definir miembros, o lo que es lo mismo, propiedades para el “Qualifier”. Así que vamos a ver el ejemplo de como sería esto:

@Qualifier
@Retention(RUNTIME)
@Target({FIELD, TYPE, METHOD})
public @interface CardType {
    CType value();
    boolean debit();
}

public enum CType {
    NORMAL, ONLINE, END_MONTH_PAY, PREMIUM
}

En este caso el código quedaría así para una tarjeta de débito normal:

@CardType(value = CType.NORMAL, debit = true)
public DebitCard implements Card {
    public String generateNumber() {
        ...
    }
}

@Inject @CardType(value = CType.NORMAL, debit = true)
private Card card;

Bueno, hasta aquí el pequeño esquema de hoy sobre inyección de dependencias y “Qualifiers”. Para cualquier duda, ya sabéis. Nos vemos.

 
Deja un comentario

Publicado por en 2 febrero, 2014 en JavaEE

 

Simplificando proyectos

Hoy, solo os traigo una charla de Adam Bien sobre el código que sobra en nuestros proyectos y la enorme cantidad de veces que tenemos en ellos mucho más de lo que necesitamos. Me ha sorprendio, entre otras cosas a parte de resultarme interesante, la cantidad de cosas que comenta que no se deberían hacer y que si que se hacen en la mayoría de proyectos grandes en los que he participado. Obviamente, esto es una opinión de él, pero con bastante sentido común muchas de las cosas que comenta.

Para quien no lo conozca, es un Freelancer que lleva trabajando muchísimos años en Java, y como él dice, aún lo disfruta. Además, ha escrito un par de libros (que tengo en mi lista para leer) y, de vez en cuando, da charlas sobre JavaEE. Los libros son:

Pero bueno, os dejo su página si queréis echarle un ojo: Adam Bien

El video, como ya he dicho, es bastante interesante. Su duración es de menos de una hora (unos 45 minutos) y, aunque está en inglés, es fácimente entendible.

Espero que os guste. Nos vemos.

 
Deja un comentario

Publicado por en 4 octubre, 2013 en JavaEE, programación

 

JavaEE: Struts2

El siguiente ejemplo que vamos a hacer es sobre Struts2. Ya se que ha día de hoy no se utiliza demasiado ya que hay otras muchas soluciones para implementar el modelo MVC, pero aún así, os asombraría la cantidad de empresas que todavía usan este framework y, que a día de hoy, no están pensando cambiar todavía ya que la migración les implicaría una ingente cantidad de trabanjo en sistemas que están más que probados y funcinando. Por este motivo, considero que es interesante que veamos aunque sea un pequeño ejemplito.

Lo primero, es crear nuestro proyecto en eclipse sin arquetipo, tras lo cual, introduciremos en nuestro fichero pom.xml el siguiente contenido:

pom.xml

<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.wordpress.infow</groupId>
        <artifactId>struts</artifactId>
        <version>1.0</version>
        <packaging>war</packaging>
        <name>struts</name>
        <url>http://www.infow.wordpress.com</url>

        <dependencies>
                <dependency>
                        <groupId>org.apache.struts</groupId>
                        <artifactId>struts2-core</artifactId>
                        <version>2.3.14.3</version>
                </dependency>
        </dependencies>
        <build>
                <finalName>StrutsExample</finalName>
                <plugins>
                        <plugin>
                                <groupId>org.apache.maven.plugins</groupId>
                                <artifactId>maven-compiler-plugin</artifactId>
                                <configuration>
                                        <source>1.7</source>
                                        <target>1.7</target>
                                </configuration>
                        </plugin>
                </plugins>
        </build>
</project>

Al ser, como en veces anteriores, una aplicación web, tendremos que añadir el fichero de configuración básico, el fichero web.xml que se encontrará en la ruta webapp/WEB-INF como las veces anteriores:

web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
        <display-name>Struts Example</display-name>

        <filter>
                <filter-name>struts2</filter-name>
                <filter-class>
                        org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
                </filter-class>
        </filter>

        <filter-mapping>
                <filter-name>struts2</filter-name>
                <url-pattern>/*</url-pattern>
        </filter-mapping>

</web-app>

Como veís su contenido es muy simple, simplemente es añadir un filtro para Struts y un mapeo para este.

El siguiente fichero que vamos a añadir es el de configuración de struts propiamente dicho. En él vamos a especificar las diferentes acciones para la navegación, es decir, que URLs van a donde y, donde se navegará dependiendo del resultado de las diferentes acciones. Como contenido de este fichero struts.xml, que estará alojado en src/main/resources, tendremos lo siguiente:

struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>

        <package name="user" namespace="/User" extends="struts-default">
                <action name="Login">
                        <result>pages/login.jsp</result>
                </action>
                <action name="Message" class="com.wordpress.infow.struts.action.MessageAction">
                        <result name="SUCCESS">pages/welcome_user.jsp</result>
                </action>
        </package>

</struts>

Como podemos ver, para la acción “login” se nos redirijirá a la página de login, y para la accion de “message” en caso de el resultado ser SUCCESS, se nos redirijirá a mostrar el mensaje.

Ya solo nos faltan las página que formar parte del comportamiento de nuestra aplicación. Entre ellas tenemos el jsp de login que tendrá el siguiente contenido:

login.jsp

<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
        <head>
                <title>Login - Struts Example</title>
        </head>
        <body>
                <s:form action="Message">
                        <s:textfield name="username" label="Username" />
                        <s:submit />
                </s:form>

        </body>
</html>

La acción que lanzará el formularío será “Message” que podéis encontrar en el fichero struts.xml.

El siguiente fichero a definir es el que nos mostrará nuestro mensaje que también es un jsp:

welcome_user.jsp

<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
        <head>
                <title>Welcome - Struts Example</title>
        </head>
        <body>
                Hello <s:property value="username" />
        </body>
</html>

Como véis también es bastante trivial.

Finalmente, tenemos nuestra clase java que implementará nuestra acción. En este caso, simplemente devolverá SUCCESS para redirijirnos a la página donde se nos mostrará el mensaje.

MessageAction.java

public class MessageAction {
        private String username;

        public String execute() {
                return "SUCCESS";
        }

        public String getUsername() {
                return this.username;
        }

        public void setUsername(String username) {
                this.username = username;
        }

}

Hasta aquí hemos llegado con el ejemplo. Como siempre, os dejo el código para que podaís echarle un ojo a lo que he estado describiendo y podáis ejecutarlo en vuestros servidores:

Codigo Struts2 Hello World: Struts

Nos vemos.

 
Deja un comentario

Publicado por en 19 julio, 2013 en JavaEE

 

JavaEE: SpringSecurity

La siguiente demo que vamos a hacer, es una pequeñita demostración con Spring Security. Además, vamos a hacerla con nuestros credenciales almacenados en un XML y no en la BBDD como sería lo más normal para dar soporte a un gran sistema con multitud de usuarios y roles.

Como en veces anteriores, vamos a crear nuestro proyecto en Eclipse con maven y sin arquetipo, tras esto, rellenaremos el fichero pom.xml con el siguiente contenido:

pom.xml

<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.wordpress.infow</groupId>
        <artifactId>springSecurity</artifactId>
        <version>1.0</version>
        <packaging>war</packaging>
        <name>springSecurity</name>
        <url>http://www.infow.wordpress.com</url>

        <properties>
                <spring.version>3.2.3.RELEASE</spring.version>
                <spring.security.version>3.1.4.RELEASE</spring.security.version>
        </properties>

        <dependencies>
                <!-- Spring 3 -->
                <dependency>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-core</artifactId>
                        <version>${spring.version}</version>
                </dependency>

                <dependency>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-web</artifactId>
                        <version>${spring.version}</version>
                </dependency>

                <dependency>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-webmvc</artifactId>
                        <version>${spring.version}</version>
                </dependency>

                <!-- Spring Security -->
                <dependency>
                        <groupId>org.springframework.security</groupId>
                        <artifactId>spring-security-core</artifactId>
                        <version>${spring.security.version}</version>
                </dependency>

                <dependency>
                        <groupId>org.springframework.security</groupId>
                        <artifactId>spring-security-web</artifactId>
                        <version>${spring.security.version}</version>
                </dependency>

                <dependency>
                        <groupId>org.springframework.security</groupId>
                        <artifactId>spring-security-config</artifactId>
                        <version>${spring.security.version}</version>
                </dependency>

                <!-- jstl -->
                <dependency>
                        <groupId>javax.servlet</groupId>
                        <artifactId>jstl</artifactId>
                        <version>1.2</version>
                </dependency>
        </dependencies>

        <build>
                <finalName>SpringSec</finalName>
                <plugins>
                        <plugin>
                                <groupId>org.apache.maven.plugins</groupId>
                                <artifactId>maven-compiler-plugin</artifactId>
                                <version>3.1</version>
                                <configuration>
                                        <source>1.7</source>
                                        <target>1.7</target>
                                </configuration>
                        </plugin>
                </plugins>
        </build>
</project>

Una vez añadido esto, vamos a proceder a rellenar los ficheros de configuración que estarán contenidos en webapp/WEB-INF/. Estos serán: mvc-dispatcher-servlet.xml con la configuración de nuestras páginas, el spring-security.xml con la configuración relativa a la seguridad y, en este caso, nuestros credenciales de acceso, y el web.xml que, como en veces anteriores, contendrá nuestra configuración general.

mvc-dispatcher-servlet.xml

<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd">

        <context:component-scan base-package="com.wordpress.infow.controller" />

        <bean
                class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                <property name="prefix">
                        <value>/WEB-INF/pages/</value>
                </property>
                <property name="suffix">
                        <value>.jsp</value>
                </property>
        </bean>

</beans>

spring-security.xml

<beans:beans xmlns="http://www.springframework.org/schema/security"
        xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/security
        http://www.springframework.org/schema/security/spring-security-3.1.xsd">

        <http auto-config="true">
                <intercept-url pattern="/welcome*" access="ROLE_USER" />
                <form-login login-page="/login" default-target-url="/welcome"
                        authentication-failure-url="/loginfailed" />
                <logout logout-success-url="/logout" />
        </http>

        <authentication-manager>
                <authentication-provider>
                        <password-encoder hash="sha" />
                        <user-service>
                                <user name="svoboda" password="f2b14f68eb995facb3a1c35287b778d5bd785511"
                                        authorities="ROLE_USER" />
                        </user-service>
                </authentication-provider>
        </authentication-manager>

</beans:beans>

En este fichero vemos un par de cosas a tener en cuenta y que merece la pena pararse a nombrar. Bajo el elemento http del XML, podemos ver la configuración de acceso y de solicitud de nuestros credenciales. Los nodos dentro de esta sección son bastante autoexplicativos, así que no entraré en detalle. También podemos ver otra sección con el nombre de authentication-manager, esta sección contrendraá nuestros credenciales de acceso ya sea en texto plano, o como en este caso, cifrados mediante sha.

web.xml

<web-app id="WebApp_ID" version="2.4"
        xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
        http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

        <display-name>Spring Security Example</display-name>

        <!-- Spring MVC -->
        <servlet>
                <servlet-name>mvc-dispatcher</servlet-name>
                <servlet-class>
                        org.springframework.web.servlet.DispatcherServlet
                </servlet-class>
                <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
                <servlet-name>mvc-dispatcher</servlet-name>
                <url-pattern>/</url-pattern>
        </servlet-mapping>

        <listener>
                <listener-class>
                        org.springframework.web.context.ContextLoaderListener
                </listener-class>
        </listener>

        <context-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>
                        /WEB-INF/mvc-dispatcher-servlet.xml,
                        /WEB-INF/spring-security.xml
                </param-value>
        </context-param>

        <!-- Spring Security -->
        <filter>
                <filter-name>springSecurityFilterChain</filter-name>
                <filter-class>
                        org.springframework.web.filter.DelegatingFilterProxy
                </filter-class>
        </filter>

        <filter-mapping>
                <filter-name>springSecurityFilterChain</filter-name>
                <url-pattern>/*</url-pattern>
        </filter-mapping>

</web-app>

A parte de las configuraciones habituales, también podemos observar que tiene una sección para Spring Security con un filtro para la intercepción de peticiones y posterior muestra del login antes de servir las diferentes páginas.

Tras esto, vamos a implementar el controller para gestionar las distintas URLs asociadas a nuestro login (las definidas en el spring-security.xml). El contenido de este controller será el siguiente:

LoginController.java

@Controller
public class LoginController {

        @RequestMapping(value = "/welcome", method = RequestMethod.GET)
        public String printWelcome(ModelMap model, Principal principal) {

                String name = principal.getName();
                model.addAttribute("username", name);
                model.addAttribute("message", "Welcome to Spring Security World!");
                return "hello";

        }

        @RequestMapping(value = "/login", method = RequestMethod.GET)
        public String login(ModelMap model) {

                return "login";

        }

        @RequestMapping(value = "/loginfailed", method = RequestMethod.GET)
        public String loginerror(ModelMap model) {

                model.addAttribute("error", "true");
                return "login";

        }

        @RequestMapping(value = "/logout", method = RequestMethod.GET)
        public String logout(ModelMap model) {

                return "login";

        }
}

No creo que en esta ocasión haya que entrar en detalle sobre las anotaciones, ya que son comunes al resto de ejemplos de Spring que hemos hecho anteriormenre y no hay inguna nueva a la que merezca la pena hacer referencia.

Y finalmente, vamos a hacer las página JSP con el formulario en el que introducir nuestros credenciales y la página donde recibiremos el mensaje habitual en todos los ejmplos hasta ahora.

login.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
        <head>
                <title>Login Page</title>
                <style>
                        .errorblock {
                                color: #ff0000;
                                background-color: #ffEEEE;
                                border: 3px solid #ff0000;
                                padding: 8px;
                                margin: 16px;
                        }
                </style>
        </head>
        <body onload='document.f.j_username.focus();'>
                <h3>Login with Username and Password (Custom Page)</h3>

                <c:if test="${not empty error}">
                        <div class="errorblock">
                                Your login attempt was not successful, try again.<br /> Caused :
                                ${sessionScope["SPRING_SECURITY_LAST_EXCEPTION"].message}
                        </div>
                </c:if>

                <form name='f' action="<c:url value='j_spring_security_check' />"
                        method='POST'>

                        <table>
                                <tr>
                                        <td>User:</td>
                                        <td><input type='text' name='j_username' value=''></td>
                                </tr>
                                <tr>
                                        <td>Password:</td>
                                        <td><input type='password' name='j_password' /></td>
                                </tr>
                                <tr>
                                        <td><input name="submit" type="submit" value="Log in" /></td>
                                        <td><input name="reset" type="reset" value="Clean form"/></td>
                                </tr>
                        </table>

                </form>
        </body>
</html>

hello.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
        <head>
                <title>Message - Spring Security</title>
        </head>
        <body>
                <h3>Message : ${message}</h3>
                <h3>Username : ${username}</h3>

                <a href="<c:url value="/j_spring_security_logout" />" > Logout</a>

        </body>
</html>

Con esto ya tendríamos nuestro ejemplo en Spring Security funcionando. Como siempre, os dejo el código para que podáis echarle una ojeada y ejecutarlo en vuestros servidores.

Código SpringSecurity Hello World: SpringSecurity

Si tenéis alguna duda, animaos y preguntad. Nos vemos.

 
Deja un comentario

Publicado por en 16 julio, 2013 en JavaEE