Crear proyecto Servlet con Maven para Eclipse

Antes de comenzar, necesitas tener instalado Maven en tu equipo y el plugin de éste para el Eclipse ( pincha aquí para ver una introducción y vínculos de instalación) . A continuación, sigue los siguientes pasos:
  1. Accede a la consola y nos ubícate en el workspace del Eclipse.

  2. Ejecuta el siguiente comando: mvn archetype:create -DgroupId=nuestroservlet -DartifactId=miproyectoServlet -DarchetypeArtifactId=maven-archetype-webapp . En el parámetro DartifactID se indica el nombre del proyecto. Para Maven, todo proyecto ha de estar engloblado en un grupo, para ello usa el parámetro DgroupId.

  3. El comando anterior creará un nuevo directorio en tu workspace cuyo nombre coincide con el que le hayas puesto a tu proyecto (parámetro DartifactId). Accede a él. Podrás observar, que en él, hay un fichero llamado pom.xml, ¿ Te suena verdad ? :p.

  4. Lanza: mvn -Declipse.workspace="la ruta del workspace" eclipse:add-maven-repo. Cuidado! Lo que esta entrecomillado debes de poner la ruta del workspace. Esto añade una variable nueva (M2_REPO) al Eclipse para sepa donde esta el repositorio (puedes comprobarlo arrancando Eclipse y luego en Windows->Preferences->Classpath Variables).

  5. Si estas ubicado en la raiz del nuevo proyecto, lanza mvn eclipse:eclipse .

  6. Ya puedes cerrar la consola ya que se ha terminado de crear el proyecto Servlet. Arranca eclipse y abre un nuevo proyecto java existente.

  7. Crea tus Source Folder necesarios (por ejemplo: src/main/java , src/main/resources , src/main/webapp y src/test/java). Estos source folder han de tener concordancia con el fichero build.xml.

  8. Edita el fichero pom.xml y añade las dependencias y plugins necesarios para la futura aplicación web. Observa que en él se refleja el grupo y el artificio que le has puesto previamente. Una forma de editar el fichero pom.xml automáticamente, es activar maven en el eclipse (paso 9) y luego boton derecho sobre dicho fichero para añadir las dependencias y plugin. Un ejemplo sería:

    <?xml version="1.0" encoding="UTF-8"?><project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>nuestroservlet</groupId>
    <artifactId>miproyectoServlet</artifactId>
    <packaging>war</packaging>
    <name>miproyectoServlet Maven Webapp</name>
    <version>1.0-SNAPSHOT</version>
    <url>http://maven.apache.org</url>
    <build>
    <finalName>miproyectoServlet</finalName>
    <plugins>
    <!-- Necesario.Indicamos la versión del jre que utilizará
    el plugin maven para el eclipse.-->

    <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
    <source>1.5</source>
    <target>1.5</target>
    </configuration>
    </plugin>
    </plugins>
    </build>
    <dependencies>
    <!-- Necesario, ya que contiene las API de los Servlet.-->
    <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <version>2.4</version>
    <scope>compile</scope>
    </dependency>
    <!-- Necesario si usamos TDD con TestNG en vez de JUnit.-->
    <dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>5.1</version>
    <classifier>jdk15</classifier>
    <scope>test</scope>
    </dependency>
    <!--Necesario en caso de que se trabaje con el fichero build.xml
    de ANT. -->

    <dependency>
    <groupId>org.apache.maven</groupId>
    <artifactId>maven-ant-tasks</artifactId>
    <version>2.0.7</version>
    </dependency>
    </dependencies>
    </project>

  9. Activa Maven (boton derecho sobre el proyecto, Maven2->Enable).

  10. Haz un Update Source Folder.

  11. Inserta en la raiz del proyecto el fichero build.xml de ANT. En este haz de poner la ruta del Tomcat. Si no tienes ganas de crearte uno, haz un copy-paste desde otro proyecto (aplicación web) que lo tenga.

  12. DeployWar.

  13. Comprueba en el browser si todo ha salido con éxito (éste ha de mostrar Hello World!, que es el ejemplo que viene por defecto).

  14. A partir de aquí, modifica y crea tus propios servlet modificando previamente el fichero web.xml.

Todo esto ha sido sacado de las siguientes URL´s:

Hibernate con un ejemplo

El framework Hibernate es una herramienta de Mapeo objeto-relacional (ORM) para la plataforma Java ( NHibernate para la plataforma .Net) empleando para ello JPA (Java Persistence API). Esta herramienta nos permite manipular los datos del DBMS operando sobre objetos de nuestra aplicación, siendo éstos persistentes y cumpliendo las características de la OOP.

Para utilizar dicho framework, lo primero que hemos de hacer es descargarnos obviamente las API´s correspondientes ( Descargar núcleo de Hibernate). Los ficheros de configuración estas basados en XML , pero si queremos deshacernos de ello y usar anotaciones, además, hemos de descargarnos la siguiente API: Descargar anotaciones de Hibernate.

Descomprimimos el fichero, y comprobamos que por defecto, este ya trae un ejemplo ya hecho. Lo único que nos interesa son los .jars y los ficheros de configuración.

Creamos un nuevo proyecto java en el eclipse y una vez creado, creamos dos sources folders:
  1. src en donde colocaremos nuestros códigos fuentes.
  2. test para realizar las pruebas, ya que aplicaremos TDD.

A continuación, creamos un nuevo directorio llamado lib, en donde colocaremos nuestras librerías, siendo en este caso los .jars de Hibernate (estos son los contenidos en el directorio lib del paquete extraido y el .jar del directorio raíz de éste). También hemos de incluir obligatoriamente en lib el driver JDBC según la base de datos con la que vayamos a trabajar (MySQL según ejemplo). Opcionalmente, pero recomendable, pondremos las librerías EasyMock, TestNG... Luego refrecamos nuestro proyecto y añadimos todas las librerías al build path.

En cuanto a los ficheros de configuración, copiamos los ficheros hibernate.cfg.xml y log4j.properties ubicados en doc\tutorial\src y lo pondremos en nuestro source folder src. Por mayor comodidad, usaremos ant en nuestro proyecto, así que copiaremos build.xml del directorio doc\tutorial y lo pondremos en el raiz de nuestro proyecto.Configuración de Hibernate (hibernate.cfg.xml) para MySQL :

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

<session-factory>

<!-- API´s del driver JDBC-->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>

<!-- URL de la base de datos, junto parámetros correspondientes -->
<property name="connection.url">
jdbc:mysql://localhost/myhibernate?createDatabaseIfNotExist=true
</property>

<!-- Usuario y contraseña de la base de datos -->
<property name="connection.username">root</property>
<property name="connection.password">root</property>

<!-- Carga de transacciones, relacionado con el rendimiento de la BB.DD. -->
<property name="connection.pool_size">1</property>

<!-- Versión de la BB.DD. En este ejemplo,versión 5 de MySQL-->
<property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>

<!-- Gestión automática de las sesiones de Hibernate a través de hilos-->
<property name="current_session_context_class">thread</property>

<!-- Caché de los datos ya extraidos de la BB.DD. -->
<property name="cache.provider_class">
org.hibernate.cache.NoCacheProvider
</property>

<!-- Muestra sentencias SQL por la consola -->
<property name="show_sql">true</property>

<!-- Relacionado con el arranque.
También podría ser create-drop(borra antes el catálogo) -->

<property name="hbm2ddl.auto">create</property>

<!-- Mapeo de objetos persistentes -->
<mapping resource="Ruta/Fichero.hbm.xml"/>

</session-factory>

</hibernate-configuration>


Si tienes algún problema a la hora de configurar el driver JDBC , tal vez te sirva de ayuda este fichero (No abrir con bloc de notas).

En el fichero log4j.xml, podemos configurar el tipo de salida que muestre por la consola (recordamos que los principales son, de mayor prioridad a la de menos: DEBUG, INFO, WARN y ERROR).

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">

<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%p - %C{1}.%M(%L)%m%n"/>
</layout>

</appender>

<logger name="net.sf.ehcache">
<level value="ERROR"/>
</logger>

<logger name="org.apache">
<level value="WARN"/>
</logger>

<logger name="org.hibernate">
<level value="INFO"/>
</logger>

<!-- Suppress warnings from Commons Validator -->
<logger name="org.apache.commons.validator.ValidatorResources">
<level value="ERROR"/>
</logger>

<!-- Suppress invalid warning messages from JSF -->
<logger name="org.apache.myfaces.shared_impl.renderkit.html">
<level value="ERROR"/>
</logger>

<logger name="nombre.paquete">
<level value="INFO"/>
</logger>

<root>
<level value="WARN"/>
<appender-ref ref="CONSOLE"/>
</root>

</log4j:configuration>


Todo lo comentado, ha sido relacionado con la instalación y configuración de hibernate, ya va siendo hora de ir al grano ....

Toda aplicación, necesita un único objeto perteneciente a la clase SessionFactory, que como su nombre indica se trata de una fábrica de sesiones. Luego, le pediremos sesiones a éste, mediante los cuales, podremos hacer transacciones con la base de datos. Veamos un ejemplo de como se crea :


package es.nuwi.hotel.util;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtil {


public static SessionFactory getSessionFactory() {

SessionFactory sessionFactory;
try {

// Create the SessionFactory from hibernate.cfg.xml
sessionFactory = new Configuration().configure()
.buildSessionFactory();

} catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
System.err.println("Error al crear la factoría de sesiones." + ex);
throw new ExceptionInInitializerError(ex);
}
return sessionFactory;

}

}

El ejemplo que usaremos tendrá la siguientes asociaciones-relaciones:

Como observamos un hotel va a tener n empleados y n habitaciones. Cada empleado puede trabajar en más de un hotel. Una habitación pertenece a un hotel y suponemos que en una habitacion sólo va a ver un único cliente. El cliente solo podrá alquilar una única habitación. En nuestro ejemplo, usaremos asociaciones bidireccionales en vez de unidireccionales.

Creamos los POJOS, los cuales serán objetos persistentes. Éstos han de llevar obligatoriamente una propiedad de tipo Long :

Fichero Hotel.java :

package es.nuwi.hotel.objpersistentes;

import java.util.HashSet;
import java.util.Set;


public class Hotel {

private Long id;
private String nombreHotel;
private Set<Empleados> empleados=new HashSet<Empleados>();
private Set<Habitacion> habitaciones=new HashSet<Habitacion>();


public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getNombreHotel() {
return nombreHotel;
}

public void setNombreHotel(String nombre) {
this.nombreHotel = nombre;
}

public Set<Empleados> getEmpleados() {
return empleados;
}

public void setEmpleados(Set<Empleados> empleados) {
this.empleados = empleados;
}

public Set<Habitacion> getHabitaciones() {
return habitaciones;
}

public void setHabitaciones(Set<Habitacion> habitaciones) {
this.habitaciones = habitaciones;
}

}

Fichero Empleado.java :

package es.nuwi.hotel.objpersistentes;

import java.util.Set;


public class Empleado {

private Long id;
private String dniEmpleado;
private Set<Hotel> hoteles;


public String getDniEmpleado() {
return dniEmpleado;
}

public void setDniEmpleado(String dniEmpleado) {
this.dniEmpleado = dniEmpleado;
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getNombreEmpleado() {
return dniEmpleado;
}

public void setNombreEmpleado(String nombreEmpleado) {
this.dniEmpleado = nombreEmpleado;
}

public Set<Hotel> getHoteles() {
return hoteles;
}

public void setHoteles(Set<Hotel> hoteles) {
this.hoteles = hoteles;
}

}


Fichero Habitacion.java :

package es.nuwi.hotel.objpersistentes;

public class Habitacion {

private Long id;
private Hotel hotel;
private CLiente cliente;


public CLiente getCliente() {
return cliente;
}

public void setCliente(CLiente cliente) {
this.cliente = cliente;
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public Hotel getHotel() {
return hotel;
}

public void setHotel(Hotel hotel) {
this.hotel = hotel;
}

}

Fichero Cliente.java :

package es.nuwi.hotel.objpersistentes;

import java.util.Calendar;


public class CLiente {

private Long id;
private String dniCliente;
Calendar fechaAlquiler;
Habitacion habitacion;


public Habitacion getHabitacion() {
return habitacion;

}


public void setHabitacion(Habitacion habitacion) {
this.habitacion = habitacion;

}


public Long getId() {
return id;
}


public void setId(Long id) {
this.id = id;
}


public String getDniCliente() {
return dniCliente;
}


public void setDniCliente(String dniCliente) {
this.dniCliente = dniCliente;
}


public Calendar getFechaAlquiler() {
return fechaAlquiler;
}


public void setFechaAlquiler(Calendar fechaAlquiler) {
this.fechaAlquiler = fechaAlquiler;
}
}

Configuramos las asociaciones antes mencionadas. Para tener una cierta concordancia, los nombres de estos ficheros coinciden con los de la clase y cuya extensión es .xbm.xml, aunque no tiene siempre porque ya que en un mismo fichero pueden asociarse varias clases y en cuanto a la extensión, ésta puede ser cambiada. Para que no de ningún error, la propiedad tipo Long ha de ser la primera :

Fichero Hotel.hbm.xml :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
<class name="es.nuwi.hotel.objpersistentes.Hotel" table="Hotel">
<id name="id" column="Hotel_id" unsaved-value="null">
<generator class="native" />
</id>
<property name="nombreHotel" column="nombreHotel" not-null="true"/>

<!-- ONE-TO-MANY -->
<set name="habitaciones" cascade="all" >
<key column="hotel_id"/>
<one-to-many class="es.nuwi.hotel.objpersistentes.Habitacion"/>
</set>

<!-- MANY-TO-MANY. SE CREA UNA TABLA INTERMEDIA -->
<set name="empleados" cascade="all" table="empleados_hoteles">
<key column="Hotel_id"/>
<many-to-many class="es.nuwi.hotel.objpersistentes.Empleado"
column="Empleado_id" />
</set>
</class>
</hibernate-mapping>

Fichero Empleado.hbm.xml :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

<class name="es.nuwi.hotel.objpersistentes.Empleado"
table="Empleados">
<id name="id" column="Empleado_id" unsaved-value="null">
<generator class="native" />
</id>
<property name="dniEmpleado" column="dniEmpleado" not-null="true"/>
<!-- MANY-TO-MANY.

SE CREA UNA TABLA INTERMEDIA, ES LA MISMA QUE LA DE ANTES. -->

<set name="hoteles" cascade="all" table="empleados_hoteles">
<key column="Empleado_id"/>
<many-to-many class="es.nuwi.hotel.objpersistentes.Hotel"
column="Hotel_id" />
</set>
</class>
</hibernate-mapping>

Fichero Habitacion.hbm.xml :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
<class name="es.nuwi.hotel.objpersistentes.Habitacion"
table="Habitacion">
<id name="id" column="Habitacion_id" unsaved-value="null">
<generator class="native" />
</id>
<!-- MANY-TO-ONE -->
<many-to-one name="hotel" column="hotel_id"
class="es.nuwi.hotel.objpersistentes.Hotel" />
<!-- ONE-TO-ONE -->

<one-to-one name="cliente" property-ref="habitacion" />
</class>
</hibernate-mapping>

Fichero Cliente.hbm.xml :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
<class name="es.nuwi.hotel.objpersistentes.Cliente"
table="Clientes">
<id name="id" column="Cliente_id" unsaved-value="null">
<generator class="native" />
</id>
<property name="dniCliente" column="dniCliente" not-null="true" />
<property name="fechaAlquiler" type="java.util.Date"
column="fechaAlquiler" not-null="true" />

<!-- MANY-TO-ONE, AUNQUE REALMENTE VIENE DE UN ONE-TO-ONE -->
<many-to-one name="habitacion" column="HabitacionCliente"
unique="true" not-null="true"/>
</class>
</hibernate-mapping>

Estas configuraciones han sido sacadas de la siguiente URL: http://www.hibernate.org/hib_docs/reference/en/html/associations.html.Veamos el reflejo del ejemplo sobre el DBMS:

  1. Al crear una relación MANY-TO-MANY se ha creado una nueva tabla ( empleados-hoteles ) con dos campos primarios (hotel_id y empleado_id) los cuales son además claves ajenas (foreign key) de las tablas hotel y empleado respectivamente. Recordamos que una clave ajena apunta a los campos primarios de otra tabla.

  2. Al hacer uso de un ONE-TO-MANY y MANY-TO-ONE, de este segundo (many-to-one, es decir, de la tabla habitacion) se crea una columna sienda esta clave ajena de la clave primaria de la primera ( one-to-many, es decir,de la tabla hotel ) .

  3. En cuanto a ONE-TO-ONE , es exactamente igual igual que el anterior, con la única diferencia de que la clave ajena es además unique (no admite valores repetidos para esa columna). Según el ejemplo, se crea un nuevo campo de la tabla cliente la cual referencia a la clave primaria de la tabla habitacion siendo además único para esta columna.

Por último, lo único que nos queda es mapear los objetos persistentes. Para ello, añadimos las siguientes entradas en el fichero hibernate.cfg.xml, siendo estas entradas la ruta más el nombre en la que se encuentran los ficheros .hbm.xml de nuestro proyecto :

<mapping resource="es/nuwi/hotel/objpersistentes/Hotel.hbm.xml"/>
<mapping resource="es/nuwi/hotel/objpersistentes/Empleado.hbm.xml"/>
<mapping resource="es/nuwi/hotel/objpersistentes/Cliente.hbm.xml"/>
<mapping resource="es/ " / " /objpersistentes/Habitacion.hbm.xml"/>

Otra característica de este framework, es que podemos crear un fichero llamado import.sql ( ha de llamarse así obligatoriamente ) el cual contiene sentencias SQL (DDL,LMD,...). Esto es de gran utilidad ya que podemos insertar tuplas en nuestro DBMS y hacer pruebas para ver el funcionamiento de nuestra aplicación. En nuestro ejemplo, insertaremos nuevas tuplas :


insert into Hotel(Hotel_id,nombreHotel) values (1,'Hotel LG')
insert into Hotel(Hotel_id,nombreHotel) values (2,'Hotel Nuwi')

insert into Empleados (Empleado_id,dniEmpleado) values (1,'Mawi')
insert into Empleados (Empleado_id,dniEmpleado) values (2,'Ana')
insert into Empleados (Empleado_id,dniEmpleado) values (3, 'María')

insert into Empleados_Hoteles (Hotel_id,Empleado_id) values (1,1)
insert into Empleados_Hoteles (Hotel_id,Empleado_id) values (1,2)
insert into Empleados_Hoteles (Hotel_id,Empleado_id) values (2,3)

insert into Habitacion (Habitacion_id,Hotel_id) values (1,1)
insert into Habitacion (Habitacion_id,Hotel_id) values (2,1)
insert into Habitacion (Habitacion_id,Hotel_id) values (3,2)

insert into Clientes (Cliente_id,dniCliente,fechaAlquiler,HabitacionCliente) values (1,'28765342H','2008-1-19 11:15',1)
insert into Clientes (Cliente_id,dniCliente,fechaAlquiler,HabitacionCliente) values (2,'49382718L','2008-2-21 14:45',2)
insert into Clientes (Cliente_id,dniCliente,fechaAlquiler,HabitacionCliente) values (3,'27272129P','2008-4-19 19:30',3)

Hibenate soporta 3 tipos de herencia:

  • Tabla para clase padre e hijas (se admiten valores nulos).
  • Tabla por cada subclase (no se admiten valores nulos).
  • Tabla por cada clase concreta (No abstracta), tanto padre como hijas.(no valores nulos).

He aquí un ejemplo del primer caso: La clases Cliente tendrá dos subclases, los que pagen en efectivo, donde guardaremos el importe y los que pagen por tarjeta de crédito, donde guardaremos el número de dicha tarjeta :

Creamos los POJO´s de las dos subclases:

Fichero ClienteEfectivo :

package es.nuwi.hotel.objpersistentes;

public class ClienteEfectivo extends Cliente{
private int cantidadEfectivo;

public int getCantidadEfectivo() {
return cantidadEfectivo;
}

public void setCantidadEfectivo(int efectivo) {
this.cantidadEfectivo = efectivo;
}
}

Fichero ClienteTarjeta:

package es.nuwi.hotel.objpersistentes;

public class ClienteTarjeta extends Cliente{
private String numeroTarjeta;

public String getNumeroTarjeta() {
return numeroTarjeta;
}

public void setNumeroTarjeta(String numeroTarjeta) {
this.numeroTarjeta = numeroTarjeta;
}
}

Modificamos el fichero Cliente.hbm.xml. Para ello, es necesario crear una nueva columna en la tabla Cliente (discriminador tipoCliente, éste no esta reflejado en ningún campo de la clase), situada obligatoriamente como segunda posición para que no de ningún error (recordamos que la primera es el Primary Key de tipo Long). Dicho discriminador ha de ser de tipos String y no puede contener valores nulos. Luego se especifican los nuevos campos de las subclases pudiendo éstos contener valores nulos y el valor del discriminador que van a usar. El fichero quedaría de la siguiente manera :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
<class name="es.nuwi.hotel.objpersistentes.Cliente"
table="Clientes">
<id name="id" column="Cliente_id" unsaved-value="null">
<generator class="native" />
</id>
<!-- DISCRIMINADOR-->
<discriminator column="tipocliente" not-null="true" type="string"/>
<!--Resto de propiedades de la clase madre -->
<property name="dniCliente" column="dniCliente" not-null="true"/>
<property name="fechaAlquiler" type="java.util.Date"
column="fechaAlquiler" not-ull="true"/>
<!-- MANY-TO-ONE, AUNQUE REALMENTE VIENE DE UN ONE-TO-ONE -->

<many-to-one name="habitacion" column="HabitacionCliente"
unique="true" not-null="true"/>
<!-- ESPECIFICAMOS LAS SUBCLASES -->
<subclass name="es.nuwi.hotel.objpersistentes.ClienteEfectivo"
discriminator-value="Efectivo">
<property name="cantidadEfectivo" column="cantidadEfectivo"
not-null="false"/>
</subclass>
<subclass name="es.nuwi.hotel.objpersistentes.ClienteTarjeta"
discriminator-value="Tarjeta">
<property name="numeroTarjeta" column="numeroTarjeta"
not-null="false"/>
</subclass>
</class>
</hibernate-mapping>

Como habrás observado, no hemos creado ningún .hbm.xml para cada subclase ya que lo hemos especificado en el de la clase madre. Será este el que esté mapeado en hibernate.cfg.xml.

Si tienes dudas, tal vez este foro te sirva de ayuda.

Tutorial sobre las API´s de reflexión

Pinchá aquí para accer al manual sobre las API´s de reflexión.

SSL bajo Tomcat

Cuando tenga time lo pondré.

Mostrar sentencias SQL de Hibernate por la consola en Spring

Para ver las sentecias SQL que Hibernate ejecuta sobre la BB.DD. por la consola, hemos de añadir la siguiente propiedad <prop key="hibernate.show_sql">true</prop> en el fichero de configuración de Hibernate en Spring (applicationContext-hibernate.xml ), ubicada en la siguiente posición:


<property name="hibernateProperties">
<props>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>

Vínculo Asociaciones-Relaciones en Hibernate (xml)

Pincha aquí para ver la documentación sobre la configuración de relaciones entre entidades, empleando para ello el frameworks Hibernate (configuración basada en xml, no en anotaciones).

Anotaciones @RequestMapping y @RequestParam en Spring MVC y la clase ModelMap

Con la anotación @RequestMapping recogemos la petición del cliente, mientras que con @RequestParam los parámetros ( para evitar posibles errores, los recogemos como String). En este último, además del valor, podemos indicar si es obligatorio o no con el atributo required (por defecto es false). Para devolver el modelo, hacemos uso de la clase ModelMap añadiéndole atributos. Veamos un ejemplo :

@RequestMapping(value="/editalibro.html")
public String dameFormularioEdicionLibro(ModelMap modelo,
@RequestParam(value="idLibro",required=true) String idLibro)
{
// Devolvemos un modelo a la capa vista (.jsp normalmente)
modelo.addAttribute("libro",libroManager.getDetalleLibro(idLibro));
return "edicionLibro"; //Retornamos al browser edicionLibro.jsp
}

Ambas anotaciones y clase, se usan dentro del controlador.

Si indicamos que un parámetro sea requerido y no es puesto en la URL, es lanzada una excepción, la cual deberemos controlar para hacer la vista más agradable al usuario.

Creación Bean de Sesión con Estado (Statefull) en Spring

Antes de todo, recordemos que es un Bean: Se trata de una clase normal y corriente, con sus propiedades y cuyos únicos métodos son getters/setters, teniendo obligatoriamente el contructor por defecto o sin parámetros ( este es creado automáticamente siempre que no se cree o se sobrecarge otro con parámetros, en este último caso, hemos de crearlo nosotros explícitamente).

En nuestro caso, el bean que trataremos cumple todas las características mencionadas arriba, aunque además, puede tener más métodos de los ya mencionados (getters/setters).

Decimos que es de Sesión con Estado ya que guarda informacion relativa de cada usuario, es decir, cada cliente va a tener su propio bean, hayase o no registrado previamente. Un ejemplo de todo esto es cuando el usuario abre nuestra página web desde un browser e ingresa productos al carrito de la compra. Otros ejemplos son: ver las operaciones que ha efectuado el usuario, número de veces que ha refrescado la página (siempre que ésta no esté en caché), saber si se ha registrado un usuario...

Veamos los pasos a seguir, como ejemplo tomaremos el carrito de la compra:
  1. Implementamos el bean:


    package org.appfuse.model;

    import java.util.ArrayList;
    import java.util.List;

    public class CarritoCompra {

    private List<libro> carrito = new ArrayList<libro>();

    public List<libro> getCarrito() {
    return carrito;
    }

    public void setCarrito(List<Libro> carrito) {
    this.carrito = carrito;
    }

    public void añadirLibro(Libro libro) {
    if (!carrito.contains(libro))
    carrito.add(libro);
    }

    public void eliminarLibro(Libro libro) {
    carrito.remove(libro);
    }
    }

  2. Utilizamos la anotación @Autowired para aplicar la inyección de dependencias a nuestra aplicación, ya sea desde un controlador u otra clase. Observa que esto también es aplicable a propiedades declaradas como privadas :



    @Autowired
    private CarritoCompra carritoCompra;

  3. Por último, indicamos al Spring que tenemos un nuevo bean de sessión con estado, por lo que a la declaración típica de bean en el fichero applicationContext.xml le vamos a añadir el valor scope="session", y dentro de ésta <aop:scoped-proxy/>:



    <bean id="carritoCompra" class="org.appfuse.model.CarritoCompra"
    scope="session">
    <aop:scoped-proxy/>
    </bean>

Logging en appfuse (spring)

Para imprimir por consola utilizando el Log de apache, hemos de hacer lo siguiente:

  1. Utilizamos en la clase deseada el siguiente objeto.

    • protected final Log logger = LogFactory.getLog(getClass());

  2. Hay que importar en nuestro archivo las siguientes clases:

    • import org.apache.commons.logging.Log;

    • import org.apache.commons.logging.LogFactory;

  3. Utilizarlo dentro de nuestro código sustituyendo las lineas:

    • System.out.println("mensaje"); por ...

    • logger.debug("userId set to: " + variable o llamada a función); donde el objeto logger nos permite indicar varios niveles de logging, cuya jeraquía de mayor a menor es: DEBUG, INFO, WARN, ERROR.

  4. Configurar el archivo /src/main/resources/log4.xml para indicarle los niveles que queremos imprimir en consola (es posible aplicar a los distintos paquetes de nuestro proyecto un tipo de logging distinto a cada uno) .

Nota: Antes hemos mencionado que existe una jerarquía en los niveles de logging, esto consiste en que si usamos el loggin INFO, se mostrarán también los mensajes de WARN y ERROR, mientras que los de DEBUG no lo harán.

Pienso que esto es sencillo, que no tiene ningún misterio y que no merece la pena poner un ejemplo, así que en caso de duda, hacer un comentario.

Internalización ( i18n ) en AppFuse

Para que nuestra aplicación appfuse pueda utilizarse en varios idiomas, tenemos que definir las posibles claves en forma de clave/valor del fichero messages.properties ubicado en /src/main/resources/

Ejemplo=> webapp.clave=Estamos aprendiendo Internalización.

Cada idioma nuevo deberá tener un messages.properties diferente, de forma que si tenemos idioma inglés deberemos tener messages_en.properties, y en español messages_es.properties. En caso de que haya sublenguajes, éstos irán en mayúsculas, veamos un ejemplo con Perú: messages_es_PE.properties .

Después, desde nuestro jsp podemos referenciar dicha clave con el objeto message, es decir ( <fmt:message key="webapp.clave"></fmt:message> ), y según la configuración del navegador de usuario que consulte la aplicación ( por ejemplo, en firefox es Herramientas=> Opciones=> Avanzado=> General=> Idiomas=>Elegir ) obtendrá el idioma correspondiente.

Todo esto funcionará si nuestro framework está bien configurado, es decir, si el archivo /src/main/webapp/WEB-INF/dispatcher-servlet.xml ha declarado el bean: bean id = "messageSource" class = "org.springframework.context.support. ResourceBundleMessageSource" con el basename = messages .
En caso de que no hayamos declarado un idioma para nuestra aplicación, por defecto pillará messages.properties .

Si quisieramos tener en nuestra web los típicos botoncitos o iconos para cambiar explícitamente el lenguaje a usar, aplicamos JSTL jugando con ello gracias a un parámetro (idioma según nuestro ejemplo) y cuyo ámbito va a ser de sesión. He aquí las líneas que debemos agregar a nuestro .jsp :


<c:if test="${param['idioma']!=null}">
<fmt:setLocale value="${param['idioma']}" scope="session"/>
</c:if>

Ejemplo AppFuse Light 1.8.1 con un DBMS

Cuando tenga time , subiré el ejemplo.

Instalación AppFuse-Light 1.8

Antes de comenzar, ten instalado una base de datos MySQL, Tomcat, Maven y Ant. A continuación, sigue los siguientes pasos:

  1. Descomprime dicho archivo en workspace del eclipse.

  2. Abre la consola y desplázate hacia el directorio descomprimido situado en el workspace.

  3. Opcional: En caso de que trabajes con un repositorio local u otro remoto, edita el archivo /pom.xml de Maven y sustituiye http://download.java.net/maven/2 por href=http://...

  4. Ejecuta ant new ( cuando solicite el nombre aplicación inserta el deseado).

  5. Desciende un nivel, verás que hay un directorio con el nombre que le hayas puesto a tu proyecto, accede a él. El otro, el archivo .zip descomprimido, lo dejaremos por si necesitamos crear nuevos proyectos.

  6. Para generar el proyecto de eclipse, utilizamos Maven:

    • mvn eclipse:eclipse . Esto sirve para que prepare el entorno, como por ejemplo el .proyect, el .classpath , ...
    • mvn eclipse:eclipse -DdownloadSources=true . Se descargarán las librerías necesarias para el proyecto.
    • mvn -Declipse.workspace="La ruta de tu workspace" eclipse:add-maven-repo . Esta línea añade una variable nueva (M2_REPO) al Eclipse.

  7. Crea en de eclipse un nuevo proyecto java existente.

  8. Preparar el despliegue de la aplicación con el tomcat de nuestro equipo y la conexion a datos (mysql):
    • Edita /build.xml propiedad server.home y pon la dirección del Tomcat.
    • Edita src/main/resources/jdbc.properties y ponle el nombre de usuario y contraseña de la base de datos MySQL.
  9. Utiliza el archivo ant (build.xml) del proyecto para construir, desplegar ... En especial, utiliza un DeployWar.

*** Todo esto esta sacado de la siguiente URL: https://appfuse-light.dev.java.net/

Creación proyecto Spring MVC Basic. Gracias Maven!

Antes de seguir leyendo este artículo, debes tener instalado MySQL en tu computadora. Una vez que ya lo tengas instalado, sigue los siguientes pasos:
  1. Abre la consola ( Desde Windows: Inicio->Ejecutar->Escribimos "cmd"), y una vez abierta la ventana desplázate hacia el directorio del workspace del Eclipse.

  2. Ejecuta el siguiente comando para que Maven se descargue las librerías necesarias de Spring MVC Basic en el repositorio local que tengas puesto en el fichero de configuración settings.xml de este (el valor del atributo DartifactID puedes cambiarlo, es el nombre que le darás a tu proyecto):

    mvn archetype:create
    -DarchetypeGroupId=org.appfuse.archetypes
    -DarchetypeArtifactId=appfuse-basic-spring
    -DremoteRepositories=http://static.appfuse.org/releases
    -DarchetypeVersion=2.0.1
    -DgroupId=com.mycompany.app
    -DartifactId=SpringMVCBasic


  3. El comando anterior creará un nuevo directorio en tu workspace cuyo nombre coincide con el que le hayas puesto a tu proyecto. Accede a él. Podrás observar, que en él, hay un fichero llamado pom.xml, ¿ Te suena verdad ? :p.

  4. Poner al final del fichero pom.xml del proyecto el nombre de usuario y la contraseña de la base de datos MySQL. Servirá para más adelante (paso 7 en concreto).

  5. Ahora, ejecuta lo siguiente para que se generen los ficheros del proyecto ( .project, .classpath ... ), los ficheros de configuración y se descarguen las herramientas para la creación del proyecto (ten paciencia, es una de las claves del buen programador): mvn eclipse:eclipse .

  6. A continuación, lanza mvn -Declipse.workspace="la ruta del workspace" eclipse:add-maven-repo. Cuidado! Lo que esta entrecomillado debes de poner la ruta del workspace. Esto añade una variable nueva (M2_REPO) al Eclipse para sepa donde esta el repositorio.

  7. Lanza: mvn install . Se descargaran todas las dependencias asociadas al proyecto y lo dejará preparado. Si te da algún error, relacionado con el Tomcat, como me pasó a mí, descárgatelo desde aquí (Apache Tomcat version 6.0.14). Asegúrate que la versión a descargar coincide con la que te ha dado el error. Una vez descargado, copia el .zip en C:\Documents and Settings\[NombreUsuario]\Configuración local\Temp\cargo\installs.

  8. Para hacer un war, deploy y ver su funcionamiento, haz un mvn jetty:run-war. También se descargarán más librerías. Jetty es un servidor (como el tomcat) incorporado en el proyecto. Pincha aquí para ver si todo a sido correcto.
  9. Agrega en el Eclipse el proyecto java existente.

  10. Por último, y por mayor comodidad, instálate el plugin Eclipse. Pincha aquí para ver la guía de instalación u aquí para ver una demo de su funcionamiento.

Todo esto esta sacado de la siguiente URL: http://appfuse.org/display/APF/Home . Espero que le haya sido de ayuda! :)

SVN vs VCS

Subverion( SVN) y Concurrent Versions System (CVS) son sistemas de control de versiones basadas en la arquitectura cliente-servidor.

Diferencia: En SVN, todos los archivos tienen el mismo número de revisión, mientras que con VCS eso no ocurre (cada archivo tiene su propio número de revisión independiente).

Cada proyecto se almacena en un repositorio, que no es más que un directorio especial del disco duro donde se almacenan los ficheros del proyecto.

¿ Cómo crear un repositorio SVN en Google y utilizarlo con Eclipse ? Para ello, hemos de seguir los siguientes pasos:
  1. Entrar en la dirección http://code.google.com/hosting/ .
  2. Click en new proyect.
  3. Rellenar todos los campos que nos pide el formulario de proyecto nuevo.
  4. Click en ficha source y desde el apartado command-line access copiamos la dirección https. Ejemplo: https://nombreDeNuestroProyecto.googlecode.com/svn/trunk/ .
  5. Hacemos click en googlecode.com password y obtendremos nuestro password.
  6. Desde eclipse:

  • Menu window>show view>other>svn repository.
  • En la ventana de svn repository botón derecho del ratón y seleccionar nuevo repositorio location.
  • Url=https://nombreDeNuestroProyecto.googlecode.com/svn/trunk/ .
  • Usuario=cuentaUsuarioGMAIL (no incluir @gmail.com, solo nombreUsuario).
  • Clave=la generada anteriormente en googlecode.com password.
  • Para conectar nuestro código con subversion, botón derecho sobre la carpeta de proyecto a Controlar->Team->Share Project e indicamos la url de antes.

Principales operaciones de SVN:

  • Cada vez que queramos subir nuesrtro código al subversion:
    botón derecho->team->commit
  • Cuando queramos bajarnos los archivos o modificaciones del subversion a nuestro equipo(debe haber variado el número de revisión):
    botón derecho->team->update
  • Cuando queremos bajarnos los archivos, haya habido o no alguna modificación, es decir, haya o no variado el número de revisión:
    botón derecho->team->revert

JBoss Seam. Primeros pasos

JBosS SEAM es un framework para desarrollar aplicaciones J2EE sobre el servidor de aplicaciones JBOSS. Más adelante pondré los pasos a seguir.

Apache MAVEN

Apache Maven es una herramienta cuya funcionalidad es parecida a la de Ant, permite compilar, realizar distribuciones,... pero con gran la diferencia que trata de forma automática las dependencias del proyecto, es decir, se encarga de gestionar las dependencias de las librerías. Esto último es de gran importancia ya que libera al programar de buscar las dependencias asociadas al proyecto. Por fín!!, se acabaron las comeduras de tarro que alguna u otra vez nos habrán dado. Maven trata los proyectos como objetos gracias a un fichero xml llamado POM.xml(Project Object Model).

Objetivos Maven:
  • Repositorio local: Por defecto en window esta ubicado en: C:\Documents and Settings\[NombreUsuario]\.m2 . Puede cambiarse en el fichero settings.xml del direcotorio config.

  • Generacion automática de proyectos: Struts, Spring,...
  • Despliegue de proyectos de forma automática : Actualiza los source folder, es decir, se encarga de las dependencias de las librerías antes mencionadas.

Otra característica de Maven, es que se puede lanzar desde la consola.

Pincha aquí para tener instalado Maven en 5 minutos.
Pincha aquí para ver una demo de la instalación del plugin en el Eclipse.
Pincha aquí para ver una demo de su funcionamiento.
Pincha aquí para ver una guía de Maven en español.

Nota: EL fichero POM.xml siempre ha de estar en la raíz del proyecto.

MVC (Modelo Vista Controlador )

El patrón modelo vista controlador ( MVC en adelante ) es una arquitectura de software donde separa 3 componentes distintos en una aplicación: los datos, la interfaz de usuario, y la lógica de negocio(control).
  1. Modelo: Representa la parte fuerte de la aplicación, es decir, todo aquello con lo que el sistema opera. Se encarga de ejecutar o de llevar a cabo los servicios o eventos dictados por el controlador e interactuar si es necesario con la bases de datos (capa de datos) aplicando para ello persistencia.


  2. Vista: Interfaz que percibe el usuario, mediante el cual interactua.


  3. Controlador (Interceptor): Se situa entre los dos anteriores, recibe las peticiones por parte del usuario e inicializa los servicios o eventos correspondientes a dicha petición. Devuelve un modelo a la capa de vista (.jsp,...).

He aquí un pequeño esquema del patrón MVC:

Java Bean

Un Bean es una clase (sin nada en especial) compuesta por propiedades y métodos getters y setters además de tener un constructor público sin parámetros.

Ejemplo de un Bean:



package es.nuwi.ejemplo.bean


public class EjemploBean{


private char caracter;


public char getCaracter(){
return caracter;
}


public void getCaracter(char caracter){
this.caracter=caracter;
}
}

Anotaciones

Una anotación en Java es una forma de añadir metadatos al código fuente en tiempo de ejecución jugando con ellas las API´s de reflexión ( java.lang.reflect ). Estas son fundamentales para los EJB3 ya que con ellas indicamos el tipo de bean, forma de persistencia,..., recordamos que un EJB3 es un "POJO + @ (anotación)". Otra características de las anotaciones es que posibilita el control sobre los aspectos de la programación orientada a Aspectos (AOP), como ejemplo la seguridad.

Para que una anotación sea detectable en tiempo de ejecución se ha de hacer uso de la siguinete anotación: @Retention(value=RetentionPolicy.RUNTIME).

Las anotaciones pueden aplicarse tanto a clases como a propiedades, métodos...

Las Anotaciones son declaradas igual que las interfaces con la única excepción de que lleva precedico el caracter @. Veamos un ejemplo :


//Creamos una clase tipo enumerado.


package es.ejemplo.anotacion;


public enum TipoUsuario {
cliente,administrador
}

//Creamos una anotación.


package es.ejemplo.anotacion;


import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;


/*La linea siguiente es obligatoria para que sea detectable en tiempo de ejecución.*/
@Retention(value=RetentionPolicy.RUNTIME)
public @interface AnotacionUsuario {
TipoUsuario tipo(); //Se trata de un atributo de la anotación.
}

//Aplicamos la anotación a una clase de ejemplo.


package es.ejemplo.anotacion;


@AnotacionUsuario(tipo=TipoUsuario.cliente)
public class ExisteAnotacion {

//Propiedades y métodos a implementar...
}

//Comprobamos que realmente existe la anotación.


package es.ejemplo.anotacion;


import org.testng.annotations.Test;


public class TestAnotacion{


@Test
public void pruebaExisteAnotacion(){
if (ExisteAnotacion.class.isAnnotationPresent
(AnotacionUsuario.class))
assert(true);
else
assert(false);
}
}

POJO

Llamamos Plain Old Java Object a una clase normal y corriente, con sus propiedades y métodos (getters, setters,...), ligándola a un determinado entorno de ejecución o contenedor y siendo independiente del framework ya que no recibe ninguna intrusión por parte de éste en forma de implementación de interfaces o extensiones de clases. En los EJB<3, las entidades y sesiones beans debían obligatoriamente implementar ciertas interfaces y heredar clases proveídas por el framework, cosa que no pasa con la version 3. Siempre ha de llevar implementado el constructor por defecto (aunque no haga nada) en caso de que necesitemos otros (constructores con parámetros).

Veamos un ejemplo:


package es.nuwi.ejemplo.pojo


impor java.io.*;


public class EjemploPojo{


private String saludo="Hola,esto es un ejemplo de POJO.";


public void saludaAlLector(){
System.out.println(saludo);
}
}

Caja blanca vs Caja negra

Llamamos caja blanca de un sistema (aplicación entera) o módulo (parte del sistema) cuando conocemos su funcionamiento interno, es decir, sabemos como es generada la salida a partir de las entradas . Un ejemplo de caja blanca es EasyMock. En cambio, si se habla de caja negra, solo conocemos sus entradas y la salida correspondiente, no la forma de generar el resultado. Ejemplos de cajas negra son TestNG o JUnit .

Apache ANT

Apache Ant es una herramienta hecha en java encargada de llevar acabo todas aquellas tareas repetitivas, como por ejemplo, el compilado, clean,build... La mayor ventaja de esta herramienta es la portabilidad, es decir, no es necesario conocer los comandos del sistema operativo (crear directorios, borrar ficheros,...) con el que se este trabajando para la ejecución de las tareas antes mencionadas. Como habrás observado, garantiza que el "IDE sea multi-plataforma"(el plugin Ant viene integrado en el ECLIPSE por defecto ).

Para llevar la ejecución de dichas tareas, Ant se basa en un fichero xml, llamado por defecto "build.xml", (puede comprobarse desde la pestaña Window->Preferences->Ant en el Eclipse). Dicho fichero contendrá el nombre del proyecto y una serie de objetivos (target o tareas a realizar). Puede darse el caso en que un objetivo dependa de otros antes de ejecutarse, para ello se utiliza el atributo "depends" siendo su valor el nombre de la tarea previa.

Otra característica de Ant, es que éste puede ser lanzado desde la consola.

He aquí un ejemplo de la wiki, ya que me parece muy básico y a la vez sencillo:


<?xml version="1.0"?>
<project name="Hello" default="compile">
<target name="clean" description="borrar archivos temporales">
<delete dir="classes"/>
</target>
<target name="compile"
description="compilar el código java a un archivo class">
<mkdir dir="classes"/>
<javac srcdir="." destdir="classes"/>
</target>
<target name="jar" depends="compile"
description="crear un archivo Jar para la aplicación">
<jar destfile="hello.jar">
<fileset dir="classes" includes="**/*.class"/>
<manifest>
<attribute name="Main-Class" value="HelloProgram"/>
</manifest>
</jar>
</target>
</project>

Pincha aquí para descargar Apache Ant. Si te lo has descargado, pon una variable en el sistema llamada ANT_HOME cuyo contenido sea la ruta en donde hayas descomprimido el fichero antes mencionado, y a continuación añade a la variable PATH %ANT_HOME%/bin .

Pincha aquí para ver el manual de Apache Ant ( esta en inglés).