Struts - Softclear

Anuncio
Struts
[parte I]
www.softclear.net
Módulo 1
Introducción a Struts
www.softclear.net
¿Qué es Struts?
Marco de trabajo MVC de Apache para la tecnología Java EE
●
Marco de trabajo (framework): extensión de un lenguaje por medio
de una jerarquía de librerías y/o clases
●
Framework
API
JVM
www.softclear.net
Visión Java EE + Struts
Struts Framework
API Java EE
Contenedor
API Java SE
JVM
www.softclear.net
Patrón MVC
Modelo-Vista-Controlador
●
Separación de la lógica de negocio de la lógica de presentación
●
Struts usa MVC en conjunto con Front Controller, Dispatcher, ...
●
www.softclear.net
Ventajas
Velocidad de desarrollo
●
Controlador pre-programado
●
Librerías de etiquetas para evitar “scriptlets”
●
Flujo de acciones basado en XML
●
Extensible con EL
●
Permite el desarrollo separado de lógica de negocio y lógica de
presentación con personal especializado
●
www.softclear.net
Requerimientos
Contenedor web
●
Colocar en la carpeta “lib” de la aplicación a desarrollar:
●
●
●
commons-*.jar, paquete de manipulación de archivos XML de
Apache/Jakarta
struts.jar, paquete de clases definidas en el marco de trabajo
Struts
Los archivos struts-*.tld, librerías de etiquetas Struts para
interfaces web, deben agregarse y especificar su ruta en el
descriptor de despliegue web.xml
●
Todos los archivos son descargables de la sección de Struts en
www.apache.org
www.softclear.net
Carpetas y archivos
www.softclear.net
Clases principales
ActionServlet: Servlet pre-programado para el marco de trabajo
Struts. Hace las veces de Front Controler.
Su ruta es org.apache.struts.action.ActionServlet
●
Action: clase que implementa el patrón Command a fin de ejecutar
determinadas acciones sobre el modelo dependiendo de la petición
que se le haga al ActionServlet.
Hereda de org.apache.struts.action.Action
●
www.softclear.net
Clases principales
ActionForm: Java Bean que contiene los datos de la solicitud
hecha por un formulario al ActionServlet y los valida.
Hereda de org.apache.struts.action.ActionForm
●
ActionMapping: representa las acciones y rutas escritas por el
programador en el archivo de configuración de Struts.
Su ruta es org.apache.struts.action.ActionMapping
●
www.softclear.net
Clases principales
ActionForward: representa el redireccionamiento de la petición
HTTP a un url específico.
Su ruta es org.apache.struts.action.ActionForward
●
ActionError: representa un mensaje de error.
Su ruta es org.apache.struts.action.ActionError.
●
(Esta clase está deprecada y se reemplaza por org.apache.struts.action.ActionMessage)
Más información:
http://struts.apache.org/1.3.8/apidocs/index.html
www.softclear.net
Archivo web.xml
<web-app>
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<jsp-config>
<taglib>
<taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-html.tld</taglib-location>
</taglib>
</jsp-config>
</web-app>
www.softclear.net
Módulo 2
Caso Práctico
www.softclear.net
Caso práctico
www.softclear.net
ActionForm
import org.apache.struts.action.ActionForm
public class RegistroForm extends ActionForm{
protected String username;
protected String password1;
protected String password2;
public String getUsername() {return this.username;}
public String getPassword1() {return this.password1;}
public String getPassword2() {return this.password2;}
}
public void setUsername(String username) {this.username = username;}
public void setPassword1(String password1) {this.password1 = password1;}
public void setPassword2(String password2) {this.password2 = password2;}
www.softclear.net
Action
import org.apache.struts.action.*;
import javax.servlet.http.*;
public class RegistroAction extends Action{
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response){
RegistroForm rf = (RegistroForm) form;
String username = rf.getUsername();
String password1 = rf.getPassword1();
String password2 = rf.getPassword2();
}
}
if(password1.equals(password2)){
try{
UserDirectory.getInstance().setUser(username, password1);
return mapping.findForward(“exito”);
}catch(Exception e){
e.printStackTrace();
return mapping.findForward(“fracaso”);
}
}else{
return mapping.findForward(“fracaso”);
}
www.softclear.net
struts-config.xml
<struts-config>
<form-beans>
<form-bean name=”registroForm” type=”RegistroForm”/>
</form-beans>
<action-mappings>
<action path=”/registro” name=”registroForm”
type=”RegistroAction” input=”/registro.jsp”>
<forward name=”exito” path=”/exito.html” />
<forward name=”fracaso” path=”/fracaso.html” />
</action>
</action-mappings>
</struts-config>
www.softclear.net
exito.html y fracaso.html
exito.html
<html>
<body>
<h1>Exito!</h1>
</body>
</html>
fracaso.html
<html>
<body>
<h1>
<font color=”#ff0000”>
Fracaso!
</font>
</h1>
</body>
</html>
www.softclear.net
registro.jsp
<%@ taglib uri=”/WEB-INF/struts-html.tld” prefix=”html”>
<html>
<body>
<html:form action=”registro.do”>
Login: <html:text property=”username”/> <br/>
Password: <html:password property=”password1”/> <br/>
Confirme su password: <html:password property=”password1”/> <br/>
<html:submit value=”Registro”/>
</html:form>
</body>
</html>
www.softclear.net
Validación en el ActionForm
[hasta Struts 1.2]
import javax.servlet.http.*;
import org.apache.struts.action.*;
public class RegistroForm extends ActionForm{
protected String username;
//...
public String getUsername() {return this.username;}
//...
public void setUsername(String username) {this.username = username;}
//...
}
public ActionErrors validate (ActionMapping mapping,
HttpServletRequest request){
ActionErrors errors = new ActionErrors();
if((username == null) || (username.trim().equals(“”)){
ActionError error = new ActionError(“username.requerido”);
errors.add(“username”, error);
}
return errors;
}
www.softclear.net
Validación en el ActionForm
[desde Struts 1.2]
import javax.servlet.http.*;
import org.apache.struts.action.*;
public class RegistroForm extends ActionForm{
protected String username;
//...
public String getUsername() {return this.username;}
//...
public void setUsername(String username) {this.username = username;}
//...
}
public ActionErrors validate (ActionMapping mapping,
HttpServletRequest request){
ActionErrors errors = new ActionErrors();
if((username == null) || (username.trim().equals(“”)){
ActionMessage error = new ActionMessage(“username.requerido”);
errors.add(“username”, error);
}
return errors;
}
www.softclear.net
Validación en el ActionForm
<struts-config>
<form-beans>
<form-bean name=”registroForm” type=”RegistroForm”/>
</form-beans>
<action-mappings>
<action path=”/registro” name=”registroForm”
type=”RegistroAction” input=”/registro.jsp”
validate=”true”>
<forward name=”exito” path=”/exito.html” />
<forward name=”fracaso” path=”/fracaso.html” />
</action>
</action-mappings>
</struts-config>
www.softclear.net
Mensajes en i18n
El archivo por defecto de todos los mensajes es
ApplicationResources.properties
●
Ejemplo del contenido de un archivo
ApplicationResources.properties:
●
username.requerido = <b>Por favor, ingrese el login</b>
username.default = Pedro Perez
La ruta del archivo de propiedades debe ser especificada en el
archivo de configuración de struts y es relativa a la carpeta classes
dentro de WEB-INF:
●
<struts-config>
<message-resources parameter="com/myapp/struts/ApplicationResource" />
</struts-config>
www.softclear.net
Mensajes e i18n
Para usar internacionalización solo se debe crear el archivo del
idioma especificando en el nombre de este el acrónimo que
representa dicho idioma. El archivo debe ser almacendo junto al
archivo por defecto ApplicationResources.properties. Ej:
ApplicationResources_es.properties
●
El browser del cliente está definido por lo general para un idioma
de preferencia, si existe el archivo
ApplicationResources_XX.properties para dicho idioma, este es
seleccionado, en caso contrario se selecciona el archivo de
propiedades por defecto
●
Ejemplo para ApplicationResources_en.properties:
●
username.requerido = <b>Please, insert a login</b>
username.default = John Doe
www.softclear.net
Módulo 3
Librerías de etiquetas
www.softclear.net
Grupos de etiquetas
HTML: struts-html.tld, de uso frecuente en la creación de
formularios HTML que introducen datos al marco de trabajo.
[http://struts.apache.org/1.2.7/userGuide/struts-html.html]
●
Bean: struts-bean.tld, manipulación de Java Beans análogo a los
JSTL.
[http://struts.apache.org/1.2.7/userGuide/dev_bean.html]
●
Logic: struts-logic.tld, manejo dinámico de condiciones análogo a
los JSTL.
[http://struts.apache.org/1.2.7/userGuide/dev_logic.html]
●
www.softclear.net
Grupos de etiquetas
Tiles: struts-tiles.tld, etiquetas especializadas en el manejo de
plantillas.
[http://struts.apache.org/1.2.7/userGuide/dev_tiles.html]
●
Nested: struts-nested.tld, extensión utilitaria de las etiquetas
anteriores.
[ http://struts.apache.org/1.2.7/userGuide/dev_nested.html]
●
www.softclear.net
Ejemplo clásico de errores
<%@ taglib prefix="html" uri="/struts-html.tld" %>
<%@ taglib uri=”/WEB-INF/struts-html.tld” prefix=”html”>
<html>
<body>
<html:form action=”registro.do”>
<!--Imprimir solo los errores de login-->
<!--La propiedad username en insertada-->
<!--al adjuntar el error en el ActionForm-->
<div align="center">
<html:errors property=”username”/>
</div>
Login: <html:text property=”username”/> <br/>
Password: <html:password property=”password1”/> <br/>
Confirme su password: <html:password property=”password1”/> <br/>
<html:submit value=”Registro”/>
</html:form>
</body>
</html>
www.softclear.net
...un último paso
Para que los errores salgan en la página del formulario que la
originó, no es necesario tener un forward asociado:
<struts-config>
<form-beans>
<form-bean name=”registroForm” type=”RegistroForm”/>
</form-beans>
<action-mappings>
<action path=”/registro” name=”registroForm”
type=”RegistroAction” input=”/registro.jsp”>
<forward name=”exito” path=”/exito.html” />
</action>
</action-mappings>
</struts-config>
www.softclear.net
Ejemplo clásico de errores
<%@ taglib prefix="html" uri="/struts-html.tld" %>
<%@ taglib uri=”/WEB-INF/struts-html.tld” prefix=”html”>
<html>
<body>
<!--Imprimir todos los errores -->
<div align="center">
<html:errors/>
</div>
<html:form action=”registro.do”>
Login: <html:text property=”username”/> <br/>
Password: <html:password property=”password1”/> <br/>
Confirme su password: <html:password property=”password1”/> <br/>
<html:submit value=”Registro”/>
</html:form>
</body>
</html>
www.softclear.net
Módulo 4
Ejercicios propuestos
www.softclear.net
Retos
A fin de obtener una mayor experticia en el marco de trabajo Struts,
se recomienda llevar a cabo los siguientes retos:
Crear una aplicación basada en Struts que imprima en una página
JSP una lista de objetos colocados en la sesión por un Action y sus
errores, con la menor cantidad de código posible utilizando
Expression Language, JSTL y Struts Tag Libraries.
●
Modificar el idioma del site por medio de Struts una vez que un
usuario seleccione su idioma de una lista sin depender del idioma
del browser
●
Realizar un request en Ajax a un url esperado por el ActionServlet
de Struts
●
Realizar una solicitud de información en un dispositivo móvil por
medio de un HttpConnection a un ActionServlet
●
www.softclear.net
Módulo 5
Struts + XDoclet
www.softclear.net
DRY
DRY – Don´t Repeat Yourself
●
Principio de diseño
●
Java EE posee graves problemas sobre este principio
●
Struts no escapa del problema
● Programar los Action y ActionForm es repetitivo
● Los tags xml del archivo de configuración de Struts son
repetitivos
● Al crear un Action o un ActionForm hay que alterar el archivo
de configuración, por lo que la información está en dos lugares
● El Action no sabe el flujo a recorrer, él consulta el archivo de
configuración xml
●
www.softclear.net
XDoclet
Motor de plantilla de metadatos
[programación orientada a atributos]
●
Originalmente creado para solventar el problema de DRY en los
EJB
●
Opera como tareas de Ant [similar a “make”] que facilita la
ejecución de tareas rutinarias
●
Sitio web: http://www.xdoclet.org/
●
En los últimos años ha extendido su comportamiento en pro de
facilitar el desarrollo de diversos componentes, entre ellos Struts
●
www.softclear.net
Problema
¿Qué pasa si eliminamos un Action o un ActionForm?
Hay que eliminar a mano los tags correspondientes del archivo de
configuración
●
¿Qué pasa si olvidamos eliminar los tags en el archivo de
configuración?
Error
●
Este proceso es frecuente y depende mucho del ser humano, del
desarrollador
●
www.softclear.net
Solución
XDoclet provee un mecanismo simple para la generación del
archivo de configuración y la consolidación de información en un
solo lugar: la clase correspondiente
●
De esta forma la clase contiene toda la información pertinente a
ella y solo a ella
●
Al ser eliminada la clase, también es eliminada toda información
relativa a ella puesto que no se generará de nuevo el archivo de
configuración con la información que ella provee
●
www.softclear.net
Solución
XDoclet provee un mecanismo simple para la generación del
archivo de configuración y la consolidación de información en un
solo lugar: la clase correspondiente
●
De esta forma la clase contiene toda la información pertinente a
ella y solo a ella
●
Al ser eliminada la clase, también es eliminada toda información
relativa a ella puesto que no se generará de nuevo el archivo de
configuración con la información que ella provee
●
www.softclear.net
Ejemplo - build.xml
<!--archivo de ant build.xml-->
<target name="webdoclet" depends="init">
<taskdef name="webdoclet" classname="xdoclet.modules.web.WebDocletTask">
<classpath>
<path refid="xdoclet.classpath" />
</classpath>
</taskdef>
<!--correr con "-Dxdoclet.force=true" para forzar la creacion de arch.-->
<webdoclet destdir="${build.web.dir}/WEB-INF"
force="${xdoclet.force}"
mergedir="metadata">
<fileset dir="src" />
<strutsconfigxml version="1.1"
xmlencoding="ISO-8859-1"
validateXML="true"
templateFile="metadata/struts/struts_config_xml.xdt"
mergeDir="metadata/struts" />
<strutsvalidationxml />
</webdoclet>
</target>
www.softclear.net
Ejemplo - build.xml
<!--archivo de ant build.xml-->
<target name="webdoclet" depends="init">
<taskdef name="webdoclet" classname="xdoclet.modules.web.WebDocletTask">
<classpath>
<path refid="xdoclet.classpath" />
Localización de los archivos .jar
</classpath>
</taskdef>
<!--correr con "-Dxdoclet.force=true" para forzar la creacion de arch.-->
<webdoclet destdir="${build.web.dir}/WEB-INF" Directorio destino
force="${xdoclet.force}"
mergedir="metadata">
<fileset dir="src" /> Directorio fuente
<strutsconfigxml version="1.1"
xmlencoding="ISO-8859-1"
validateXML="true"
templateFile="metadata/struts/struts_config_xml.xdt"
mergeDir="metadata/struts" /> Directorio de archivos a incluir en
el struts-config.xml
<strutsvalidationxml />
Genera el archivo validate.xml
</webdoclet>
</target>
www.softclear.net
Merge
<strutsconfigxml version="1.1" xmlencoding="ISO-8859-1" validateXML="true"
templateFile="metadata/struts/struts_config_xml.xdt" mergeDir="metadata/struts" />
El directorio indicado por “mergeDir” es la fuente de los tags xml
que no serán mantenidos por XDoclet
●
Los archivos que contiene son:
● struts-data-sources.xml
● struts-forms.xml
● global-exceptions.xml
● global-forwards.xml
● struts-actions.xml
● struts-controller.xml
● struts-message-resources.xml
● struts-plugins.xml
●
www.softclear.net
Action
/**
* @struts.action name="registroForm" path="/registro"
* scope="request" validate="true" input="/registro.jsp"
*
* @struts.action-forward name="exito" path="/exito.html"
*
* @struts.action-forward name="fracaso" path="/fracaso.html"
*/
import org.apache.struts.action.*;
import javax.servlet.http.*;
public class RegistroAction extends Action{
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response){
RegistroForm rf = (RegistroForm) form;
String username = rf.getUsername();
String password1 = rf.getPassword1();
}
}
UserDirectory.getInstance().setUser(username, password1);
return mapping.findForward(“exito”);
www.softclear.net
ActionForm
/**
* @struts.form name="registroForm"
*/
import javax.servlet.http.*;
import org.apache.struts.action.*;
public class RegistroForm extends ActionForm{
protected String username;
//...
public String getUsername() {return this.username;}
//...
public void setUsername(String username) {this.username = username;}
//...
}
public ActionErrors validate (ActionMapping mapping,
HttpServletRequest request){
ActionErrors errors = new ActionErrors();
if((username == null) || (username.trim().equals(“”)){
ActionMessage error = new ActionMessage(“username.requerido”);
errors.add(“username”, error);
}
return errors;
}
www.softclear.net
Validación en el ActionForm
<struts-config>
<form-beans>
<form-bean name=”registroForm” type=”RegistroForm”/>
</form-beans>
<action-mappings>
<action path=”/registro” name=”registroForm”
type=”RegistroAction” input=”/registro.jsp”
validate=”true”>
<forward name=”exito” path=”/exito.html” />
<forward name=”fracaso” path=”/fracaso.html” />
</action>
</action-mappings>
</struts-config>
www.softclear.net
Requerimientos e instalación
Ant 1.5 en adelante
●
“tools.jar” debe estar en <directorio jdk>/lib para manipular del jdk
●
●
www.softclear.net
Descargar