NF3 - Framework JSP (15h)

De wikiserver
Dreceres ràpides: navegació, cerca

STRUTS2

Struts2 és framework d'aplicacions web populars basada en el patró de disseny MVC. Struts2 no és només la propera versió de Struts 1, però és una reescriptura completa de l'arquitectura Struts.

Característiques

  • Formes POJO i accions POJO - Struts2 ha acabat amb les formes d'acció que van ser una part integral del marc de treball Struts. Amb Struts2, es pot utilitzar qualsevol POJO per rebre el formulari d'entrada. De la mateixa manera, ara es pot veure qualsevol POJO com una classe d'Acció.
  • Compatible amb etiquetes - Struts2 ha millorat les etiquetes de formulari i les noves etiquetes permeten als desenvolupadors escriure menys codi.
  • Suport AJAX - Struts2 ha integrat AJAX en el framework mitjançant la creació d'etiquetes d'AJAX, que funciona de manera molt similar a les etiquetes estàndard struts2.
  • Fàcil integració - Integració amb altres frameworks com Spring i SiteMesh.
  • Plantilles - Suport per utilitzar plantilles.
  • Suport Plugin - El comportament de Struts2 pot ser millorada utilitzant plugins. Existeixen una sèrie molt variada de plugins que estan disponibles per Struts2.
  • Entorns - Struts2 ofereix l'entorn per depurar i l'entorn de l'aplicació. A més d'això, Struts també ofereix depuració integrada amb l'ajuda de eines de depuració.
  • Fàcil modificar etiquetes - Els Tag Struts2 poden ser ajustats utilitzant plantilles Freemarker.


Instal·lació i configuració de Struts amb Netbeans

Per instal·lar els plugins de Stuts2 en Netbeans pots seguir aquesta mini guia: M7-UF2-Guia-Instalacio-Struts2-Netbeans

Arquitectura Struts2

Struts2 és un framework basat en el patró de disseny pull-MVC (o MVC2). El patró Model-View-Controller en Struts2 es realitza amb els següents cinc components bàsics:

  • Interceptors
  • Actions
  • Value Stack / OGNL
  • Results / Result types
  • View technologies

Struts 2 és lleugerament diferent d'un marc MVC tradicional. L'acció es troba al model més que en el controlador i existeix un cert solapament.

Struts 2 architecture.gif

El controlador s'implementa amb un filtre de servlet dispatch Struts2 així com interceptors, el model s'implementa amb accions, i la vista com una combinació de tipus de resultats i els resultats. La Value Stack / OGNL proporcionen fil comú, que uneix i permet la integració entre els altres components.

A més dels components anteriors, hi haurà una gran quantitat d'informació referent configuració del framework amb els components anteriors.

Aquest és el panorama arquitectònic del patró MVC Struts 2.

Cicle de vida

Basat en el digrama anterior, es pot explicar el cicle de petició vida de l'usuari en Struts 2 com segueix:

  • L'usuari envia una petició al servidor per sol·licitar algun recurs (és a dir, pàgines).
  • El FilterDispatcher mira la sol·licitud i determina l'acció apropiada.
  • S'apliquen els interceptores configurats (ex: validació, càrrega d'arxius, etc.)
  • S'executa l'acció seleccionada per realitzar l'operació sol·licitada.
  • S'apliquen els interceptors configurats per fer qualsevol processament posterior, si es requereix.
  • Finalment el resultat es prepara per la vista i es retorna a l'usuari.

Cicle vida struts2.png

Interceptors

Els interceptors són classes que s'empren per especificar el cicle de vida d'una petició, i estan pensades per afegir funcionalitat extra a les actions. Podríem dir que un interceptor és semblat a un filtre de J2EE tret que el seu ús és més localitzat i es pot fer dependre de actions concrets i no que s'executi de forma global. Per configurar-los es fa de forma declarativa.

Els interceptors es solen usar per realitzar validacions, workflows, etc..., i quan es defineixen sobre un action, s'executen com els filtres, és a dir, de forma consecutiva com una cadena.

Actions

Els actions són POJOs (Plain Old Java Object). Qualsevol classe java amb un mètode execute() pot actuar com un Action. Així no es fa necessari implementar cap interfície.

package exemple;

import com.opensymphony.xwork2.ActionSupport;
import java.util.Date;

public class HolaMon extends ActionSupport {
	public static final String MESSAGE = "Hola a tots";
	private String message;

	public String execute() throws Exception {
		setMessage(MESSAGE);
		return SUCCESS;
	}

	public void setMessage(String message){
		this.message = message;
	}
	
	public String getMessage() {
		return message;
	}
	
	public String getCurrentTime(){
		return new Date().toString();
	}
}

Result

Totes les Actions han de retornar el Result a utilitzar per tal de renderitzar la JSP apropiada. Aquest Result s'identifica amb una cadena que s'utilitza en el fitxer struts.xml per associar-lo amb la pàgina JSP apropiada. En el cas que la cadena sigui la constant SUCCESS s'utilitzarà el result per defecte (el que no té un nom assignat). Los Results estàndards que es poden enviar son:

  • SUCCESS
  • ERROR (pàgina jsp d'error)
  • INPUT (pàgina jsp de validació dels inputs d'un formulari)

El gestor de la configuració

El gestor de la configuració és l'element encarregat de llegir el fitxer de control (struts.xml), analitzar-ho i en el cas que sigui correcte desplegar aquells elements que es referencien.

Exemple de configuració (struts.xml):

<struts>
    <include file="exemple.xml"/>
    <!-- Configuration for the default package. -->
    <package name="default" extends="struts-default">
    </package>
</struts>

##i el fitxer exemple.xml:
<struts>
    <package name="exemple" namespace="/exemple" extends="struts-default">
        <action name="HolaMon" class="exemple.HolaMon">
	    <result name="error">/exemple/error.jsp</result>
            <result>/exemple/HolaMon.jsp</result>
        </action>
    </package>
</struts>

## Els dos fitxers, struts.xml i exemple.xml han de estar en el mateix directori.

Per aclarir idees i mostrar com és l'arquitectura de Struts 2 s'afegeix un diagrama en el qual es pot veure de forma gràfica quina elements són els que intervenen dins del processament d'una petició HTTP, distingint-se quins són elements d'estàndards de J2EE, quins són elements propis de Struts 2 i quins són creats per l'usuari.

Arquitectura real.png

El Fitxer de configuració struts.xml

El framework Struts 2 utilitza un fitxer de configuració anomenat struts.xml per inicialitzar els recursos, com poden ser:

  • Interceptors que poden processar, abans o després, una petició.
  • Actions que modifiquen la lògica de negoci i accedeixen a les dades
  • Results que poden preparar les vistes utilitzant JavaServer o FreeMarker.

El fitxer struts.xml és el fitxer central de la configuració del framework i ha d'estar en el classpath de l'aplicació web.

Les seves característiques son les següents:

  • Permet la seva descomposició en petits fitxers de configuració xml que han d'estar inclosos en el principal.

Exemple:

<struts>
	.....
	......
	<include file="file1.xml"/>
	<include file="file2.xml"/>
	.....
	.....
</struts>

Un error en qualsevol d'aquests fitxers produeix que l'aplicació no es pugui carregar.

En aquest enllaç podeu trobar el DTD del fitxer de configuració struts.xml DTD-struts2

L'etiqueta Package

Els paquets s'utilitzen per agrupar actions, results, type results, interceptors i interceptors stack. Els paquets son similars als objectes de manera que poden heretar (extends) uns dels altres.

El tag <package /> s'utilitza per agrupar les configuracions que tinguin atributs en comú (interceptors o namespaces).

El package té els següents atributs:

  1. name: ha d'identificar de manera única un paquet. Aquest atribut és l'únic obligatori.
  2. extends: Identifica el nom del paquet del que heretarà tota la informació de configuració, incloent la configuració dels action. D'aquesta manera, tota la configuració del paquet estarà disponible en un nou paquet, sota un nou nom.
  3. namespace: s'afegeix el namespace a les URL del paquet. Por exemple, per dos paquets diferents, con noms “pack1” i “pack2”, la URL te la següent forma: “/webApp/pack1/my.action” i “/webAppl/pack2/my.action”.
  4. abstract: si el valor d'aquest atribut és true, el paquet és una agrupació de configuracions i actions que no serán accesibles vía el

nom del paquet. Es important assegurar-se de que se algún altre paquet l'hereta per a que la seva configuració esté disponible.

L'etiqueta include

El tag <include /> s'utilitza per modularitzar una aplicació struts2. Només conté un atribut file amb el nom del fitxer que s'inclourà. Els fitxers tenen la mateixa estructura que struts.xml Exemple:

<struts>
<include file="invoices-config.xml" />
<include file="admin-config.xml" />
<include file="reports-config.xml" />
</struts>

L'etiqueta Bean

Aquesta etiqueta ens permet definir Beans globals, però no es sol necessitar en la majoria d'aplicacions. Es necessiten

  1. class:És l'unic atribut obligatori. Identifica la classe que implementa el Bean.
  2. type:Interface que implementa el Bean.
  3. name:Nom del bean per a que poguem recuperar-lo en les pàgines.
  4. scope:Àmbit del bean. Aquest pot ser: Default, singleton, request, session o thread.

Exemple:

<struts>
	...
<bean type="net.ObjectFactory" name="factory" class="sample.MyObjectFactory" />
	...
</struts>

L'etiqueta constant

Les constants realitzen dos funcions:

  1. Representar les dades, ex: MAX_FILESIZE: mida màxima d'un fitxer que es pot penjar.
  2. Especificar el Bean escollit, d'entre les múltiples implementacions que poden existir.

Les constants es poden declarar en múltiples fitxers, el frmework de struts els cercarà en el següent ordre:

  • struts-default.xml
  • struts-plugin.xml
  • struts.xml
  • struts.properties
  • web.xml

Exemple:

<struts>
	...
	<constant name="struts.devMode" value="true" />
	...
</struts>

URL

Url-struts2.png

Canviar l'extensió final del action

Cal afegir la següent configuració dintre del fitxer web.xml:

<init-param>
            <param-name>struts.action.extension</param-name>
            <param-value></param-value>
 </init-param>

Si no posem res dintre de param-value no caldrà afegir cap extensió a la URL.

El Fitxer web.xml quedaria de la següent manera:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
        <init-param>
            <param-name>struts.action.extension</param-name>
            <param-value></param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>example/HelloWorld.jsp</welcome-file>
    </welcome-file-list>
</web-app>

Exercici Hola Mon

La pàgina de benvinguda ha de mostrar el text: "hola a tots. Benvinguts a la pàgina de M7" i a més a més, ha de mostrar la data actual.

  • Creació del Package exemple
  • Crea el controlador (Action).
#Controlador HolaMon.java
package exemple;

import com.opensymphony.xwork2.ActionSupport;
import java.util.Date;

public class HolaMon extends ActionSupport {
	public static final String MESSAGE = "Hola a tots";
	private String message;

	public String execute() throws Exception {
		setMessage(MESSAGE);
		return SUCCESS;
	}

	public void setMessage(String message){
		this.message = message;
	}
	
	public String getMessage() {
		return message;
	}
	public String getCurrentTime(){
		return new Date().toString();
	}
}
  • Creació de la vista (HolaMon.jsp) en el directori pages:
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
	<head>
		<title>Hola Mon!</title>
	</head>
	<body>
		<h2><s:property value="message" /></h2>
		<p>La data actual és: <b><s:property value="currentTime" /></b>
	</body>
</html>
  • Creació del fitxer de configuració
<struts>
	<constant name="struts.enable.DynamicMethodInvocation" value="false" />
	<constant name="struts.devMode" value="true" />
	<package name="exemple" namespace="/" extends="struts-default">
		<action name="HolaMon" class="exemple.HolaMon">
			<result>/pages/HelloWorld.jsp</result>
		</action>
	</package>
</struts>

Com funciona l'aplicació HolaMon?

El navegador envia una petició al servidor web mitjançant la adreça:

http://ip-server/struts2/HolaMon.action.

  • El servidor intenta buscar el recurs HolaMon.action. Struts 2 configura el web.xml de tal forma que envia les peticions al filtre org.apatxe.struts2.dispatcher.FilterDispatcher.

El fitxer de configuració web.xml conté el següent:

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

<filter-mapping>
	<filter-name>struts2</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>
  • El framework busca el action HelloWorld utilitzant el fitxer struts.xml. En trobar una definició de action que correspon amb el patró de la url, crea una instància de la classe corresponent que apareix en el attribute class. Utilitzant el API d'introspecció realitza la crida al mètode execute() de l'objecte.
  • A continuació el mètode execute fixa el missatge i retorna SUCCESS.
  • El framework determina què pàgina es carrega en el cas que SUCCESS sigui retornat. Per a això identifica que si es retorna SUCCESS buscarà en el xml l'etiqueta action result que no tingui cap name. En el nostre cas, el servidor carrega la pàgina HolaMon.jsp.

Etiquetes Struts2

Podem dividir les etiquetes del framework de Struts2 en dos tipus:

  • Etiquetes genèriques: Son les etiquetes que corresponen al control del flux d'execució i les etiquetes corresponents a la manipulació de dades.
  • Etiquetes d'intefície d'usuari (UI): Mostren informació al usuari que provenen de les propietats dels actions.

Aquestes etiquetes es'utilitzen en les pàgines JSP.

Exemple de Tags genèrics

  • if
  • elseIf
  • else
  • append
  • generator
  • iterator
  • merge
  • sort
  • subset
  • a
  • action
  • bean
  • date
  • Debug
  • i18n
  • include
  • param
  • Push
  • set
  • text
  • url
  • property

Exemple de Tags UI

  • autocompleter
  • checkbox
  • checkboxlist
  • combobox
  • datetimepicker
  • doubleselect
  • Head
  • file
  • form
  • Hidden
  • label
  • optiontransferselect
  • optgroup
  • password
  • radio
  • reset
  • select
  • submit
  • textarea
  • textfield
  • token
  • updownselect
  • actionerror
  • actionmessage
  • fielderror

Podeu trobar informació sobre aquest tags en la següent URL: reference

Exemple d'una Etiqueta genèrica iterator

/*Action associat**/
import com.opensymphony.xwork2.ActionSupport;
import java.util.*;

public class iteratorTag extends ActionSupport{
	private List myList;

	public String execute()throws Exception{
		myList = new ArrayList();
		myList.add("Fruits");
		myList.add("Apple");
		myList.add("Mango");
		myList.add("Orange");
		myList.add("Pine Apple");
	return SUCCESS;
	}

	public List getMyList(){
	return myList;
	}
}
<!--JSP associada al SUCCESS del action anterior!-->
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
	<head>
		<title>Iterator Tag Example!</title>
	</head>
	<body>
		<h1><span style="background-color:#FFFFcc">Iterator Tag Example!</span></h1>
		
		<s:iterator value="myList">
			<s:property /><br>
		</s:iterator>
	</body>
</html>

Exemple d'una etiqueta de UI de formulari

/*Action associat*/
import com.opensymphony.xwork2.ActionSupport;
import java.util.HashMap;

@SuppressWarnings("serial")
public class Accion extends ActionSupport {

    private HashMap<String, String> registrados;
    private HashMap<String, String> vips;

    public HashMap<String, String> getVips() {
        return vips;
    }

    public void setVips(HashMap<String, String> vips) {
        this.vips = vips;
    }

    public HashMap<String, String> getRegistrados() {
        return registrados;
    }

    public void setRegistrados(HashMap<String, String> registrados) {
        this.registrados = registrados;
    }

    public String execute() {
        registrados = new HashMap<String, String>();
        registrados.put("Juan", "Juan Encina");
        registrados.put("Manuel", "Manuel Robledo");
        vips = new HashMap<String, String>();
        vips.put("Pedro", "Pedro Peral");
        vips.put("María", "María Manzano");
        return SUCCESS;
    }
}
<!-- JSP associada al action anterior !-->
<%@ taglib uri="/struts-tags" prefix="s"%>
<html>
	<body>
		<s:form action="Otro">
			<s:optiontransferselect list="registrados" leftTitle="Registrados"
				doubleList="vips" rightTitle="VIPs" doubleName="usuarios" />
			<s:submit value="Enviar" />
		</s:form>
	</body>
</html>

Vista renderitazada:

Exemple-etiqueta-form-struts2.png

Exercici Login

Es vol fer la validació, mitjançant un formulari, d'un usuari. Els volrs del usuari no es trobaran emmagatzemats en una base de dades, si no, que es trobaran en el mateix Action. Funcionament:

  1. La pàgina de login mostrarà el formulari d'entrada.
  2. L'usuari introduirà el nom i la paraula de pas, i clicarà en el botó de login.
  3. La validació del usuari es realitzarà en el action.
    1. Nom usuari: admin
    2. Paraula de pas:admin
  4. Si la validació és correcta, es mostrarà una pàgina que indiqui que ha entrat a l'aplicació.
  5. Si la validació és incorrecta, es veurà una pàgina d'error amb un missatge que indiqui el problema

Els Interceptors

Interceptor és un objecte que intercepta una acció dinàmica. S'executa abans i després de l'execució de l'acció.

  • La Sol·licitud és generat per l'usuari i s'envia al contenidor servlet.
  • El contenidor de servlets invoca filtre FilterDispatcher que al seu torn determina l'acció apropiada.
  • Un per un, els Intercetors s'apliquen abans de cridar a l'acció. Els Interceptors porta a terme tasques com el login, la validació, càrrega d'arxius, doble-submit etc.
  • S'executa l'Action i es retorna un Result
  • Segons el Result generat, es presenta la vista apropiada a l'usuari (JSP, Velocity, etc.).

Exemple:

package exemple;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;

public class ExempleInterceptor implements Interceptor{

    @Override
    public void destroy() {
        
        
    }

    @Override
    public void init() {
            
    }

    @Override
    public String intercept(ActionInvocation actionInvocation) throws Exception {
        
        String startInterceptor="   Comença 1";
        System.out.println(startInterceptor);
        String result=actionInvocation.invoke();
        String endInterceptor="   Acaba 1";
        System.out.println(endInterceptor);
        return result;
    }

}

El Interface Interceptor (com.opensymphony.xwork2.interceptor) és una classe sense estat. La interfície Interceptor té tres mètodes que són els següents:

  • void destroy () - Aquest mètode s'utilitza per netejar els recursos assignats a l'interceptor.
  • void init () - Aquest mètode es crida en el moment de la creació d'intercepció, però abans del processament de la sol·licitud. S'utilitza per inicialirzar qualsevol recurs que necessiti l'interceptor.
  • String intercept (ActionInvocation invocació) - Aquest mètode permet interceptar el processament i fer un procés abans i / o després de la ActionInvocation.

Struts2 ve amb llista per defecte de interceptors ja configurats: Llistat d'interceptors

Interceptor's Official Reference.

Com declarar interceptors en struts.xml

Es poden crear tantes classes interceptors com es vulguin, una vegada creades s'han de definir en el package dintre del fitxer struts.xml i després s'han de referenciar quan vulguis utilitzar-les. Per referenciar-les, en el action on ho necessites has de afegir la referencia dels interceptors que necessitis. Aquest han d'estar declarats amb anterioritat. L'ordre de declaració és molt important ja que s'executaran seqüencialment segon l'ordre establert en aquest fitxer.

Exemple:

<?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.custom.i18n.resources" value="LoginAction" />


    <package name="default" extends="struts-default" namespace="/">
        <interceptors>
            <interceptor name="interceptor1"
                class="exemple.interceptor1" />
            <interceptor name="interceptor2"
                class="exemple.interceptor2" />

        </interceptors>
                
        <action name="wkflow" class="exemple.WkflowAction">
        	<interceptor-ref name="interceptor1"/>
        	<interceptor-ref name="interceptor2"/>
            	<result>Home.jsp</result>
        </action>
    </package>
</struts>

Exercici Interceptors encadenats

Crea tres interceptors i fes que es cridin un darrera l'altre fins arribar a l'Action que toqui. Una vegada executat l'Action fes que es tornin a cridar de manera seqüencial. Per comprovar que funciona, cada vegada que un interceptor s'executi ha de escriure a la consola el seu nom.

Exercici Validació

Utilitza l'Interceptor Validate, per a fer la validació del Login d'un usuari. Pots aprofitar el que necessitis del exercici Login.

Pràctica Pt2.2 - Conjunt d'exercicis d'Struts2 (35% de la nota)

Exercicis anteriors 1p

Recull de tots els exercicis de struts2 fets i resolts a classe. (login, helloworld,...)

Auto-emplenar 1p

Utilitzant l'etiqueta d'struts2 autocompleter cercar dintre de un llistat el resultat més aproximat del que s'escriu dintre del textbox. Exemple:

Autocompletar-struts2.png

Dades:

state = new ArrayList();
state.add("Alabama");
state.add("Alaska");
state.add("Arizona");
state.add("Arkansas");
state.add("California");
state.add("Colorado");
state.add("Connecticut");
state.add("Delaware");
state.add("District of Columbia");
state.add("Florida");
state.add("Georgia");
state.add("Hawaii");
state.add("Idaho");
state.add("Illinois");
state.add("Indiana");
state.add("Iowa");
state.add("Kansas");
state.add("Kentucky");
state.add("Louisiana");
state.add("Maine");
state.add("Maryland");
state.add("Massachusetts");
state.add("Michigan");
state.add("Minnesota");
state.add("Mississippi");
state.add("Missouri");
state.add("Montana");
state.add("Nebraska");
state.add("Nevada");
state.add("New Hampshire");
state.add("New Jersey");
state.add("New Mexico");
state.add("New York");
state.add("North Carolina");
state.add("North Dakota");
state.add("Ohio");
state.add("Oklahoma");
state.add("Oregon");
state.add("Pennsylvania");
state.add("Rhode Island");
state.add("South Carolina");
state.add("South Dakota");
state.add("Tennessee");
state.add("Texas");
state.add("Utah");
state.add("Vermont");
state.add("Virginia");
state.add("Washington");
state.add("West Virginia");
state.add("Wisconsin");
state.add("Wyoming");

Selects encadenats 1p

Utilitza l'etiqueta doubleselect per mostrar dos combo box encadenats entre si.

Bean 1p

Crea el Bean Usuari. Aquest Bean te les següents propietats:

  • nom
  • cognom
  • username
  • password

Mostra per pantalla una instància d'aquest Bean. Utilitza l'etiqueta d'struts2 bean per mostrar les dades.ç

Sessions 2p

Ampliarem l'exercici de login afegint la funcionalitat de sortir de la intranet. Es a dir, una vegada l'usuari ha posat correctament les credencials accedeix a una pàgina que recorda a l'usuari.

Aquest usuari "admin" amb contrasenya "admin" s'anomena realment "Super Usuari". Aquest és el nom que ha d'aparèixer. A més a més, Aquesta pàgina disposa d'un enllaç anomenat sortir que surt de sessió i torna al formulari inicial.

Crida a un action 1p

Utilitza l'etiqueta d'structs 2 action. Crea els actions necessaris i les jsp necessàries per utilitzar aquesta etiqueta. Explica com ho has realitzat.

Càrrega d'un fitxer 3p

Utilitza l'interceptor fileUpload i el tag file per pujar un fitxer al servidor.

Bibliografia/webgrafia