VISITAS:

martes, 23 de abril de 2013

Introducción a Struts 2

Struts 2 es un framework para el desarrollo de aplicaciones web basado en:

  • Acciones
  • Interceptores
  • Librería de tags

Acciones

Una acción puede ser cualquier clase Java que cumpla con las condiciones del framework.
Una acción hace tres cosas:
  • Realiza la lógica asociada a una request. Esta lógica se implementa en el método execute() de la acción. Una acción no trata con la request del servlet, ni con la response. Trata con la lógica de negocio.
  • Contiene los datos que vienen de la request y que van al resultado. Estos datos se almacenan como atributos de la acción. Al estar los datos disponibles en la acción, siempre estarán disponibles para la ejecución de la lógica de negocio. La acción simplemente implementa propiedades tipo javabean para cada dato que tiene que transportar. Los parámetros de la request que coinciden con propiedades de la acción se rellenan automáticamente antes de ejecutar la acción. Además, estas propiedades tipo javabean, también estarán disponibles para renderizar el resultado (por ejemplo en la página JSP).
  • Decide cuál es el resultado que se debe visualizar. Cada acción retorna un String que selecciona el resultado que se va a renderizar.

Paquetes de acciones

Los paquetes son contenedores lógicos de acciones.
Un paquete define el namespace (URL base) para todas las acciones de ese paquete y los interceptores que se activarán en todas las acciones del paquete.
Un paquete puede heredar de otro paquete, tomando todas las propiedades del paquete padre, pudiendo añadir nuevas propiedades. Si no heredamos de otro paquete, deberíamos al menos heredar del paquete struts-default, que viene definido en la distribución de struts (fichero struts2-core.jar, struts-default.xml).
Cada paquete define los interceptores y pilas de interceptores que utilizarán las acciones de ese paquete. En caso de herencia, se heredan las pilas e interceptores de la clase padre. Se define una pila de interceptores por defecto, que será la que se ejecute en caso de que la acción no declare otra específicamente.
Normalmente, las acciones se organizan en paquetes por funcionalidad o por nivel de seguridad (por ejemplo un paquete para acciones que requieren autenticación previa y otro paquete para acciones que no requieren autenticación).

Paquete struts-default

Este paquete que viene con la distribución de struts2 (está dentro del fichero struts-core.jar) contiene muchos componentes que se pueden recoger al heredar de este paquete. Es el fichero struts-default.xml
Uno de los componentes más importantes dentro de struts-default es la pila de interceptores por defecto, o defaultStack. Esta pila de interceptores se aplica por defecto a todas las acciones dentro de los paquetes que heredan de struts-default (salvo que se defina otra pila por defecto).
Por ejemplo, la pila por defecto incluye un interceptor llamado params que se encarga de pasar los datos de la request a propiedades de la acción (javabean).
Lo habitual es que todos los paquetes que definamos hereden del paquete struts-default obteniendo así automáticamente las funcionalidades que ofrece este paquete, entre otras, la pila de interceptores por defecto.

Implementar acciones 

Una acción es cualquier clase java que tiene un método execute(). No tiene que heredar de ninguna otra clase ni implementar ningún interfaz. Sin embargo, es útil que las acciones implementen el interfaz Action, ya que entonces tendrán acceso a las constantes definidas en este interfaz. Son constantes para los valores retornados por el método execute: ERROR, SUCCESS, INPUT, LOGIN, NONE. El resultado retornado por la acción determina lo que Struts va a ejecutar la finalizar la acción. Si retorna SUCCESS, el framework dirige a la página definida como SUCCESS para la acción. Si retorna ERROR, el framework dirige a la página definida como ERROR para la acción.
Si deseamos obtener algo más de funcionalidad, podemos heredar nuestra acción de la clase ActionSupport, la cual implementa el interfaz Action. Pero además, implementa otros interfaces muy útiles para internacionalización y validación, proporcionando una implementación por defecto muy útil. Veamos a continuación estas dos importantes funcionalidades: validación e internacionalización.

Validación básica

La clase ActionSupport proporciona una validación básica que será suficiente en muchos casos. El requisito para poder utilizar esta funcionalidad de validación básica es heredar nuestro paquete del paquete struts-default y que nuestra clase acción herede de la clase ActionSupport.
La pila de interceptores por defecto (defaultStack) introduce un interceptor denominado workflow, de la clase Java DefaultWorkflowInterceptor. Este interceptor desvía el flujo a la página de entrada (página llamante) si ocurre un error en la validación. Este interceptor se ejecuta después que el interceptor params, o sea, cuando los datos ya están metidos en los atributos de la acción.
Veamos cómo se ejecuta el interceptor workflow. Cuando se dispara este interceptor, busca un método validate() en la acción. Este método puede chequear los atributos de la acción y detectar errores en los valores pasados como parámetros. Cada vez que ocurre un error de validación, se añade este error a una lista utilizando el método AddFieldError() que proporciona ActionSupport. Después de ejecutarse el método validate() de la acción, el control vuelve al interceptor workflow, el cual mira si se ha generado algún error. Si hubiera algún error, este interceptor altera el flujo de la request y devuelve el control a la página de entrada, mostrando el error junto al campo o campos que han provocado el error.
El método validate() tiene dos opciones para generar errores:
  • addFieldError(fieldName, errorMessage) : genera un error de validación asociado a un campo de entrada
  • addActionError(errorMessage) : genera un error de validación a nivel de acción
Como se puede ver hasta ahora, la filosofía de struts es dejar toda la lógica de negocio en el método execute() de la acción. Todo lo demás, validaciones, paso de parámetros, etc. queda fuera de este método.

Internacionalización

La clase ActionSupport proporciona también una implementación para el manejo de la internacionalización, es decir, gestiona los ficheros de mensajes en varios idiomas. Tenemos a nuestra disposición el método getText() de la clase ActionSupport para obtener mensajes a partir de un clave. Estos mensajes están en un fichero asociado a la acción y se recuperan a partir de una clave. El fichero de mensajes tiene el mismo nombre que la clase que implementa la acción y tiene que estar en el mismo paquete java. Este fichero es un fichero de properties normal de java.
Para definir ficheros de mensajes en varios idiomas, añadiremos a cada uno en el nombre el sufijo con el idioma correspondiente: XXX_es.properties.

Transferencia de datos a la acción

Hasta ahora hemos visto que los datos que  vienen en la request se pueden transferir a atributos de la clase acción. Esos datos son simples. Por ejemplo, si en la request va un atributo que se llama "nombre", el interceptor param intentará transferirlo al atributo "nombre" de la acción, a través de los métodos setNombre() y getNombre().