Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

PrimeFaces: un esempio introduttivo

Realizzazione di un semplice progetto di esempio introduttivo per PrimeFaces (una rubrica dei contatti)
Realizzazione di un semplice progetto di esempio introduttivo per PrimeFaces (una rubrica dei contatti)
Link copiato negli appunti

PrimeFaces è una suite open source utilizzabile con il framework JavaServer Faces 2.0, esplicitamente pensata per realizzare i componenti presentazionali di una applicazione web enterprise: editor HTML, finestre di dialogo, meccanismi per l'auto-completamento, grafici e calendari, drag & drop, integrazione di mappe google e molto altro.

La suite offre supporto sia ad ajax che al rendering parziale delle pagine web, grazie ad una integrazione nativa con jquery. L'aspetto grafico dei componenti si basa su JQuery UI: è quindi possibile personalizzarlo attraverso lo skin framework Theme Roller, o utilizzare un discreto insieme di temi predefiniti. Da segnalare infine la presenza di uno User Interface Kit per la realizzazione di applicazioni Web orientate ai dispositivi mobili (iPhone, Android, etc.), di semplice e veloce configurazione.

Una rubrica dei contatti con PrimeFaces

Vogliamo implementare una piccola applicazione Web per la gestione di una classica agenda di contatti. Prima di entrare nei dettagli realizzativi, definiamo tutto ciò che occorre per l'ambiente di sviluppo:

Librerie/framework utilizzati per l'esempio
PrimeFaces 2.2.1 JSF Mojarra 2.0.4
JBoss Developer Studio 4.0.0.cr1 GlassFish Application Server
iText Apache POI
PostgreSQL JDBC per PostgreSQL

Una Rubrica dei contatti con PrimeFaces: configurazione di Postgres

Per realizzare lo strato di persistenza dell'applicazione con tecnologia JPA, installiamo PostgreSQL (nell'esempio abbiamo usato la versione 8.4.7.1). È sufficiente prestare attenzione a due schermate in particolare: quella in cui definiamo l'account e quella in cui ultimare l'installazione. Su quest'ultima possiamo tranquillamente togliere il segno di spunta all'opzione "Launch Stack Builder at exit" e fare click su "finish":

Figura 1. Installazione di PostgreSQL
(clic per ingrandire)


Installazione di PostgreSQL

Dopo aver installato Postgres, assicuriamoci che il servizio sia in esecuzione e colleghiamoci ad esso attraverso l'utility pgAdmin. Creiamo un database con il nome PrimeFacesDb: in esso creiamo anche la tabella "contatti" che l'applicazione utilizzerà per la gestione dei dati. Possiamo usare l'interfaccia grafica, oppure attraverso uno script SQL nell'editor di pgAdmin:

CREATE TABLE contatti
(
  nome character varying,
  cognome character varying,
  telefono character varying,
  professione character varying,
  id serial NOT NULL,
  CONSTRAINT contatti_pkey PRIMARY KEY (id)
)
WITH (OIDS=FALSE);

ALTER TABLE contatti OWNER TO postgres;

Una Rubrica dei contatti con PrimeFaces: configurazione Glassfish

Una volta creato il database concentriamoci sull'application server GlassFish: estraiamo il file precedentemente scaricato in una directory a nostro piacimento. Dobbiamo copiare i file di mojarra (jsf-api.jar e jsf-impl.jar) nella directory glassfishmodules, sovrascrivendo le versioni esistenti. Il driver JDBC (postgresql-8.4-702.jdbc4.jar) va copiato invece in glassfishlib. Proseguiamo con l'istallazione di Jboss Developer Studio e finalmente ci dedichiamo al progetto.

Il passo successivo sarà definire, nell'ambiente di sviluppo, il server su cui eseguire la Web Application, e configurare la connessione verso il DBMS Postgres che abbiamo creato.

In Jboss Developer Studio apriamo la view Servers (Window > Show View). In questo pannello creiamo un nuovo server, scegliendo GlassFish 3.1 (se non c'è, possiamo aggiornare la lista cliccando su download additional server adapters).

Figura 2. Installazione Glassfish
Installazione Glassfish

Clicchiamo su add per aggiungere il runtime di GlassFish che abbiamo scaricato, facendo puntare il campo Application Server Directory alla directory di installazione di GlassFish. Un click su finish e proseguiamo.

Figura 3. Impostare il path per Glassfish
Impostare il path per Glassfish

Una volta creato il server, lo facciamo partire (start) per verificare che tutto sia andato a buon fine. In tal caso possiamo proseguire con la configurazione di un datasource che permetterà alla nostra applicazione di collegarsi al db postgres precedentemente creato.

Glassfish e PostgreSQL: connessione e creazione di un datasource

La creazione di un datasource è un'operazione semplice dalla console di amministrazione di Glassfish: la attiviamo cliccando con il tasto destro sul server che abbiamo creato nella view Servers e selezionando ViewAdminCondole.

Figura 4. Creare il datasource in Glassfish
(clic per ingrandire)


Creare il datasource in Glassfish

Attendiamo che la console di amministrazione abbia ultimato il suo caricamento, e al termine dovremmo visualizzare una schermata con un menu principale sulla sinistra (Common Tasks). Selezioniamo la voce Resources > JDBC > JDBC Connection Pools:

Figura 5. Selezionare JDBC Connection Pools
(clic per ingrandire)


Selezionare JDBC Connection Pools

in risposta sulla destra della schermata verrà visualizzata l'interfaccia per la definizione di un connection pool verso un database, facciamo click su New:

Figura 6. Creare un JDBC Connection Pool
(clic per ingrandire)


Creare un JDBC Connection Pool

impostiamo come Resource Type javax.sql.ConnectionPoolDataSource e Datasource Classname org.postgres.ds.PGConnectionPoolDataSource.

Figura 7. Associare la risorsa al datasource
(clic per ingrandire)


Associare la risorsa al datasource

Nella tab Additional Properties modifichiamo i parametri di connessione verso il nostro db come mostrato nella seguente tabella:

Parametri di connessione a JDBC
Proprietà Valore
portNumber 5432
databaseName PrimeFacesDb
datasourceName PrimeFacesDemoDS
serverName 127.0.0.1
user postgres
password postgres

Salviamo tutto e, tornando nella tab General effettuiamo il ping verso il database, per verificare che la connessione funzioni. Per utilizzare questo datasource dall'applicazione Web, dobbiamo però definire un collegamento JNDI. Torniamo al menu principale e selezioniamo JDBC Resources:

Figura 8. Selezionare JDBC Resources
(clic per ingrandire)


SelezionareJDBC Resources

verrà visualizzata una pagina simile alla seguente:

Figura 9. JDBC Resources
(clic per ingrandire)


JDBC Resources

Cliccando su New definiamo la risorsa JNDI per il nostro datasource: scegliamo il nome JNDI jdbc/PrimeFacesDemo che ci servirà poi per recuperare un oggetto datasource dalla nostra applicazione attraverso un'operazione di lookup.

Figura 10. Definire una nuova risorsa JNDI
(clic per ingrandire)


Definire una nuova risorsa JNDI

Una rubrica dei contatti con PrimeFaces: il progetto J2EE in Glassfish

In Jboss Developer Studio creiamo un progetto J2EE Enterprise (enterprise application project) con nome PrimeFacesDemoEAR al quale legheremo i successivi due progetti JSF e JPA. Creato il progetto enterprise, proseguiamo con un nuovo progetto JSF 2:

Figura 11. Creazione del progetto JSF
Creazione del progetto JSF

Nel wizard di creazione del progetto, facciamo attenzione a collegare il nostro EAR. Diamo un nome al progetto, ad esempio PrimeFacesDemo, scegliamo la versione 2.0 del framework in JSF Environment e scegliamo la location del progetto oppure lasciamo il percorso di default con un check su Use default path. Scegliamo poi la versione servlet da utilizzare, 2.5 o 3 , impostiamo il runtime per GlassFish 3.1 (Se l'adapter per il server non dovesse comparire nella lista, scarichiamolo attraverso il link Download additional adapters) e facciamo in modo che punti alla directory di installazione:

Figura 12. Configurazione del server per il progetto JSF
(clic per ingrandire)


Configurazione del server per il progetto

Al termine della creazione del progetto inseriamo in WEB-INF/lib il file della libreria PrimeFaces (primefaces-2.2.1.jar) il file .jar di iText e della libreria POI precedentemente scaricati.

Affinchè PrimeFaces funzioni correttamente è necessario definire nel web.xml la sua resource servlet nel seguente modo:

<servlet>
<servlet-name>Resource Servlet</servlet-name>
<servlet-class>org.primefaces.resource.ResourceServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Resource Servlet</servlet-name>
<url-pattern>/primefaces_resource/*</url-pattern>
</servlet-mapping>

e siccome stiamo utilizzando una versione di mojarra 2.0 anche il seguente parametro

<context-param>
<param-name>com.sun.faces.allowTextChildren</param-name>
<param-value>true</param-value>
</context-param>

queste operazioni completano l'aspetto di configurazione della libreria. Sebbene sia possibile utilizzare pagine jsp, dalla versione 2.0 di JSF l'uso di esse è divenuto deprecato: faremo quindi uso delle facelets per comporre le pagine xhtml. Configuriamo quindi il mapping sulla Faces Servlet all'interno del file web.xml, ad esempio nel modo seguente:

<context-param>
	<description>
		The default suffix for extension-mapped resources that contain JSF components. Default is '.jsp'.
	</description>
	<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
	<param-value>.xhtml</param-value>
</context-param>
<servlet>
	<servlet-name>Faces Servlet</servlet-name>
	<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
	<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
	<servlet-name>Faces Servlet</servlet-name>
	<url-pattern>*.xhtm</url-pattern>
</servlet-mapping>

Le nostre pagine saranno salvate con estensione .xhtml e raggiungibili con .xhtm.Lo scheletro delle pagine che realizzeremo è il seguente:

<!DOCTYPE
	html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
	xmlns="http://www.w3c.org/1999/xhtml"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:p="http://primefaces.prime.com.tr/ui">
<h:head>...</h:head>
<h:body>
...
</h:body>
</html>

Si tratta di una pagina xhtml in cui vengono importati i tag del framework JSF e della libreria PrimeFaces.

PrimeFaces fornisce dalle funzionalità particolarmente per la costruzione di tabelle, tra cui

  • Paginazione
  • Selezione singola di un record
  • Selezione multipla di record
  • Lazy Loading, ovvero la possibilità di caricare soltanto un sottoinsieme alla volta del numero di record totale
  • Selezione della singola cella
  • Ordinamento sulle colonne

Realizziamo quindi un esempio sfruttando questo componente. Immaginiamo di avere una tabella di contatti con i campi Nome, Cognome, Telefono, Mail e Professione e vogliamo creare un piccolo gestionale che permetta di visualizzare la lista di contatti, aggiungerne di nuovi, modificarli e cancellarli. Come ulteriore aspetto vedremo l'esportazione di base dei record della tabelle nei formati excel, pdf, csv ed xml.

Il componente dataTable ha molti attributi, in questo esempio utilizzeremo quelli relativi alla paginazione e alla selezione singola con un istant ajax rerender del componente che mostra il record selezionato.

Una rubrica dei contatti con PrimeFaces: il progetto JPA

Dopo aver definito il progetto JSF PrimeFacesDemo, creiamo un progetto JPA con nome PrimeFacesDemoJPA. Dobbiamo fare attenzione ad utilizzare la versione JPA dell'application server, perciò esaminiamo questi passaggi del wizard di creazione del progetto:

Figura 13. Configurare il progetto JPA
(clic per ingrandire)


Configurare il progetto JPA

Selezioniamo il nostro target runtime. In EAR membership aggiungiamo il progetto all'enterprise application project già creato nella schermata finale scegliere Hibernate (JPA 2.x).

Figura 14. JPA Facet
(clic per ingrandire)


JPA Facet

Terminata la creazione del progetto, editiamo il file persistence.xml:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
	xmlns="http://java.sun.com/xml/ns/persistence"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
	<persistence-unit name="PrimeFacesDemoJPA">
		<jta-data-source>jdbc/PrimeFacesDemo</jta-data-source>
	</persistence-unit>
</persistence>

in questo modo definiamo una persistence unit collegata al database configurato in Glassfish precedentemente. Abbiamo una sola tabella e quindi dobbiamo creare l'entity JPA che la rappresenta. Scegliamo di creare nel progetto JPA il package primefaces.demo.jpa e in esso la seguente entità:

@Entity
@Table(name="contatti")
@SequenceGenerator(name="CONTACT_SEQUENCE_GENERATOR", sequenceName="contatti_id_seq",allocationSize=1,initialValue=1)
public class Contact implements Serializable {
	private static final long serialVersionUID = 1L;
	@Id
	@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="CONTACT_SEQUENCE_GENERATOR")
	private Integer id;
	private String cognome;
	private String nome;
	private String professione;
	private String telefono;
    public Contact() {...}
    // metodi get e set...
}

contatti_id_seq è la sequence creata durante lo statement di creazione della tabella contatti. Con la definizione di questa classe, il lavoro per quanto riguarda il progetto JPA è finalmente terminato, e possiamo concentrarci sul progetto JSF PrimeFacesDemo.

Una Rubrica dei contatti con PrimeFaces: le pagine di visualizzazione

Iniziamo qui con la realizzazione della pagina dataTable.xhtml. In questa pagina trovano spazio diversi componenti primefaces:

  • dataTable per la visualizzazione della lista dei record
  • panel per la decorazione con pannello dotato di header
  • dialog per la visualizzazione delle interfacce di inserimento/modifica record
  • grow per la visualizzazione di messaggi di notifica

Come detto precedentemente si tratta di una pagina conforme allo standard xhtml e deve quindi necessariamente avere la seguente forma generale:

<html xmlns="http://www.w3c.org/1999/xhtml"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:p="http://primefaces.prime.com.tr/ui"
	xmlns:ui="http://java.sun.com/jsf/facelets">
<f:view contentType="text/html">
<h:head>...</h:head>
<h:body>
...
<h:body>
</html>

datatable: la lista dei record

In allegato all'articolo sono disponibili i sorgenti degli applicativi nei quali trovare l'intera pagina, qui concentriamoci sulle parti più importanti iniziando dalla datatable (clicca per visualizzare il codice). Si tratta del componente che utilizziamo per visualizzare la lista dei record, analizziamo uno ad uno gli attributi della dataTable utilizzati:

attributo descrizione
var rappresenta la variabile di iterazione; ad ogni step del ciclo contiene l'oggetto relativo al contatto corrente della lista contacts definita nel bean ContactsBean
value il collegamento con la lista contacts del bean ContactsBean i cui oggetti desideriamo visualizzare nella dataTable
selection contiene gli oggetti Contact selezionati dalla lista attraverso il dataTable
selectionMode permette di impostare la selezione singola o multipla
paginator attiva o disattiva la paginazione per la tabella
rows numero di record per pagina
update aggiorna lo stato di un componente il cui id è specificato come valore al termine di una richiesta ajax
onselectComplete al termine della richiesta ajax indica quale operazione compiere

selezionare un record

contactsBean è il nome del managed bean JSF che dichiareremo poi nel faces-config.xml. Il managed bean avrà tra i suoi campi una lista di oggetti di tipo Contact recuperata dal database, ed un campo contact di classe Contact che ospita di volta in volta il record selezionato. La lista viene collegata alla datatable attraverso l'attributo value, il record è selezionato attraverso un click, e viene memorizzato nella variabile contact del managed bean mediante l'attributo selection.

Con gli attributi

update="updForm:updDisplay" onselectComplete="updDialog.show()"

chiediamo l'aggiornamento del pannello con id "updDisplay" all'interno del form con id "updForm", e di visualizzare successivamente la dialog in esso contenuta, la cui widget var è "updDialog". In sostanza il record viene selezionato, memorizzato nel campo del bean ed i suoi dati mostrati grazie all'aggiornamento ajax dell'area di pagina che contiene la dialog di aggiornamento. (clicca per visualizzare il sorgente)

Vediamo sul browser l'effetto di questa azione:

Figura 15. Demo
(clic per ingrandire)


Demo

aggiornamenti e cancellazione dei record

Per aggiornare e cancellare il record possiamo definire i pulsanti:

<p:commandButton value="Aggiorna"
	ajax="true"
	actionListener="#{contactsBean.aggiorna}"
	update="tbl,growl"
	onclick="updDialog.close()">
</p:commandButton>
<p:commandButton value="Elimina"
	ajax="true"
	actionListener="#{contactsBean.elimina}"
	update="tbl,growl"
	onclick="updDialog.close()">
</p:commandButton>

Queste operazioni avvengono attraverso i metodi aggiorna ed elimina definiti nel managed bean. Al termine della loro invocazione, la datatable (id=tbl) viene aggiornata, ed un messaggio viene visualizzato. Da ultimo la dialog viene chiusa(updDialog.close()). Notiamo un footer nella datatale che contiene alcuni tag particolarmente interessanti come il seguente:

<h:commandLink>
	<p:graphicImage value="/images/pdf.png" style="border:none" />
	<p:dataExporter type="pdf" target="tbl" fileName="contacts"	pageOnly="true" />
</h:commandLink>

Questi tag consentono l'esportazione dei record in diversi formati: dataExporter infatti è un componente che legandosi ad una datatable ne permette l'esportazione in formato pdf,excel,csv,xml (dell'intera lista o solo della pagina corrente). L'attributo target lo lega alla tabella, fileName definisce il nome del file di esportazione e type il formato del file. La dialog che permette l'inserimento viene visualizzata attraverso il pulsante Nuovo Contatto, ed il funzionamento è praticamente identico alla form di aggiornamento.

<h:form>
	<p:dialog widgetVar="newDialog" header="Inserisci Contatto"	  modal="true">
		<p:outputPanel id="newDisplay">
			<h:panelGrid columns="2">
				<h:outputLabel value="Nome" />
				<p:inputText value="#{contactsBean.contact.nome}"></p:inputText>
				<h:outputLabel value="Cognome" />
				<p:inputText value="#{contactsBean.contact.cognome}"></p:inputText>
				<h:outputLabel value="Telefono" />
				<p:inputText value="#{contactsBean.contact.telefono}"></p:inputText>
				<h:outputLabel value="Professione" />
				<p:inputText value="#{contactsBean.contact.professione}"></p:inputText>
			</h:panelGrid>
			<p:commandButton value="Salva"
				actionListener="#{contactsBean.salva}"
				update="contact"
				onclick="newDialog.close()">
			</p:commandButton>
		</p:outputPanel>
	</p:dialog>
</h:form>

La logica di gestione della tabella

Vediamo adesso il managed bean che incapsula la logica di gestione della nostra tabella di contatti configurato nel faces-config come:

<managed-bean>
	<managed-bean-name>contactsBean</managed-bean-name>
	<managed-bean-class>prime.sample.ContactsBean</managed-bean-class>
	<managed-bean-scope>request</managed-bean-scope>
</managed-bean>

Anche qui definiamo un package,prime.sample, che ospita l'unica classe JSF:

public class ContactsBean {
	private List<Contact> contacts;
	private Contact contact=new Contact();
	@PersistenceUnit(unitName="PrimeFacesDemoJPA")
	private EntityManagerFactory emf;
	@Resource
	private UserTransaction utx;
	public List<Contact> getContacts() {...}
	public void salva(ActionEvent event){...}
	public void aggiorna(ActionEvent event){...}
	public void elimina(ActionEvent event){...}
	// getters / setters ...
	// visualizzazione messaggi ...
}

(clicca per visualizzare il sorgente completo)

Concentriamo la nostra attenzione sui campi:

private List<Contact> contacts;
private Contact contact=new Contact();
@PersistenceUnit(unitName="PrimeFacesDemoJPA")
private EntityManagerFactory emf;
@Resource
private UserTransaction utx;

con essi definiamo la lista collegata alla datatable,contacts, l'oggetto selezionato dalla stessa,contact, che è anche l'oggetto collegato alle dialog di inserimento e aggiornamento, ed infine gli oggetti per ottenere un entityManger per interagire con lo strato JPA e il relativo oggetto per la gestione transazionale. Vediamo ad esempio il metodo aggiorna:

public void aggiorna(ActionEvent event){
	EntityManager em = emf.createEntityManager();
	try {
		utx.begin();
		em.joinTransaction();
		em.merge(contact);
		utx.commit();
		showGrowlUpdMessage();
	} catch (Exception e) {
		try {
			utx.rollback();
		} catch (IllegalStateException e1) {
			showGrowlErrorMessage();
			e1.printStackTrace();
		} catch (SecurityException e1) {
			showGrowlErrorMessage();
			e1.printStackTrace();
		} catch (SystemException e1) {
			showGrowlErrorMessage();
			e1.printStackTrace();
		}
	}finally{
		em.close();
	}
	contact=null;
	}
}

quando questo metodo viene invocato, l'oggetto contact contiene il record selezionato dalla dataTable, viene quindi creata una transazione ed in essa l'operazione merge di aggiornamento con relativo commit. Se tutto si conclude con successo, viene eseguito il metodo

private void showGrowlUpdMessage(){
	FacesContext context = FacesContext.getCurrentInstance();
	context.addMessage(null, new FacesMessage("Successful", "Contatto aggiornato con successo"));
}

che attiva il componente grow per la visualizzazione di un messaggio:

Figura 16. Aggiornamento contatto
(clic per ingrandire)


Aggiornamento contatto

Nella pagina dataTable.xhtml accanto al button Nuovo Contatto, possiamo notare il tag

<p:themeSwitcher initialText="Cambia tema"></p:themeSwitcher>

Questo componente, se siamo collegati a internet, reperisce dal sito ThemeRoller, alcuni temi predefiniti e ci permette di applicarli in tempo reale alla nostra pagina,alcuni esempi:

Figura 17. Tre temi di esempio
(clic per ingrandire)


Tre esempi di temi

Considerazioni finali

Con questo esempio abbiamo visto come sia possibile realizzare soluzioni web 2 J2EE ajax di una certa complessità, in pochi passi, e scrivendo pochissimo codice grazie a JSF 2 e PrimeFaces. Le potenzialità di questi strumenti sono notevoli e l'esempio illustrato ne fornisce un piccolo assaggio.

Per chi fosse interessato ad approfondimenti sui vari temi affrontati durante la costruzione di questo progetto, suggeriamo una piccola ma interessante collezione di link:

Ti consigliamo anche