Le impostazioni per gestire la navigazione tra le pagine JSF si basano su principi piuttosto semplici. Tutto viene scritto nel faces-config.xml
e le asserzioni sono decisamente facili da comprendere.
A sfavore di questa tecnica va sottolineato come per siti di certe dimensioni e con esigenze più complesse la stesura e lettura delle direttive potrebbe risultare caotica.
Un primo esempio: Navigazione Statica
Creare la pagina “home.jsp”
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="f" uri="http://java.sun.com/jsf/core"%>
<%@ taglib prefix="h" uri="http://java.sun.com/jsf/html"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Navigazione JSF - Homepage</title>
</head>
<body>
HOMEPAGE <br />
<br />
Navigazione:
<f:view>
<h:form>
<h:commandLink action="pagina1" value="Vai alla prima pagina" />
</h:form>
</f:view>
</body>
</html>
Creare la pagina “target.jsp”
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="f" uri="http://java.sun.com/jsf/core"%>
<%@ taglib prefix="h" uri="http://java.sun.com/jsf/html"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Navigazione JSF - Target</title>
</head>
<body>
Pagina target
<f:view>
<h:form>
<h:commandLink action="HOME" value="torna alla home" />
</h:form>
</f:view>
</body>
</html>
Queste sono le due pagine del progetto.
E' evidente che ciò che consente all'utente di passare da una pagina all'altra è il tag <h:commandLink>, ma il motore di tutta l'operazione sono le seguenti righe all'interno del faces-config.xml
:
<navigation-rule>
<from-view-id>/home.jsp</from-view-id>
<navigation-case>
<from-outcome>pagina1</from-outcome>
<to-view-id>/target.jsp</to-view-id>
</navigation-case>
</navigation-rule>
<navigation-rule>
<navigation-case>
<from-outcome>HOME</from-outcome>
<to-view-id>/home.jsp</to-view-id>
</navigation-case>
</navigation-rule>
Per definire la navigazione bisogna impostare delle regole, la prima regola che si può vedere (contenuta nel primo tag <navigation-rule>
) dice questo: se si è nella pagina home.jsp
e viene emesso in output una stringa “pagina1” allora va chiamata la pagina target.jsp
.
Questo tipo di regola è la più comune, viene definito un punto di partenza e si definisce un punto di arrivo basandosi su un output. Nel caso della pagina di esempio mostrata sopra, l'output è dato dall'attributo action del commandLink. All'interno della stessa regola è possibile definire anche più tag <navigation-case>
attivati da diversi output.
La seconda regola permette la navigazione da target.jsp
alla home, ed è diversa dalla prima in quanto non c'è nessun punto di partenza. In questo modo da qualunque pagina venga inviato in output la stringa “HOME” il framework reindirizzerà l'utente alla pagina indicata. Da notare invece che se uscisse un output “pagina1” da una pagina diversa da home.jsp
la regola descritta sopra non verrebbe attivata.
Testando questo primo esempio si otterranno le seguenti pagine:
E' interessante notare come nella barra dell'indirizzo non cambi il riferimento nella pagina target, e se dalla pagina target si torna alla home, nella barra degli indirizzi apparirà l'url della pagina target. Questo è un dettaglio che potrebbe risultare sgradito, dunque per ovviarvi è possibile aggiungere un tag <redirect />
al'interno del faces-config.xml in questo modo:
<navigation-rule>
<from-view-id>/home.jsp</from-view-id>
<navigation-case>
<from-outcome>pagina1</from-outcome>
<to-view-id>/target.jsp</to-view-id>
<redirect />
</navigation-case>
</navigation-rule>
L'effetto collaterale di questa soluzione è che comporta una richiesta in più al server, che, benché abbia un peso minimo, può essere problematica in casi di connessione lenta.
Un secondo esempio: Navigazione dinamica
Negli esempi precedenti si è vista una tecnica di navigazione che si può definire “statica”, in quanto ogni commandLink ha un output definito e dunque non può che puntare ad una sola pagina, e vista l'esigenza di mappare ogni pagina ad uno o più output non sarebbe niente di speciale se fosse limitata solo a questo utilizzo.
Dunque la parte saliente della navigazione JSF sta nella navigazione dinamica.
Il meccanismo non è affatto diverso dagli esempi visti prima, la direzione di navigazione è sempre diretta dai tag definiti nel faces-config.xml
, ma il tag action, nel quale viene definito l'output, può contenere, invece di una stringa, una funzione di un bean il cui risultato (della funzione) stabilisce l'output.
Come esempio per questa tecnica si illustrerà il progetto “Dado”.
Questo semplice programma chiederà all'utente di inserire un numero (tra 1 e 6) e poi di tirare il dado. A seconda del risultato verrà mostrata la pagina di vittoria o di sconfitta.
Per cominciare serve una classe Dado con un unica funzione:
package bean;
import java.util.Random;
public class Dado {
public Dado() { //... }
public int tiraDado() {
final Random r = new Random();
return (r.nextInt(6) + 1);
}
}
Questa classe servirà solo a calcolare casualmente il numero tra 1 e 6.
Anche se non verrà registrato come bean nel faces-config.xml per comodità viene messo comunque nel package bean.
Serve poi una classe Tentativo che invece sarà un vero e proprio bean con i relativi setter e getter dei due attributi di cui è fornita, ovvero numero e tentativo (vedere capitoli precedenti o progetto in allegato), l'uno per memorizzare il tiro del dado, l'altro il tentativo dell'utente.
Infine il controller:
package controller;
import bean.Dado;
import bean.Tentativo;
public class DadoController {
private final Dado d = new Dado();
private Tentativo t;
public String tiraDado() {
String risultato = "";
t.setNumero(d.tiraDado());
if (t.getTentativo() == t.getNumero()) {
risultato = "indovinato";
} else {
risultato = "sbagliato";
}
return risultato;
}
// ...
}
I getter
e setter
sono stati omessi per brevità, il cuore di questa classe è il metodo tiraDado() che calcola il risultato della supposizione dell'utente e torna una stringa: questa sarà la chiave che userà il framework per decidere verso quale pagina navigare.
E' fondamentale ricordarsi sempre di registrare i propri beans nel faces-config.xml
.
In questo caso i bean da registrare sono 2: il bean tentativo e il bean dadoController, quest'ultimo con il bean tentativo registrato come valore dell'attributo t:
<managed-bean>
<managed-bean-name>dadoController</managed-bean-name>
<managed-bean-class>controller.DadoController</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>t</property-name>
<property-class>bean.Tentativo</property-class>
<value>#{tentativo}</value>
</managed-property>
</managed-bean>
Per tenere in memoria il risultato del tiro del dado verrà usata la variabile numero della classe Tentativo, per cui il bean tentativo deve avere session come scope.
Per i dettagli relativi alla creazione dei bean rifarsi agli articoli precedenti.
Le pagine .jsp da creare sono 3:
dado.jsp
PROGETTO DADO <br />
<br />
Indovina che numero uscirà col dado:
<f:view>
<h:form>
<h:inputText value="#{tentativo.tentativo}" required="true" label="Inserisci il numero" /><br />
<h:commandButton action="#{dadoController.tiraDado()}" value="tira il Dado!" />
</h:form>
</f:view>
</body>
Al click sul command button l'attributo action verrà valorizzato dalla funzione tiraDado()
e questo valore governerà la navigazione in base alla regola (scritta più avanti) sul faces-config.xml
.
successo.jsp
Numero indovinato!
<f:view>
<h:outputLabel value="E' uscito il #{tentativo.numero}" /><br />
<h:form>
<h:commandLink action="HOME" value="torna alla home" /> <br />
<h:commandLink action="Dado" value="gioca ancora" />
</h:form>
</f:view>
sbagliato.jsp
Numero sbagliato!
<f:view>
<h:outputLabel value="hai puntato sul numero #{tentativo.tentativo} ma è uscito #{tentativo.numero}" /><br />
<h:form>
<h:commandLink action="HOME" value="torna alla home" /> <br />
<h:commandLink action="Dado" value="ritenta" />
</h:form>
</f:view>
Infine bisogna aggiungere al faces-config.xml
le regole di navigazione per l'output del commandButton della pagina dado.jsp
:
<navigation-rule>
<navigation-case>
<from-outcome>indovinato</from-outcome>
<to-view-id>/successo.jsp</to-view-id>
</navigation-case>
</navigation-rule>
<navigation-rule>
<navigation-case>
<from-outcome>sbagliato</from-outcome>
<to-view-id>/sbagliato.jsp</to-view-id>
</navigation-case>
</navigation-rule>
Le due regole sono assolutamente banali: se esce “successo” reindirizza alla pagina di successo, se esce “sbagliato” alla pagina sbagliato.jsp
.
Conclusioni
In definitiva: la potenza e flessibilità della navigazione JSF è data dall'unione dell'utilizzo dei bean nella definizione degli attributi e dalle proprietà del faces-config.xml
. I primi permettono di avere attributi il cui valore viene definito dinamicamente dal codice scritto in Java, i secondi permettono di stabilire delle regole che valgono su tutto il sito e che sono di facile lettura e interpretazione.
In questo modo è possibile nonché relativamente semplice ed elegante definire una navigazione che possa essere sia prefissata sia stabilità dalle logiche del progetto.