Creating a Database-driven Application

From Documentation

WarningTriangle-32x32.png This page is for ZK 5 and is out of date. If you are interested in translating our tutorial into Italian please contact us.

Translated by Stefano Bianchi

Before You Start

Translations are available in English, Français, Español, Italiano and 日本語.

Other Introductions

Una applicazione reale con accesso a database

Ti mostreremo ora, passo dopo passo, come sviluppare una semplice Web application che utilizza un database. Sebbene questo tutorial sia pensato per i nuovi utilizzatori di ZK, richiede comunque che tu abbia un minimo di esperienza pregressa in Java. Non preoccuparti se non hai conoscenze di altri linguaggi per sviluppo in ambito Web, Java è tutto quello di cui hai bisogno per sviluppare Web application basate su Ajax con ZK.

In questo tutorial assumiamo che tu abbia già installato il JDK (1.4 o superiore) ed un Servlet container (ad es. Tomcat). Per ulteriori informazioni, puoi fare riferimento a Creare una applicazione "Hello World" con Eclipse e ZK Studio.

La tua prima applicazione ZK - Lista "Cose da fare"

Immagina che per pianificare meglio la giornata sorga la necessità di una applicazione che memorizzi la lista della cose da fare. Una Web application di questo tipo avrebbe bisogno di un database. Per gli scopi di questo tutorial useremo un database Java (HSQL DB) che non richiede l'installazione di un database server. Se lo desideri, puoi già vedere e testare un esempio funzionante dell'applicazione.

Scarica il file ZK Todo

  1. Scarica zk-todo-0.9.zip.
  2. Decomprimi zk-todo-0.9.zip, che contiene rispettivamente l'archivio todo.war, la cartella hsqldb ed il file readme.txt.

Lancia l'applicazione di esempio senza un IDE

  1. Copia la cartella hsqldb nella cartella principale (root) dove è installato Apache Tomcat (ad es. C:\)
  2. Copia todo.war nella cartella $TOMCAT_HOME\webapps.
  3. Fai partire Apache Tomcat.
  4. Apri il tuo browser e collegati a http://localhost:8080/todo.

Lancia l'applicazione di esempio con un IDE

  1. Copia la cartella hsqldb nella cartella principale (root) dove è situato il tuo workspace Eclispe (ad es.C:\).
  2. Lancia Eclipse.
  3. Seleziona File > Import.
  4. Nella finestra di Import, seleziona Web > WAR file e quindi clicca su Next.
  5. Usa il bottone Browse fino ad individuare todo.war.
  6. Clicca su Finish per importare il Web Project.
  7. Clicca con il tasto destro del mouse sul progetto todo nella vista Explorer e seleziona Run As > Run on Server.
  8. Seleziona Apache > Tomcat v6.0 Server nella finestra relativa al tipo di server e clicca su Finish.
  9. La finestra del browser verrà attivata automaticamente per visualizzare l'applicazione di esempio.

Todo.png

Casi d'uso

  • Inserisci le informazioni relative ad una cosa da fare e premi sul bottone Add per inserirla nel database.
  • Seleziona una riga qualunque nella tabella per visualizzare e modificare le informazioni nei campi in basso, quindi premi sul tasto Update per aggiornarle.
  • Seleziona una riga qualunque nella tabella e premi il tasto Delete per cancellare l'elemento selezionato.

Model

Nei paragrafi seguenti verranno introdotti schema del database, Domain Object e DAO Object.

Schema del database

Una tabella di database che gestisca i dati della nostra applicazione avrà bisogno dei seguenti campi: event id, event name, event priority e event date.

Lo schema del database è riportato di seguito.

Field Type
id varchar(50)
name varchar(50)
priority int
date date

Domain Object

Per la tabella sopra, creiamo un corrispondente oggetto (Domain Object) come sotto riportato:

public class TodoEvent {
    private String id;
    private String name;
    private int priority;
    private Date date;

    public TodoEvent(String id, String name, int priority, Date date) {
        this.id = id;
        this.name = name;
        this.priority = priority;
        this.date = date;
    }

    // i metodi setter e getter sono omessi, fai riferimento al codice sorgente
}

DAO Object (Data Access Object)

Per accedere facilmente ai dati del nostro database abbiamo bisogno di un oggetto DAO con i seguenti metodi: findAll(), delete(), insert() e update().

public class EventDAO {
    // L'implementazione è omessa, fai riferimento al codice sorgente.
	public List<TodoEvent> findAll() {
	}

	public boolean delete(TodoEvent evt) {
	}

	public boolean insert(TodoEvent evt) {
	}

	public boolean update(TodoEvent evt) {
    }
}

View

Il tuo primo componente ZK

Il primo passo è creare un file la cui estensione sia zul - diciamo todo.zul - e pozionarlo nella cartella principale (home) della tua Web application, per es. $TOMCAT_HOME/webapps/ProjectName/. Puoi dichiarare un componente ZK nello stesso modo in cui dichiari un componente usando HTML.

Dichiara il tuo primo componente window come segue:

<window title="To do list" border="normal">
</window>

Quindi fai partire Tomcat e indirizza il tuo browser alla pagina relativa, ad es. http://localhost:8080/todo/todo.zul. Il risultato è mostrato sotto: una finestra con il titolo ?To do List?.

Ogni cosa in ZK è un componente. Pertanto, puoi modificare titolo, ampiezza e bordo della tua finestra a piacimento. É piuttosto semplice ed intuitivo. Prova a modificare questi attributi e guarda il risultato.

Relazioni gerarchiche tra i componenti ZK

Ora vediamo di arricchire la pagina con altri componenti ZK. Dal momento che abbiamo bisogno di mostrare i dati in forma tabellare, potremmo usare un componente listbox che è progettato per visualizzare dati. Per inserire un listbox lo andiamo a dichiarare all'interno dei tag relativi al componente window, come segue:

 <window title="To do list" border="normal">
  <listbox id="box" multiple="true" rows="5">
  </listbox>
 </window>

In questo esempio il componente listbox è un componente figlio di window. Esatto, tra i componenti ZK sussistono relazioni gerarchiche, ed andrai incontro ad eccezioni relative all'interfaccia grafica (UI exception) se tenterai di dichiarare un componente all'interno di un contesto errato, ad es. dichiarando un componente window come figlio di un componente listbox.

Un componente annidato

Un listbox è un componente annidato che ammette due tipi di componente figlio, listhead (cioè la colonna della tabella) e listitem (cioè la riga della tabella). All'interno della dichiarazione del listbox andiamo a settare il suo attributo id a ?box?, così da potere usare l'attributo per fare riferimento al listbox.

<window id="win" title="To do list" width="640px" border="normal">
	<listbox id="box" multiple="true" rows="5">
		<listhead>
		</listhead>
		<listitem>
		</listitem>
	</listbox>
</window>

Non abbiamo ancora finito. Dichiariamo tre componenti listheader all'interno dei tag listehead dal momento che abbiamo bisogno di tre colonne -- ?Item?, ?Priority?, and ?Date? -- all'interno della tabella, come segue:

<window id="win" title="To do list" width="640px" border="normal">
	<listbox id="box" multiple="true" rows="5">
		<listhead>
			<listheader label="Item" />
			<listheader label="Priority" width="80px" />
			<listheader label="Date" width="170px" />
		</listhead>
		<listitem>
		</listitem>
	</listbox>
</window>

Dal momento che abbiamo tre colonne nella nostra tabella, anche ogni riga ha bisogno di tre campi. Dichiara quindi tre componenti listcell all'interno dei tag del componente listitem.

<window id="win" title="To do list" width="640px" border="normal">
	<listbox id="box" multiple="true" rows="5">
		<listhead>
			<listheader label="Item" />
			<listheader label="Priority" width="80px" />
			<listheader label="Date" width="170px" />
		</listhead>
		<listitem>
			<listcell />
			<listcell />
			<listcell />
		</listitem>
	</listbox>
</window>

La struttura annidata del componente listbox risulta quindi:

listbox
+-- listhead
|    |
|    +-- listheader
|
+-- listitem
      |
     +-- listcell

Componenti per input

Oltre a visualizzare le cose da fare nel listbox, abbiamo bisogno di informazioni (input) relative alla singola cosa da fare, e cioè il nome (valore testuale), la priorità (valore numerico) e la data entro la quale farla (valore data). Per ottenere ciò, dichiariamo un textbox, un intbox e un datebox all'interno dei tag del componente window, come segue:

<window id="win" title="To do list" width="640px" border="normal">
	<listbox id="box" multiple="true" rows="5">
		<listhead>
			<listheader label="Item" />
			<listheader label="Priority" width="80px" />
			<listheader label="Date" width="170px" />
		</listhead>
		<listitem>
			<listcell />
			<listcell />
			<listcell />
		</listitem>
	</listbox>
	Item: <textbox id="name" cols="25" />
	Priority: <intbox id="priority" cols="1" />
	Date: <datebox id="date" cols="8" />
	<button id="add" label="Add" />
	<button id="update" label="Update" />
	<button id="delete" label="Delete" />
</window>

Componenti per layout

Per distinguere questi componenti di input dalla listbox sopra dichiariamo un groupbox per raggrupparli assieme. Così facendo verrà disegnato un bordo attorno a tutti i componenti all'interno del groupbox, in questo caso i componenti input.

<window id="win" title="To do list" width="640px" border="normal">
	<listbox id="box" multiple="true" rows="5">
		<listhead>
			<listheader label="Item" />
			<listheader label="Priority" width="80px" />
			<listheader label="Date" width="170px" />
		</listhead>
		<listitem>
			<listcell />
			<listcell />
			<listcell />
		</listitem>
	</listbox>
	<groupbox>
		<caption label="Event" />
		Item: <textbox id="name" cols="25" />
		Priority: <intbox id="priority" cols="1" />
		Date: <datebox id="date" cols="8" />
		<button id="add" label="Add" />
		<button id="update" label="Update" />
		<button id="delete" label="Delete" />
	</groupbox>
</window>

In aggiunta al componente groupbox, dichiariamo un componente caption per mostrare una etichetta ?Event? in alto nel riquadro. Il componente caption funziona in modo simile all'elemento HTML legend.

Controller

I nostri requisiti includono visualizzazione, aggiunta, modifica e cancellazione delle cose da fare. Nei paragrafi seguenti realizzeremo l'interazione necessaria tra la pagina della nostra Web application e il database.

Definire un Controller

Il primo passo è definire un EventController che estenda org.zkoss.zk.ui.util.GenericForwardComposer.

Implementare org.zkoss.zk.ui.util.GenericForwardComposer

Crea un EventController che estenda org.zkoss.zk.ui.util.GenericForwardComposer permettendoti di accedere alla View e definire i metodi CRUD nel file Java.

// org.zkforge.todo.event.EventController.java

public class EventController extends GenericForwardComposer {
    private static final long serialVersionUID = -9145887024839938515L;
    private EventDAO eventDao = new EventDAO();

    // Nota: Qualcosa è omesso. Puoi vedere tutti i dettagli della classe nel codice sorgente.

    public List<TodoEvent> getAllEvents() {
        return eventDao.findAll();
    }

    public void onClick$add() {
    }

    public void onClick$update() {
    }

    public void onClick$delete() {
    }
}

Associare il Controller alla View

Per realizzare l'interazione tra View e Controller settiamo l'attributo apply del componente window al valore del percorso del nostro EventController.

<window id="win" title="To do list" width="640px" border="normal"
 apply="org.zkforge.todo.event.EventController">

......

Mostrare dati nella View

La visualizzazione dei dati letti dal database richiede solo tre passi:

Attivare il meccanismo di DataBinding

Per utilizzare il meccanismo di Data Binding, dobbiamo attivare il DataBinding Manager tramite la definizione di un Initializer(org.zkoss.zkplus.databind.AnnotateDataBinderInit) in cima alla pagina.

<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit"?>

<window id="win" title="To do list" width="640px" border="normal"
 apply="org.zkforge.todo.event.EventController">
....

Associare i dati alla View

Il passo successivo consiste nel recuperare i dati dal database attraverso l' EventController usando l'espressione (win$composer.allEvents) per invocare EventController.getAllEvents(). Il metodo EventController.getAllEvents() ritorna una lista che contiene tutte le cose da fare memorizzate nel database che possono essere associate all'attributo model del listbox.

<window id="win" title="To do list" width="640px" border="normal"
 apply="org.zkforge.todo.event.EventController">
	<listbox id="box" multiple="true" rows="5" model="@{win$composer.allEvents}">
....

Segui il passo sotto per definire un template UI e renderizzare i Dati nella View.

Definire un Template UI

É possibile definire un template di interfaccia (UI) per il DataBinding per includere e visualizzare i dati nei relativi componenti. Ciò si ottiene usando l'attributo self del listitem per definire una variabile che rappresenti ciascuna istanza di ToDoEvent. Ciascuna listcell è quindi usata per mostrare i dati di ciascun ToDoEvent (cosa da fare).

<window id="win" title="To do list" width="640px" border="normal"
 apply="org.zkforge.todo.event.EventController">
	<listbox id="box" multiple="true" rows="5"
     model="@{win$composer.allEvents, load-after='add.onClick, delete.onClick, update.onClick'}"
     selectedItem="@{win$composer.current}">
		<listhead>
			<listheader label="Item" sort="auto(name)" />
			<listheader label="Priority" width="80px" sort="auto(priority)" />
			<listheader label="Date" width="170px" sort="auto(date)" />
		</listhead>
		<listitem self="@{each='event'}" value="@{event}">
			<listcell label="@{event.name}" />
			<listcell label="@{event.priority}" />
			<listcell label="@{event.date}" />
		</listitem>
	</listbox>

Per maggiori informazioni, fai riferimento a Associare i componenti UI ad una Collection.

Aggiungere la funzionalità di ordinamento

La funzionalità di ordinamento può essere aggiunta assegnando all'attributo sort una espressione che indichi come ordinare la colonna. Per esempio, possiamo specificare auto(name)per il primo listheader dal momento che andrà a mostrare il nome della cosa da fare. Parimenti, auto(priority) è usato per ordinare la lista di cose da fare in base alla priorità.

Sincronizzare la View

Una volta che l'utente ha selezionato un ToDoEvent (cosa da fare) nella listbox, dobbiamo mostrarlo anche nel groupbox. Sarebbe bello se questi lavori tediosi fossero eseguiti automaticamente... Data Binding è la risposta! Vai semplicemente ad associare i dati con i relativi componenti dell'interfaccia (UI). DataBinding sincronizzerà lo stato di tutti i componenti una volta che i dati sono stati modificati.

Definire una istanza "ToDoEvent" all'interno di un Controller

Definisci una istanza ToDoEvent in EventController e definisci metodi setter e getter in modo che possano essere raggiunti dalla View.

// org.zkforge.todo.event.EventController.java

public class EventController extends GenericForwardComposer {
    private TodoEvent current = new TodoEvent();
    // Omitted...
    public TodoEvent getCurrent() {
        return current;
    }

    public void setCurrent(TodoEvent current) {
        this.current = current;
    }

Associare più componenti UI all'Istanza

Per prima cosa associa l'istanza EventController con la proprietà selectedItem del listbox. Poi associa le proprietà di ToDoEvent con i corrispondenti componenti UI, inclusi testbox, intbox e datebox. Nel momento in cui l'utente seleziona un elemento di listbox, l'istanza verrà aggiornata coerentemente assieme a tutti i componenti UI.

	<listbox id="box" multiple="true" rows="5"
      model="@{win$composer.allEvents, load-after='add.onClick, delete.onClick, update.onClick'}"
      selectedItem="@{win$composer.current}">
	<!-- Omitted -->
	<groupbox>
		<caption label="Event" />
		Item: <textbox id="name" cols="25" value="@{win$composer.current.name}" />
		Priority: <intbox id="priority" cols="1" value="@{win$composer.current.priority}" />
		Date: <datebox id="date" cols="8" value="@{win$composer.current.date}" />

Sincronizzare View e Database

Oltre a mostrare dati dal database nella View, vorremmo anche gestire le azioni di aggiunta, modifica e cancellazione di cose da fare. Questa funzionalità richiede tre passi - monitoraggio dell'attività dell'utente, interazione con il Controller per aggiornare il database e aggiornamento della View.

Registrare l'EventListener nel Controller

Per monitorare le attività utente, associa semplicemente un onClick EventListener a ciascuno dei tre bottoni add, update e delete. Quando si cliccano questi bottoni verranno chiamati i corrisponenti metodi definiti nell' EventController, definiti sotto:

public class EventController extends GenericForwardComposer {
    private EventDAO eventDao = new EventDAO();
    // Omesso...
    public void onClick$add() {
        if (current != null) {
            current.setId(UUID.randomUUID().toString());

            if (validate(current)) {
                // insert into database
                eventDao.insert(current);
            }
        }
    }

    public void onClick$update() {
        if (current != null && validate(current)) {
            // update database
            eventDao.update(current);
        }
    }

    public void onClick$delete() {
        if (current != null && validate(current)) {
            eventDao.delete(current);
        }
    }
}

Valorizza gli id degli attributi del bottone in modo che ciascuno corrisponda al relativo metodo di controllo:

		<button id="add" label="Add" />
		<button id="update" label="Update" />
		<button id="delete" label="Delete" />

Fai riferimento ai javadoc per maggiori chiarimenti.

Aggiornare la View tramite DataBinding

Dopo l'interazione con il database, l'ultimo passo è aggiornare la View. Basta semplicemente notificare il DataBinding per fare in modo che il modello venga aggiornato quando l'utente clicca su uno qualunque dei tre bottoni. Associa l'attributo load-after all'attributi model del listbox, e il DataBinding aggiornerà la View automaticamente se l'evento specificato si verifica.

<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit"?>

<window id="win" title="To do list" width="640px" border="normal"
 apply="org.zkforge.todo.event.EventController">
	<listbox id="box" multiple="true" rows="5"
     model="@{win$composer.allEvents, load-after='add.onClick, delete.onClick, update.onClick'}"
     selectedItem="@{win$composer.current}">
	<!-- Omitted... -->
		<button id="add" label="Add" />
		<button id="update" label="Update" />
		<button id="delete" label="Delete" />
	</groupbox>
</window>

Last Update : 2012/02/10