Generalmente una cosa del genere viene modellata usando 4 componenti:
- Una pagina XHTML che rappresenta la View, dove l'utente interagisce (indica i termini di ricerca e clicca sul pulsante per effettuare la ricerca)
- Una pagina XHTML che rappresenta la View di arrivo, dopo aver effettuato la ricerca, con i risultati.
- Un backing bean che mappa tutte le azioni che l'utente può fare nella pagina di view
- Un EJB (Enterprise JavaBean) (stateless session bean) che verrà usato dal backing bean: si occupa di effettuare materialmente le operazioni sul DB e restituire i risultati di queste operazioni al backing bean, il quale le renderà disponibili alla view.
Vediamo una bozza delle tre componenti.
La prima pagina XHTML, con il form per la ricerca:
codice:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:body>
<h:form>
<h:panelGrid columns="2" id="frmRicerca">
<h:outputText value="Testo da ricercare:" />
<h:inputText value="#{myBean.textSearch}" id="srcText" label="Testo da ricercare" />
</h:panelGrid>
<h:commandButton type="submit" value="Cerca" action="#{myBean.executeSearch}" />
</h:form>
</h:body>
</html>
Da notare subito due cose:
1) l'inputText è associato (attributo "value") alla proprietà "textSearch" del backing-bean "myBean"; essendo un bean, nella relativa classe vanno creati i relativi metodi getter/setter per la proprietà. Se la proprietà sarà in "sola lettura" sarà sufficiente il metodo getter. Non è il nostro caso: l'utente deve poter "popolare" il valore del campo di ricerca del bean.
2) la action del pulsante (commandButton) è associata ad un metodo del backing-bean ( metodo executeSearch() ); tale metodo deve ritornare una stringa, che rappresenterà l'outcome, cioè una stringa che sarà valutata da JSF per capire a quale pagina reindirizzare l'utente dopo che il lavoro del metodo è stato eseguito.
Vediamo il backing-bean:
codice:
package it.test;
public class SearchBean implements java.io.Serializable {
...
@EJB
private DatabaseOperations dbOperations; // Sarà il mio EJB con cui effettuerò le operazioni sul DB
...
private String textSearch; // Conterrà il testo da cercare, digitato dall'utente
private List<Record> lstRisultato; // Conterrà il risultato della ricerca, come lista di "Record" (non meglio definiti)
...
// Getter e setter
public String getTextSearch() {
return textSearch;
}
public void setTextSearch(String textSearch) {
this.textSearch = textSearch;
}
public List<Record> getLstRisultato() {
return lstRisultato;
}
// La action per il pulsante
public String executeSearch() {
// Qui effettuo la ricerca sul DB usando il mio EJB
lstRisultato = dbOperations.ricerca( textSearch );
// Qui potrei usare un minimo di logica applicativa per decidere
// dove reindirizzare l'utente in base ai risultati (ad esempio, potrei
// mandarlo alla pagina dei risultati se e solo se la lista non è nulla/vuota
// altrimenti indirizzarlo ad una pagina di errore, o quant'altro... per il
// nostro esempio, reindirizziamo sempre l'utente alla stessa pagina)
return "risultati";
}
}
Da notare che la stringa di output del metodo executeSearch() può essere qualunque cosa: può essere il nome di una pagina XHTML o una stringa che identifica una navigazione (nel qual caso dovrai provvedere a fornire una navigation-rule (trovi svariati esempi on-line). Nel nostro caso JSF semplicemente cercherà la pagina "risultati.xhtml" e reindirizzerà lì l'utente.
L'EJB che effettua le operazioni sul DB non è particolarmente interessante:
codice:
@Stateless
public class DatabaseOperations {
// Qui potrei utilizzare un framework di persistenza per il DB
// oppure ottenere una risorsa JDBC direttamente dall'Application Server/Servlet Container
// oppure ancora stabilire al volo una connessione al DB, usarla e quindi rilasciarla
...
public List<Record> ricerca(String strToSearch) {
List<Record> ret = null;
StringBuilder sql = new StringBuilder();
sql.append("SELECT * ");
sql.append("FROM Tabella ");
sql.append("WHERE mioCampo LIKE ?");
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
pstmt = con.prepareStatement( sql.toString() );
pstmt.setString(1, "%" + strToSearch + "%");
rs = pstmt.executeQuery();
if (rs != null) {
ret = new ArrayList<Record>();
while( rs.next() ) {
Record rec = createRecordFromResultSet( rs );
ret.add( rec );
}
}
} catch (Exception e) {
logger.log("Errore nella ricerca", e);
} finally {
if (rs != null) {
try { rs.close(); } catch (Exception e) { }
}
if (pstmt != null) {
try { pstmt.close(); } catch (Exception e) { }
}
}
return ret;
}
...
}
Infine la pagina dei risultati
codice:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:body>
<h:form>
<h:panelGrid columns="2" id="frmRisultati">
<ui:repeat value="#{myBean.lstRisultato}" var="rec">
<h:oputputText value="#{rec.blabla}" />
</ui:repeat>
</h:panelGrid>
</h:form>
</h:body>
</html>
In questo caso ho usato un ui:repeat per scorrere l'arraylist restituito dal getter "getLstRisultato()" e stampare in output ogni singolo record... ovviamente puoi usare qualsiasi cosa: una tabella, una lista, un framework esterno (come RichFaces o PrimeFaces o altro per la composizione della pagina risultati).
Una cosa che va fatta è informare il framework JSF del fatto che vogliamo avere il backing-bean come managed-bean. Quindi nel faces-config (o in altro file XML opportunamente mappato nel web.xml) andiamo a definire il managed-bean relativo al nostro backing-bean:
codice:
<faces-config version="2.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd">
<managed-bean>
<managed-bean-name>myBean</managed-bean-name>
<managed-bean-class>it.test.SearchBean</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
...
</faces-config>
E questo dovrebbe essere più o meno tutto (ho scritto il tutto al volo, spero sia abbastanza chiaro).
Ciao.