El API Struts

Ahora que hemos entendido c�mo construir los componentes del Modelo y de la Vista de nuestra aplicaci�n, es hora de enfocarnos en los componentes del Controller. Struts incluye un servlet que implementa la funci�n principal de mapeo de una solicitud URI a una clase Action. Por lo tanto, nuestras principales responsabilidades con el controlador son:

  • Escribir una clase Action por cada solicitud l�gica que podr�a ser recibida (extendida desde org.apache.action.Action).
  • Configurar un ActionMapping (en XML) por cada solicitud l�gica que podr�a ser enviada. El fichero de configuraci�n XML normalmente se llama struts-config.xml.
  • Actualizar el fichero del descriptor de despliegue de la aplicaci�n Web (en XML) para nuestra aplicaci�n para que incluya los componentes Struts necesarios.
  • A�adir los componentes Struts apropiados a nuestra aplicaci�n.

.�Clases Action

La clase Action define dos m�todos que podr�an ser ejecutados dependiendo de nuestro entorno servlet:

public ActionForward perform(ActionMapping mapping,
 ActionForm form,
 ServletRequest request,
 ServletResponse response)
  throws IOException, ServletException;

public ActionForward perform(ActionMapping mapping,
 ActionForm form,
 HttpServletRequest request,
 HttpServletResponse response)
  throws IOException, ServletException;

La mayor�a de los proyectos s�lo usar�n la versi�n "HttpServletRequest".

El objetivo de una clase Action es procesar una solicitud, mediante su m�todo perform(), y devolver un objeto ActionForward que identifica d�nde se deber�a reenviar el control (por ejemplo a una JSP) para proporcionar la respuesta apropiada. En el patr�n de dise�o MVC/Model 2, una clase Action t�pica implementar� una l�gica como �sta en su m�todo perform():

  • Validar el estado actual de la sesi�n del usuario (por ejemplo, chequear que el usuario ha hecho el login). Si la clase Action encuentra que no existe logon, la solicitud es reenviada a la p�gina JSP que muestra las peticiones del nombre de usuario y la password para logging on. Esto podr�a ocurrir porque un usuario intente entrar "en el medio" de una aplicaci�n (digamos, desde un bookmark), o porque la sesi�n ha expirado, y el contenedor servlet cre� una nueva.
  • Si la validaci�n no se ha completado, valida las propiedades del bean formulario seg�n sea necesario. Si se encuentra un problema, almacena las claves de los mensajes de error apropiados como un atributo de la petici�n, y reenv�a el control de vuelta al formulario de entrada para que se puedan corregir los errores.
  • Realizar el procesamiento requerido para tratar con esta solicitud (como grabar un fila de la base de datos). Esto se puede hacer mediante c�digo l�gico embebido dentro de la propia clase Action, pero generalmente deber�a realizarse llamando a un m�todo apropiado del bean de l�gica de negocio.
  • Actualizar los objetos del lado del servidor que ser�n usados para crear la siguiente p�gina del interface de usuario (normalmente beans del �mbio de solicitud o de sesion, dependiendo de cu�nto tiempo necesitemos mantener estos �tems disponibles).
  • Devolver un objeto ActionForward apropiado que identifica la p�gina JSP usada para generar esta respuesta, basada en los beans actualizados recientemente. T�picamente adquiriremos una referencia a dicho objeto llamando a findForward() o al objeto ActionMapping que recibimos (si estamos usando un nombre l�gico normal para este mapeo), o en el propio servlet controlador (si estamos usando un nombre l�gico global para la aplicaci�n).

Entre los problemas de dise�o a recordar cuando codificamos clases Action incluimos los siguientes:

  • El servlet controlador crea un s�lo ejemplar de nuestra clase Action, y la usa para todas las solicitudes. Es decir, necesitamos codificar nuestra clase Action para que opere correctamente en un entorno multi-thread, como si estuvieramos codificando un m�todo service() de un servlet.
  • El principio m�s importante que nos ayuda en la codificaci�n de threads seguros es usar s�lo variables locales, no variables de ejemplar, en nuestra clase Action. Las variables locales se crean en una pila que es asignada (por nuestra JVM) a cada thread solicitado, por eso no necesitamos preocuparnos de compartirlas.
  • Los beans que representan el Modelo de nuestro sistema podr�a lanzar excepciones debido a problemas de acceso a bases de datos o a otros recursos. Deber�amos atrapar dichas excpeciones en la l�gica de nuestro m�todo perform(), y guardalas en el fichero de log de la aplicaci�n (junto con el seguimiento de pila correspondiente) llamando a:
    servlet.log("Error message text", exception);
    
  • Como regla general, asignar recursos y mantenerlos a trav�s de las solicitudes del mismo usuario (en la misma sesi�n de usuario) puede causar problemas de escalabilidad. Deber�amos pensar en liberar esos recursos (como las conexions a una base de datos) antes de reenviar el control al componente de la Vista apropiado -- incluso si un m�todo del bean que hemos llamado lanza una excepci�n.

Adem�s, queremos protegernos contra clases Action que son demasiado largas. La forma m�s f�cil de hacer que esto suceda es embeber la l�gica funcional en la propia clase Action, en vez codificarla en beans de l�gica de negocio independientes. Adem�s de hacer la propia clase Action dura de entender y de mantener, esta aproximaci�n tambi�n hace d�ficil re-utilizar el c�digo de la l�gica de negocio, porque est� embebido dentro de un componente (la clase Action) que est� concebido para ser ejecutado en un entorno de aplicaci�n Web.

Una Action puede dividirse en varios m�todos locales, mientras que todas las propiedades necesarias sean pasadas en las firmas de m�todos. La JVM maneja dichas propiedades usando la pila, y por eso son seguras ante los threads.

La aplicaci�n de ejemplo incluida con Struts no cumple este principio, porque la propia l�gica de negocio est� embebida dentro de las clases Action. Esto deber�a considerarse un bug en el dise�o de la aplicaci�n de ejemplo, en vez de una caracter�stica intr�nseca de la arquitectura , o una aproximaci�n a emular.

.�La Implementaci�n de ActionMapping

Para poder operar satisfactoriamente, el servlet controlador Struts necesita conocer varias cosas sobre como se deber�a mapear toda URI solicitada a una clase Action apropiada. El conocimiento requerido ha sido encapsulado en un interface Java, llamado ActionMapping, estas son las propiedades m�s importantes:

  • type - nombre totalmente cualificado de la clase Java que implementa la clase Action usada por este mapeo.
  • name - El nombre del bean de formulario definido en el fichero de configuraci�n que usar� este action.
  • path - El path de la URI solicitada que corresponden con la selecci�n de este mapeo.
  • unknown - Seleccionado a true si este action deber�a ser configurado como por defecto para esta aplicaci�n, para manejar todas las solicitudes no manejadas por otros action. S�lo un Action puede estar definido como por defecto dentro de una s�la aplicaci�n.
  • validate - Seleccionado a true si se deber�a llamar al m�todo validate() de la action asociada con este mapeo.
  • forward - El path de la URI solicitada a la que se pasa el control cuando se ha invocado su mapeo. Esto es una alternativa a declarar una propiedad type.

.�Fichero de Configuraci�n de los Mapeos de Action

�C�mo aprende el servlet controlador sobre los mapeos que queremos? Ser�a posible (pero tedioso) escribir una peque�a clase Java que simplemente ejemplarizara nuevos ejemplares de ActionMapping, y llamara a todos los m�todos set() apropiados. Para hacer este proceso m�s sencillo, Struts incluye un m�dulo Digester que es capaz de leer la descripci�n basada en XML de los mapeos deseados, creando los objetos apropiados de la misma forma. Puedes encontrar m�s informaci�n sobre este Digester en la documentaci�n del API

La responsabilidad del desarrollador es crear un fichero XML llamado struts-config.xml, y situarlo en el directorio WEB-INF de su aplicaci�n. Este formato de documento est� restringido por su definici�n en "struts-config_1_0.dtd". El elemento XML m�s exterior debe ser <struts-config>.

Dentro del elemento <struts-config>, hay dos elementos importantes que son usados para describir nuestras acciones:

  • <form-beans>
    Esta secci�n contiene nuestras definiciones de beans. Usamos un elemento <form-bean> por cada bean de formulario, que tiene los siguientes atributos importantes:
    • name: Un identificador �nico para este bean, que ser� usado para referenciarlo en los correspondientes mapeos de acciones. Normalmente, es tambi�n el nombre del atributo de solicitud o sesi�n bajo el que se almacena este bean de formulario.
    • type: El nombre totalmente cualificado de la clase Java de nuestro bean de formulario.
  • <action-mappings>
    Esta secci�n contiene nuestras definiciones de acciones. Usamos un elemento <action> por cada una de nuestras acciones que queramos definir. Cada elemento action requiere que se definan los siguientes atributos:
    • path: El path a la clase action en relaci�n al contexto de la aplicaci�n.
    • type: El nombre totalmente cualificado de la clase Java de nuestra clase Action.
    • name: El nombre de nuestro elemento <form-bean> para usar con esta action.

El fichero struts-config.xml de la aplicaci�n de ejemplo incluye las siguientes entradas de mapeo para la funci�n "log on", que se usar� para ilustrar los requerimientos. Oserva que las entradas para otras acciones se han dejado fuera:

<struts-config>
  <form-beans>
    <form-bean
      name="logonForm"
      type="org.apache.struts.example.LogonForm" />
  </form-beans>      
  <global-forwards
      type="org.apache.struts.action.ActionForward" />
    <forward name="logon" path="/logon.jsp"
 redirect="false" /> 
  </global-forwards>      
  <action-mappings>     
    <action
path="/logon" 
type="org.apache.struts.example.LogonAction"
name="logonForm"
       scope="request"
       input="/logon.jsp"
     unknown="false"
    validate="true" />  
  </action-mappings>
</struts-config>

Primero se define el bean formulario, Un bean b�sico de la clase "org.apache.struts.example.LogonForm" es mapeado al nombre l�gico "logonForm". Este nombre se usa como un nombre de atributo de sesi�n o solicitud para el bean de formulario.

La secci�n "global-forwards" se usa para crear mapeos de nombres l�gicos para p�ginas JSP usadas comunmente. Cada uno de estos reenv�os est� disponible a trav�s de una llamada a nuestro ejemplar de mapeo de action, por ejemplo actionMappingInstace.findForward("logicalName").

Como podemos ver, este mapeo corresponde con el path /logon (realmente, porque la aplicaci�n de ejemplo usa mapeo de extensi�n, la URI que especificamos en una p�gina JSP terminar�a en /logon.do). Cuando se recibe una solicitud que corresponde con el path, se crea un ejemplar de LogonAction (s�lo la primera vez). El Servlet controlador buscar� un bean de �mbito de sesi�n bajo la clave logonForm, creando y guardando un bean de la clase especificada si es necesario.

Opcionales pero muy �tiles son los elementos localizados en "forward". En la aplicaci�n de ejemplo, muchas acciones incluyen un reenvio local "success" y/o "failure" como parte de un mapeo de Action.

<!-- Edit mail subscription -->
<action    path="/editSubscription"
  type="org.apache.struts.example.EditSubscriptionAction"
  name="subscriptionForm"
  scope="request"
  validate="false">
  <forward name="failure" path="/mainMenu.jsp"/>
  <forward name="success" path="/subscription.jsp"/>
  </action>

Usando estas dos propiedades extras, las clases Action de la aplicaci�n de ejemplo son casi totalmente independientes de los nombres reales de las p�ginas JSP que son usadas por los dise�adores, Las p�ginas, pueden renombrarse (por ejemplo) durante un redise�o, con un m�nimo impacto en las propias clases Action. Si los nombres de las p�ginas JSP "next" estuvieran codificados dentro de las clases Action, todas estas clases tendr�an que ser modificadas. Por supuesto, podemos definir cualquier propiedad de reenv�o local que tenga sentido para nuestra aplicaci�n.

Una secci�n m�s de buen uso es la secci�n <data-sources>, que especifica las fuentes de datos que puede usar nuestra aplicaci�n. Aqu� podemos ver c�mo especificar una fuente de datos para nuestra aplicaci�n dentro de struts-config.xml:

<struts-config>
  <data-sources>
    <data-source
      autoCommit="false"
     description="Example Data Source Description"
     driverClass="org.postgresql.Driver"
maxCount="4"
minCount="2"
password="mypassword"
     url="jdbc:postgresql://localhost/mydatabase"
    user="myusername"/>
  </data-sources>
</struts-config>

.�Descriptor de Despliegue de la Aplicaci�n Web

El paso final en la configuraci�n de la aplicaci�n es configurar el descriptor de despliegue (almacenado en el fichero WEB-INF/web.xml) para incluir todos los componentes Struts que son necesarios. Usando el descriptor de despliegue del la aplicaci�n de ejemplo como gu�a, veremos que se necesitan crear o modificar la siguientes entradas.

.�Configurar el Ejemplar de Action Servlet

A�adimos una entrada definiendo el propio servlet action, junto con los par�metros de inicializaci�n apropiados. Dicha entrada se podr�a parecer a esto:

<servlet>
  <servlet-name>action</servlet-name>
  <servlet-class>
    org.apache.struts.action.ActionServlet
  </servlet-class>
  <init-param>
    <param-name>application</param-name>
    <param-value>
      org.apache.struts.example.ApplicationResources
    </param-value>
  </init-param>
  <init-param>
    <param-name>config</param-name>
    <param-value>
      /WEB-INF/struts-config.xml
    </param-value>
  </init-param>
  <init-param>
    <param-name>debug</param-name>
    <param-value>2</param-value>
  </init-param>
  <init-param>
    <param-name>mapping</param-name>
    <param-value>
      org.apache.struts.example.ApplicationMapping
    </param-value>
  </init-param>
  <load-on-startup>2</load-on-startup>
</servlet>

Los par�metros de inicializaci�n soportados por el servlet controlador se describen abajo. Los corchetes cuadrados describen los valores por defecto que se asumen si no proporcionamos un valor para el par�metro de inicializaci�n.

  • application - El nombre de la clase Java para la clase base del paquete de recursos de la aplicaci�n. [NONE].
  • bufferSize - El tama�o del buffer de entrada usado para procesar uploads de ficheros. [4096].
  • config - Path relativo al contexto del recurso XML que contiene nuestra informaci�n de configuraci�n.[/WEB-INF/struts-config.xml].
  • content - Tipo de contenido por defecto y codificaci�n de caracteres a seleccionar en cada respuesta; podr�a ser sobreescrito por un servlet re-enviado o una p�gina JSP. [text/html].
  • debug - El nivel de detalle de depuraci�n para este servlet, que controla cuanta informaci�n se pone en el log. [0].
  • detail - El nivel de detalles de depuraci�n para el Digester que utilizamos en initMapping(), que sale por System.out en lugar de servlet log. [0].
  • factory - El nombre de la clase Java del MessageResourcesFactory usado para crear el objeto MessageResources de la aplicaci�n. [org.apache.struts.util.PropertyMessageResourcesFactory].
  • formBean - El nombre de la clase Java de la implementaci�n de ActionFormBean a utilizar. [org.apache.struts.action.ActionFormBean].
  • forward - el nombre de la clase Java de la implemetnaci�n de ActionForward a utilizar. [org.apache.struts.action.ActionForward]. Podr�amos usar aqu� dos clases de conveniencia:
    • org.apache.struts.action.ForwardingActionForward - Subclase de org.apache.struts.action.ActionForward que por defecto pone la propiead redirect a false (lo mismo que el valor por defecto de ActionForward).
    • org.apache.struts.action.RedirectingActionForward - Subclase de org.apache.struts.action.ActionForward que por defecto pone la propiedad redirect a true.
  • locale - Si se selecciona a true, y hay una sesi�n de usuario, indentifica y almacena un objeto java.util.Locale apropiado (bajo la clave est�ndard indentificada por Action.LOCALE_KEY) en la sesi�n de usuario si no hay ya un objeto Locale. [true]
  • mapping - El nombre de la clase Java de la implementaci�n del ActionMapping a utilizar. [org.apache.struts.action.ActionMapping]. Podr�amos usar aqu� dos clases de conveniencia:
    • org.apache.struts.action.RequestActionMapping - Subclase de org.apache.struts.action.ActionMapping que por defecto deja la propiedad scope a "request".
    • org.apache.struts.action.SessionActionMapping - Subclase de org.apache.struts.action.ActionMapping que por defecto deja la propiedad scope a "session". (Igual que el valor por defecto de ActionMapping).
  • maxFileSize - El tama�o m�ximo (en bytes) para que un ficheo sea aceptado para upload. Puede expresarse como un n�mero seguido por una K" "M", o "G", que ser�n interpretadas como kilobytes, megabytes, o gigabytes, respectivamente. [250M].
  • multipartClass - El nombre totalmente cualificado de la clase de la implementaci�n de MultipartRequestHandler usado para procesar uploads de ficheros. [org.apache.struts.upload.DiskMultipartRequestHandler].
  • nocache - Si se selecciona a true, a�ade cabeceras HTTP a cada respuesta para evitar que el navegador almacene en el cah� cualquier respuesta generado o reenviada. [false].
  • null - Si se selecciona a true, configura los recursos de nuestra aplicaci�n a devolver null si se usa una clave de mensaje desconocida. De otra forma, se devolver� un mensaje de error incluyendo la clave err�nea. [true].
  • tempDir - El directorio de trabajo temporal usado cuando se procesan uploads de ficheros. [El directorio de trabajo proporcionado para esta aplicaci�n web como atributo contexto del servlet].
  • validate - �Est�mos suando el nuevo formato de fichero de configuraci�n? [true].
  • validating - �Deber�amos usar un analizador con validaci�n XML para procesar el fichero de configuraci�n (altamente recomendado? [true].

.�Configurar el Mapeo del Servlet Action

Nota: El material de esta secci�n no es espec�fico de Struts. La configuraci�n del mapeo de servlets est� definida en la Java Servlet Specification. Esta secci�n describe los significados m�s comunes de configuraci�n de una aplicaci�n Struts.

Hay dos aproximaciones comunes para definir las URLS que ser�n procesadas por el servlet controlador -- correspondencia de prefijo y correspondencia de extensi�n.

La correspondencia de prefijo significa que queremos que todas las URLs que empiecen con (despu�s de la parte del path de contexto) un valor particular sean pasadas a este servlet. Dicha entrada se podr�a parecer a esto:

  
	<servlet-mapping>
     <servlet-name>action</servlet-name>
     <url-pattern>/execute/*</url-pattern>
   </servlet-mapping>

lo que significa que una URI que coincida con el path /logon descrito anteriormente podr�a parecerse a esto:

http://www.mycompany.com/myapplication/execute/logon

donde /myapplication es el path de contexto bajo el que se ha desplegado nuestra aplicaci�n.

Por otro lado, en el mapeo por extensi�n, se renvian las URIs solicitadas al servlet action bas�ndose en el hecho de que la URI termine en un punto seguido por un conjunto defindo por caracteres. Por ejemplo, el servlet de procesamiento JSP est� mapeado al patr�n *.jsp para que sea llamado cada vez que se solicite una p�gina JSP. Para usar la extensi�n *.do (que implica "hacer algo"), la entrada de mapeo se podr�a parecer a esta:

  <servlet-mapping>
     <servlet-name>action</servlet-name>
     <url-pattern>*.do</url-pattern>
   </servlet-mapping>

y una URI que corresponda con el path /logon descrito anteriormente se parecer�a a esto:

http://www.mycompany.com/myapplication/logon.do

.�Configurar la Librer�a de Etiquetas de Struts

Luego, debemos a�adir una entrada definiendo la librer�a de etiquetas Struts. Actualmente hay cuatro librer�as que vienen con Struts.

La librer�a struts-bean contiene etiquetas �tiles para acceder a los beans y sus propiedades, as� como para definir nuevos beans (basados en esos accesores) que son accesibles para el resto de la p�gina mediante variables de scripting y atributos de �mbito de p�gina. Tambi�n se proporcionan mecanismos convenientes para crear nuevos beans basados en el valor de una cookie, de las cabeceras y de los par�metros.

La librer�a struts-html contiene etiquetas para crear formularios de entrada struts, as� como otras etiquetas generalmente �tiles en la creaci�n de interfaces de usuario basados en HTML.

La librer�a struts-logic contiene etiquetas que son �tiles para manejar la generaci�n condicional de salida de texto, hacer bucles sobre colecciones de objetos para generaci�n repetitiva de salida de texto y control del flujo de la aplicaci�n.

La librer�a struts-template contiene etiquetas que definen un mecanismo de plantillas.

Abajo podemos ver c�mo se definir�an todas las librer�as de etiquetas para usarlas en nuestra aplicaci�n, en realidad, s�lo deber�amos especificar las librer�as que vayamos a utilizar:

<taglib>
  <taglib-uri>
    /WEB-INF/struts-bean.tld
  </taglib-uri>
  <taglib-location>
    /WEB-INF/struts-bean.tld
  </taglib-location>
</taglib>
<taglib>
  <taglib-uri>
    /WEB-INF/struts-html.tld
  </taglib-uri>
  <taglib-location>
    /WEB-INF/struts-html.tld
  </taglib-location>
</taglib>
<taglib>
  <taglib-uri>
    /WEB-INF/struts-logic.tld
  </taglib-uri>
  <taglib-location>
    /WEB-INF/struts-logic.tld
  </taglib-location>
</taglib>
<taglib>
  <taglib-uri>
    /WEB-INF/struts-template.tld
  </taglib-uri>
  <taglib-location>
    /WEB-INF/struts-template.tld
  </taglib-location>
</taglib>

Esto le dice al sistema JSP donde encontrar el descritor de librer�a de etiqueta para esta librer�a (en nuestro directorio WEB-INF de la aplicaci�n, en vez de en alg�n lugar exterior en Internet).

.�A�adir Componentes Struts a nuestra Aplicaci�n

Para usar Struts, debemos copiar los ficheros .tld que necesitamos en nuestro directorio WEB-INF, y copiar struts.jar (y todos los otros ficheros commons-*.jar) en nuestro directorio WEB-INF/lib.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP