Intro Struts2

Despues de mucho esperar (lo cual les agradezco) y como respuesta a este post Cuando mas rapido empieces a programar mas tarde terminaras

Esto solo es una breve introduccion a Struts 2; Fue concebido por la union de 2 frameworks; WebWork y Struts 1, Struts 2 fue pensado para basarse en POJO's, con ello facilita la aplicacion de pruebas a nuestros actions

  • Soporte para plugins sin configuracion
  • Para esta version incluye soporte para el paradigna Convention Over Configuration a travez de un plugin
  • Integracion con Spring de forma muy sencilla
  • Agrega manejo de plantillas para los componentes de nuestra pagina, como nuestros formularios, a travez de FreeMarker
  • Ahora en su libreria de etiquetas hace uso de un lenguaje de expresiones llamado OGNL, lo que le permite simplificar la evaluacion y ejecutacion expresiones.

Con esta breve introduccion vayamos a nuestro primer ejemplo

Generamos el proyecto con Maven, usando la version de la libreria de Struts 2.2.1

mvn archetype:create   -DgroupId=org.javamexico.demo \
                       -DartifactId=demoStruts2 \
                       -DarchetypeGroupId=org.apache.struts \
                       -DarchetypeArtifactId=struts2-archetype-starter \
                       -DarchetypeVersion=2.2.1

Con este comando nos crea nuestro proyect integrado con otros frameworks como Spring, Sitemesh, DWR y con clases demo como lo vamos a ver en este ejemplo.

Con esto deberia de funcionar, en mi caso tuve problemas con el archetype de maven, el error fue el siguiente:

struts2-archetype-starter only whitespace content allowed before start tag and not \ud4 (position: START_DOCUMENT seen \ud4... @1:1)

no pude encontrar alguna solucion, por ello tuve que generar el proyecto con la version 2.1.8 y despues actualizarlo a la version 2.2.1 de Struts.

Ahora como diria Jack el Descuartizador "Vamos por partes"

La configuracion en nuestro archivo web.xml:

El filtro de Struts2
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter

Como les comente, nuestro proyecto fue generado con la integracion de Sitemesh, por eso tenemos 2 filtros mas

org.apache.struts2.dispatcher.ActionContextCleanUp // que nos sirve para que Struts y Sitemesh puedan trabajar sin problemas, este filtro le dice al filtro de Struts2 (StrutsPrepareAndExecuteFilter) cuando quitar objetos obsoletos.

com.opensymphony.module.sitemesh.filter.PageFilter // que hace el trabajo de Sitemesh

La integracion con Spring con su listener:
org.springframework.web.context.ContextLoaderListener

y DWR
uk.ltd.getahead.dwr.DWRServlet

Vayamos a nuestro archivo de configuracion de Struts2, ahora llamado struts.xml y localizado, de acuerdo en la estructura de directorio de Maven en: src/main/resources/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="myPackage" extends="struts-default">
                <action name="index" class="org.javamexico.demo.IndexAction">
                        <result>/jsp/index.jsp</result>
                </action>
                <action name="helloWorld" class="helloWorldAction">
                        <result name="input">/jsp/index.jsp</result>
                        <result>/jsp/helloWorld.jsp</result>
                </action>
        </package>
</struts>

Ahora en la configuracion de Struts2 tiene una organizacion en paquetes de nuestros actions, el extends="struts-default" es porque Struts2 tiene soporte para heredar configuracion de otros paquetes.

Para entender el codigo, primero vamos a explicar que es lo que hace la aplicacion, cuando entramos a la URL: http://localhost:8080/demoStruts2/, responde nuestro index.jsp para redireccionar a index.action (si .action en vez del conocido .do), entonces struts invoca la clase que se configuro para dicho index.action y finalmente se desplega el jsp: /jsp/index.jsp, como resultado tenemos una pagina con un formulario al centro, 2 menus, header y footer. Vemos que 1 de los campos del formulario fue prellenado y esto fue por la ejecucion del action

Para el primer action llamado 'index' tenemos la clase IndexAction, el codigo:

package org.javamexico.demo;

import com.opensymphony.xwork2.ActionSupport;
import java.util.Date;
import com.opensymphony.xwork2.conversion.annotations.Conversion;
import com.opensymphony.xwork2.conversion.annotations.TypeConversion;

@Conversion()
public class IndexAction extends ActionSupport {
        private static final long serialVersionUID = -1007080611403935133L;
       
        private Date now = new Date(System.currentTimeMillis());

        @TypeConversion(converter = "org.javamexico.demo.DateConverter")
        public Date getDateNow() { return now; }

        public String execute() throws Exception {
                now = new Date(System.currentTimeMillis());
                return SUCCESS;
        }
       
}

Diferencias de Struts2:

  1. Ahora nuestras clases Action extienden de ActionSupport.
  2. Nuestro metodo con las actividades de nuestro action es 'execute', retorna un objeto String y no recibe parametros
  3. Struts2 viene con anotaciones, para este ejemplo tenemos @Convertion que le dice a Struts que IndexAction tiene un convertidor de datos y @TypeConversion donde se especifica la clase que se encarga de hacer esa conversion de datos.
  4. La clase IndexAction tiene una propiedad llamada 'now' y es donde Struts hace el binding con nuestros parametros, ya no hay FormBeans (no recuerdo si asi se llaman)

Entonces cada vez que se invoque a index.action se asigna un nuevo Date a nuestra propiedad y se retorna la cadena 'success', SUCCESS es una constante de la clase padre de ActionSupport.

La clase DateConverter hace la conversion de tipo Date a String y viceversa, como lo pueden apreciar en su demo.

Ahora Struts como sabe a donde ir, veamos la configuracion para este action

<action name="index" class="org.javamexico.demo.IndexAction">
        <result>/jsp/index.jsp</result>
</action>

Ahora vemos un elemento llamado result y como valor tiene la ruta de un JSP, este es nuestro result default (por que no le especificamos el valor al atributo 'name') y aqui es donde se le especifica a Struts a donde continuar con el flujo cuando el action retorna SUCCESS.

Ahora veamos el JSP

La forma para hacer uso de las taglibs de struts es:

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

Recordemos que Struts2 hace uso de plantillas hechas en FreeMarker, con ello en nuestro formulario toma cierto formato, Struts tiene temas con lo cual se puede cambiar dicho formato.

Como hace Struts para el binding?

<s:textfield label="What is the date?" name="dateNow" />

El nombre del campo es 'dateNow' y en la funcionalidad vemos que este campo es prellenado, Struts hace instrospeccion a nuestros action y al estar basados en beans se realiza el binding entre los parametros, por esta razon en nuestro IndexAction tenemos un metodo get.

@TypeConversion(converter = "org.javamexico.demo.DateConverter")
public Date getDateNow() { return now; }

La anotacion de conversion especifica que a este metodo se debe realizar la conversion, para este caso del formato de la fecha.

De esta forma es como trabaja Struts2, espero no sea confuso lo que explique, de todas formas cualquier duda/comentario sera bien recibido y de esa forma mejorar estos post del framework.

Les pido disculpas por la tardanza, y pronto publicare la siguiente parte.