domingo 22 de agosto de 2010

Vistazo a Spring Framework (Un ejemplo del uso de JdbcTemplate e integración con Struts 2 )

Introducción



El desarrollar aplicaciones web involucra la configuración de varias herramientas y tecnologías, peor aun si lo vemos desde una perspectiva de mantenibilidad; por ejemplo que la aplicación requiera constantes cambios. A principios en java esto fue una tarea difícil; poco a poco fueron apareciendo tecnologías posteriores a los servlets; estas facilitando en gran medida el desarrollo de aplicaciones web, por que no es que los servlets estén obsoletos.

Esta guía trata de brindar un breve vistazo sobre Struts 2, un framework para el desarrollo web que simplifica en gran medida el estilo de programación de Servlets y JSPs; mostrando a la vez como se integra con Spring para poder hacerle inyección de dependencias a las clases controladoras de struts . Además utilizaremos el framework Spring para facilitar el ingreso y obtención de datos por medio del uso de JdbcTemplate .

La ventaja del uso de la tecnología Spring en aplicaciones es claramente la Inversion De Control (IoC, por sus siglas en inglés) y la inyección de dependecias; ya que permite desarrollar sistemas de todo tipo con previstas a cambios futuros y con la facilidad de poder configurar todos los componentes desde un contenedor, situación que provoca que el sistema sea fácilmente mantenible.


Descripción


La aplicación consiste en una sencilla aplicación web que ingresa y consulta trabajadores basada en MVC mediante Struts Framework 2.

Conocimientos

Conocimientos básicos en: Html, Java y JSP. Además de conocer un poco el entorno de desarrollo Eclipse , el servidor java que este utilizando y mysql .

Requerimientos

Estos requerimientos son para seguir paso a paso la guía.
  1. Eclipse Galileo (For Java EE Developers), preferiblemente aunque puede ser otra distribución que permita el desarrollo de Dynamic Web Projects.
  2. Spring Tool Suite.
  3. Servidor Java local para correr la aplicación, en este caso utilicé JBoss 5.1, pero de igual manera puede optarse por Apache Tomcat.
  4. Servidor MySQL local, para poder instalar la base de datos a la cual se va a conectar la aplicación y las herramientas para administrar servidor(Opcional).


Librerias de las que depende el proyecto

Struts: junto con sus dependencias, se pueden encontrar en la distribución 2.x.x al descargarla. Estas son: struts2-core-xxxx.jar, commons-fileupload-xxxx.jar, freemarker-xxxx.jar, ognl-xxx.jar, commons-io-xxxx.jar, xwork-core-xxx.jar y struts2-spring-plugin-xxxxx.jar.
Spring: esta es una implementación de la versión 3.x.x (En el paso 3 muestro las librerías necesarias para realizar este proyecto; no vamos a utilizar todos los módulos de spring).
Conector Java Para MySQL.

Además deberá de incluirse la librería commons-logging.jar en caso que el servidor sea distinto(yo he necesitado esa librería para correr la aplicación en Tomcat) a JBoss 5.1

Pasos:

  • Comenzaremos creando un proyecto Dynamic Web Project en Eclipse, File->New->Dynamic Web Project, el cual llamaremos Ejemplo. Si bien ya previamente habían configurado un servidor simplemente lo seleccionan del combo box Target Runtime, si no deberán crear uno nuevo (1); los pasos para realizar eso es muy simple, solamente deben de seleccionar la versión del servidor que tienen instalado e indicar en que parte se encuentra instalado. Luego damos Finish.
  • Ahora procederemos a configurar las librerías que utilizara nuestro proyecto; primero se selecciona el proyecto en el Project Explorer y luego vamos a a la barra de menú en Project->Properties . Aqui configuraremos (1 y 2) librerías de usuario (User Library) con los respectivos jar de struts, mysql-connector y de spring, mediante la opción Add Library. Seguidamente se procede a pegar (3) copiar directamente las librerías necesarias en la carpeta lib, para que sean referenciadas en tiempo de ejecución de la aplicacion.
  • A continuación procederemos a crear la base de datos en mysql con el nombre “ejemplos” y la tabla “trabajadores” que utilizaremos.
    CREATE DATABASE IF NOT EXISTS ejemplos;

    USE ejemplos;



    --

    -- Definition of table `trabajadores`

    --



    DROP TABLE IF EXISTS `trabajadores`;

    CREATE TABLE `trabajadores` (

    `id` varchar(20) NOT NULL,

    `nombre` varchar(20) NOT NULL,

    `departamento` varchar(20) NOT NULL DEFAULT 'No Asignado',

    `numero_trabajador` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,

    PRIMARY KEY (`numero_trabajador`) USING BTREE,

    UNIQUE KEY `Index_2` (`id`)

    ) ENGINE=InnoDB AUTO_INCREMENT=46 DEFAULT CHARSET=latin1;
  • En el proyecto en eclipse crearemos la clase Trabajador.java con sus respectivos 3 atributos y métodos (getters y setters para los atributos) que va a ser la unidad del negocio en este ejemplo en el paquete com.misBeans:
    package com.misBeans;



    public class Trabajador {

    private String id;

    private String nombre;

    private String departamento;



    public String getId() {

    return id;

    }



    public void setId(String id) {

    this.id = id;

    }



    public String getNombre() {

    return nombre;

    }



    public void setNombre(String nombre) {

    this.nombre = nombre;

    }



    public String getDepartamento() {

    return departamento;

    }



    public void setDepartamento(String departamento) {

    this.departamento = departamento;

    }



    }
  • Creamos la interfaz TrabajadorDAO.java en un paquete llamado com.daos para implementar una clase de acceso de datos con un método para ingresar que tenga un parámetro del tipo trabajador y otro método para listar que nos devuelta objetos del tipo Trabajador.

    package com.daos;



    import java.util.List;



    import com.misBeans.Trabajador;



    public interface TrabajadorDAO {

    public boolean ingresarEmpleado(Trabajador t);

    public List<Trabajador> listarEmpleados();

    }
  • Ahora generamos una clase en el paquete mencionado en el punto anterior con el nombre TrabajadorDAOImplementacion con eclipse que implemente la interfaz creada previamente, ya por creada de igual forma con las herramientas para la manipulación de código fuente implementamos los métodos asignados en la interfaz. Asignamos el atributo plantilla del tipo JdbcTemplate. Además debemos agregar el método setDataSource(DataSource dataSource) para que spring pueda hacer una inyección de dependecia a la clase para instanciar plantilla mediante un bean en el contenedor que definiremos para asignar los datos con los cuales se conectara a la base de datos (driver, usuario, contraseña, url).
    package com.daos;



    import java.sql.ResultSet;

    import java.sql.SQLException;

    import java.util.List;



    import javax.sql.DataSource;



    import org.springframework.dao.DataAccessException;

    import org.springframework.jdbc.core.JdbcTemplate;

    import org.springframework.jdbc.core.RowMapper;



    import com.misBeans.Trabajador;



    public class TrabajadorDAOImplementacion implements TrabajadorDAO {



    private JdbcTemplate plantilla;



    public void setDataSource(DataSource dataSource) {

    // se instancia plantilla con la inyeccion del datasource

    this.plantilla = new JdbcTemplate(dataSource);

    }



    @Override

    public boolean ingresarEmpleado(Trabajador t) {

    // TODO Auto-generated method stub

    // ingresamos 1 trabajador con el metodo update de plantilla

    try {

    this.plantilla.update("INSERT INTO trabajadores(id,nombre,departamento) VALUES(?,?,?)", t

    .getId(), t.getNombre(), t.getDepartamento());

    return true;

    } catch (DataAccessException e) {

    return false;

    }

    }



    @Override

    public List<Trabajador> listarEmpleados() {

    // TODO Auto-generated method stub

    // realizamos la consulta de de trabajadores

    return this.plantilla.query("SELECT * FROM trabajadores" +

    " ORDER BY numero_trabajador DESC LIMIT 10",

    // se mapea el resultado de la consulta para que query

    // retorne una lista con objetos de tipo Trabajador

    new RowMapper<Trabajador>() {

    public Trabajador mapRow(ResultSet rs, int rowNum)

    throws SQLException {

    Trabajador t = new Trabajador();

    t.setId(rs.getString("id"));

    t.setNombre(rs.getString("nombre"));

    t.setDepartamento(rs.getString("departamento"));

    return t;

    }

    });

    }



    }

  • En este paso nos enfocaremos en crear la clase ControladorTrabajador.java en un paquete llamado com.struts, en esta se colocaran los metodos (ingresar y listar) requeridas desde una vista en una pagina jsp y que definiremos como acciones(IngresarTrabajador y Formulario respectivamente) en el archivo struts.xml que crearemos posteriormente. La clase constara de 5 atributos:
    • tDAO(tipo TrabajadorDAO, que la inicializara Spring mediante inyección de dependencia).
    • id, nombre y departamento (los datos que se ingresaran desde el formulario ).
    • trabajadores (atributo que sera llenado para la accion).
    Debera de definirse los métodos para ingresar y listar, estos requieren que lancen una excepción.
    Aparte de esos, se definirán los siguientes métodos en la clase: Para los atributos id, nombre y departamento deberán asignarse métodos get y set respectivamente; para tDAO solo el método set y para el atributo trabajadores el método get.
    package com.struts;



    import java.util.List;



    import com.daos.TrabajadorDAO;

    import com.misBeans.Trabajador;

    import com.opensymphony.xwork2.validator.annotations.RequiredFieldValidator;

    import com.opensymphony.xwork2.validator.annotations.Validation;





    public class ControladorTrabajador{

    private TrabajadorDAO tDAO;

    private String id;

    private String nombre;

    private String departamento;

    private List<Trabajador> trabajadores;



    public String ingresar() throws Exception {

    //se instancia un objeto tipo trabajador

    // se llena con los datos del formulario

    Trabajador t = new Trabajador();

    t.setId(getId());

    t.setNombre(getNombre());

    t.setDepartamento(getDepartamento());

    //se llamado el metodo para ingresar enviando t

    if(this.tDAO.ingresarEmpleado(t))

    return "success";

    else return "error";

    }

    public String listar() throws Exception{

    //llamada al metodo para listar del objeto tDAO

    // al retornar una lista con objetos se debe realizar un casting

    this.trabajadores = (List<Trabajador>) this.tDAO.listarEmpleados();

    return "success";

    }



    public void settDAO(TrabajadorDAO tDAO) {

    this.tDAO = tDAO;

    }







    public String getId() {

    return id;

    }

    public void setId(String id) {

    this.id = id;

    }



    public String getNombre() {

    return nombre;

    }



    public void setNombre(String nombre) {

    this.nombre = nombre;

    }



    public String getDepartamento() {

    return departamento;

    }



    public void setDepartamento(String departamento) {

    this.departamento = departamento;

    }

    public List<Trabajador> getTrabajadores() {

    return trabajadores;

    }
    }
  • Vamos a declarar los beans en el contenedor de Spring. Para ello utilizaremos SpringSource Tool Suite; lo primero que haremos acá sera crear un proyecto, File->New->Spring Project . Al proyecto le ponemos cualquier nombre. Acordemos que estos pasos son una guía porque el programa lo pueden utilizar de la manera que les quede mas comodo. De igual manera a como se hizo para configurar el proyecto en Eclipse, aquí también tendremos que agregar las mismas librerías al proyecto (de nuevo crear librerías de usuario pero para el proyecto de STS) para que las herramientas de configuración de beans de spring detecte las dependencias. Seguidamente necesitamos crear una carpeta en el proyecto(nombre de proyecto, SpringEjemplo), para referenciar el proyecto de Eclipse y poder accesar todos los archivos que hemos creado.Como se puede observar expandí la opción avanzada para enlazar la carpeta a la carpeta en donde se encuentra e proyecto de Eclipse.
  • Ahora se prosigue a añadir un nueva carpeta src o de código fuente a parte de la que se crea por defecto cuando se crea un proyecto. Esta carpeta nueva en el proyecto debe de ser el src del proyecto de eclipse. El motivo de esto se da para que el STS detecte las clases generadas previamente y se pueda utilizar esta herramienta de una manera mas eficiente.
    Damos Project->Properties en la barra de menú. Nos vamos a Java Build Path y en la pestaña Source seleccionamos Add Folder, se necesita expandir la carpeta Ejemplo y se marca el src del proyecto de eclipse.
  • Ahora le damos refresh al proyecto y seleccionamos la carpeta Ejemplo/src ( aparece después del paso anterior ) para irnos luego a la barra de menú File->New->Spring Bean Configuration File. Al archivo le colocamos el nombre applicationContext.xml y damos Finish, con este nombre por convenio el listener de Spring lo va a encontrar para poder instanciar los beans, en caso que se desee cambiar este nombre, deberá especificarse en el web.xml que archivo sera el contenedor. Abrimos el archivos que acabamos de crear y nos aparece un editor, en el cual debemos de seleccionar la pestaña beans, seguidamente hacemos click sobre el botón New Bean.
    La primera definición de bean sera para el data source tal y como se ve en la imagen inferior. Se debe de llenar el campo Id y la clase que se va a utilizar para el objeto (el botón browse facilita la búsqueda de la clase, en este caso DriverManagerDataSource para conectar con la Base de Datos), damos Next
  • Al dar Next en el paso anterior nos aparece esta pantalla en donde agregamos las propiedades (mediante el botón Add) que vamos a utilizar y llenamos el value(ref se utilizara en los otros beans) respectivo para poder realizar la conexión y damos Finish.
  • Ahora volvemos a crear a definir un bean( con nombre trabajadorDAO) que utilice la clase TrabajadorDAOImplementacion, llenamos la propiedad dataSource pero en este caso no con value si no con ref (le asignamos ds como valor y de esta manera referenciar el dataSource que se había declarado en el paso anterior) y damos Finish.
  • Por ultimo declararemos un bean llamado ControladorTrabajador para instanciar la clase que controlara la acciones de Struts, en la que se hara una inyección de dependencia para la propiedad tDAO utilizando como referencia el bean trabajadorDAO declarado en el contenedor tal y como se muestra en las siguientes ilustraciones:



  • Deberá de agregarse en el nodo beans del archivo applicationContext.xml el atributo default-autowire con el valor byName, esto para que las clases de las acciones en el struts.xml (creado en el siguiente paso) sean enlazadas por nombre a los objetos definidos en Spring y de esta manera ser utilizadas ya con las dependencias inyectadas. Para terminar de configurar el container de Spring deberá de copiarse el archivo applicationContext.xml a la raíz de la carpeta WEB-INF de nuestra aplicación para que sea reconocido por el ContextLoaderListener de Spring.
    <?xml version="1.0" encoding="UTF-8"?>

    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

    <beans default-autowire="byName">



    <bean id="ds"

    class="org.springframework.jdbc.datasource.DriverManagerDataSource">

    <property name="driverClassName"

    value="com.mysql.jdbc.Driver">

    </property>

    <property name="username" value="root"></property>

    <property name="password" value="1234"></property>

    <property name="url"

    value="jdbc:mysql://localhost:3307/ejemplos">

    </property>

    </bean>

    <bean id="trabajadorDAO"

    class="com.daos.TrabajadorDAOImplementacion">

    <property name="dataSource" ref="ds"></property>

    </bean>



    <bean id="ControladorTrabajador" class="com.struts.ControladorTrabajador">

    <property name="tDAO" ref="trabajadorDAO"></property>

    </bean>

    </beans>


  • Volviendo al entorno de Eclipse Galileo deberemos crear el archivo struts.xml, y colocarlo en la raíz de la carpeta src del proyecto. Como se puede observar a diferencia de una implementación simple de struts, en este caso debemos de utilizar el nodo constant para poder referenciar el plugin de struts 2 para spring. Debemos notar que en el atributo class de cada acción de este archivo colocamos ControladorTrabajador (nombre que corresponde al bean que declaramos en el applicationContext.xml).
    En este archivo declaramos dos acciones:
    • IngresarTrabajador:Se encargara de procesar los datos al ingresarlos al formulario y esta enlazada al método ingresar de la clase ControladorTrabajador.
    • Formulario:Se encargara de consultar los trabajadores ingresados y esta enlazada al método listar de laclase ControladorTrabajador.

    <?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>

    <constant name="struts.objectFactory"

    value="org.apache.struts2.spring.StrutsSpringObjectFactory" />

    <package name="default" extends="struts-default">

    <action name="IngresarTrabajador" class="ControladorTrabajador" method="ingresar">

    <result name="success" type="redirectAction">Formulario</result>

    <result name="error" type="redirectAction">Formulario</result>

    <result name="input">/index.jsp</result>

    </action>

    <action name="Formulario" class="ControladorTrabajador" method="listar">

    <result name="success">/index.jsp</result>

    </action>

    </package>

    </struts>


  • Configuración del archivo web.xml, lo único que tenemos que agregar serian la definición del filtro junto con su respectivo mapeo por url para la invocación de las acciones que se realizan en cualquier implementación básica de Struts 2 y además deberemos definir el listener de Spring que se encargará de iniciar el contexto junto con todos los beans que se coloquen en el archivo applicationContext.xml exponiéndolos para que queden listos para su uso.
    <?xml version="1.0" encoding="UTF-8"?>

    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"

    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"

    id="WebApp_ID" version="2.5">

    <display-name>Ejemplo</display-name>

    <welcome-file-list>

    <welcome-file>index.jsp</welcome-file>

    </welcome-file-list>

    <filter>

    <filter-name>action2</filter-name>

    <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>

    </filter>

    <filter-mapping>

    <filter-name>action2</filter-name>

    <url-pattern>/*</url-pattern>

    </filter-mapping>

    <listener>

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

    </listener>

    </web-app>


  • A continuación creamos el archivo index.jsp que va a ser la vista de nuestra aplicación web, como se puede observar en la línea 3 importamos la etiquetas de struts y utilizamos el prefijo “s” para incrustar los componentes en el archivo, el resto de los detalles se explican en el archivo.
    <%@ page language="java" contentType="text/html; charset=ISO-8859-1"

    pageEncoding="ISO-8859-1"%>

    <%@ taglib uri="/struts-tags" prefix="s"%>

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

    <html>

    <head>

    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"></meta>

    <title>@SOTTO</title>

    <link href="estilos.css" rel="stylesheet" type="text/css"></link>

    </head>

    <body>

    <div>

    <a id="titulo1">@SOTTO</a> <a id="titulo2">www.asotto.blogspot.com </a>

    </div>

    <%-- Declaramos un formulario de struts que va a usar la accion que definimos

    para que haga el ingreso de datos

    --%>

    <s:form action="IngresarTrabajador">

    <%-- los campos tienen los mismos nombres que los atributos de la clase ControladorTrabajador --%>

    <s:textfield name="id" label="Id"></s:textfield>

    <s:textfield name="nombre" label="Nombre"></s:textfield>

    <s:select label="Departamento" name="departamento"

    list="{'Taller', 'Oficina', 'Planta'}"></s:select>

    <s:submit value="Ingresar"></s:submit>



    </s:form>

    <table>

    <tr class="tencabezado">

    <td>ID</td>

    <td>NOMBRE</td>

    <td>DEPARTAMENTO</td>

    </tr>

    <%-- este iterador sirve para llenar la tabla con los trabajadores

    cuando se es llamada la accion Formulario

    desde el navegador --%>

    <s:iterator value="trabajadores">

    <tr>

    <td><s:property value="id" /></td>

    <td><s:property value="nombre" /></td>

    <td><s:property value="departamento" /></td>

    </tr>

    </s:iterator>

    </table>

    </body>

    </html>

  • Y para darle un poco de forma a la interfaz usamos esta hoja de estilos.
    @charset "utf-8";

    /* CSS Document */



    body {

    font-family: Verdana, Geneva, sans-serif;

    font-size: 11px;

    }

    #titulo1 {

    font-family: Verdana, Geneva, sans-serif;

    font-size: 24px;

    color: #333;

    }

    .tencabezado {

    background-color: #09C;

    color: #FFF;

    font-style: normal;

    font-weight: bold;

    }

    td {

    width: 200px;

    }

    #titulo2 {

    font-size: 14px;

    color: #099;

    font-style: italic;

    }


    1. Con esto ya queda nuestra aplicación lista para ser corrida desde el navegador de la siguiente forma: http://localhost:8080/Ejemplo/Formulario.action



      Aplicación y códigos fuente:

      • El archivo desplegable en el servidor(.war) :

      Ejemplo.war

      • El comprimido zip en:

      Ejemplo.zip



      Con este tutorial espero que puedan ser entendidas algunas de las capacidades que tiene el framework Spring.

      6 comentarios:

      1. Man, muy buen ejemplo!

        En lo personal si quieres velocidad y usar tecnologia equivalentes, te recomiendo usar Spring Roo! Ademas con el ide de spring que estas usando, resulta mas sencillo, pues viene integrado para que el AOP funcione!

        A mi me encanta Struts y trabaje con el, por mas de 7 anos, tanto en la version 1.0, 1.1, 1.2 y 2.X
        Tambien he trabajado con SpringMvc 2.x y 3.x

        Pero te recomiendo hechar un vistaso a Apache Stripes, si yo se un framework mas, pero es tan sencillo y poco intrusivo que la verdad lo quiero mucho! Ademas ocupa muy poca configuracion o casi nada!

        Ah para la base de datos, DDLUtil te puede servir, genera a partir de un XML, el sql necesario para diferentes servidores y puede usar liquibase, para gestionar los cambios en tu base de datos!

        Un saludo,
        J

        ResponderSuprimir
      2. Saludos.... Pura vida, muchas gracias.... Si la verdad que las herramientas en java permiten gran flexibilidad, voy a probarlo... Otro framework que me encanta para la capa de navegador es icefaces....

        ResponderSuprimir
      3. Yo quede curado con los esquemas MVP, asi que face, muy bonito pero de lejos! y me parece que el mecanismo de server push, lo sacaron aparte, asi que....

        ResponderSuprimir
      4. Otra cosa que podes usar, es Maven, supongo que ya lo debes conocer, sirve para manejar el ciclo de vida del proyecto, entre un monton de cosas mas

        http://jsanca.ticoblogger.com/search/label/maven

        Al final podras encontrar un articulo que escribi, sobre introduccion a Maven y segui escribiendo! ayuda aprender, a que otros aprendan y de memoria de largo plaza!

        ResponderSuprimir
      5. claro lo he escuchado maneja las dependencias del proyecto y lo configura, lo independiza a uno de andar buscando librerias por todo lado... muchas gracias voy a probarlo para ver que tal es para eclipse... Pero en curva de aprendiza jsf y icefaces es menos empinada... Saludos

        ResponderSuprimir
      6. http://apps.facebook.com/herolegend/?ftype=flyfish&uid=100001743240536

        ResponderSuprimir

      Compartir