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 Spanish please contact us.

Translated by Sergio Cerro Pascual

Before You Start

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

Other Introductions

Un ejemplo real usando una base de datos

Te mostraremos, paso a poaso, como construir una sencilla aplicación web que use una base de datos. Este tutorial va dirigido a nuevos usuarios de ZK, pero se requiere que el usuario tenga, al menos, una pequeña experiencia con Java. No te preocupes si no conoces otros lenguajes, Java es todo lo que necesitas en cuanto al desarrollo de Ajax en aplicaciones web con ZK.

En este tutorial, asumimos que ya tienes instalado  JDK (1.4 o superior), y un contenedor de servlets (ex.Tomcat). Si no has configurado tu entorno aún, pero estás interesado en continuar con este tutorial, te recomendamos leer Create and Run Your First ZK Application with Eclipse and ZK Studio!

Tu primera aplicación ZK. Una lista "To-do"

Imaginemos que para que nuestro día esté mejor planificado, necesitamos una aplicación web que almacene sucesos que vamos a hacer en el futuro. Una aplicación web así, requeriría usar una base de datos. Para la conclusión de este turorial usaremos una base de datos Java (HSQL DB) la cual no requiere que instalemos un servidor de base de datos. Puedes ver una demo de la aplicación en aquí.

Descargar el fichero Todo de ZK

  1. Descargar zk-todo-0.9.zip.
  2. Descomprimir zk-todo-0.9.zip, el zip contiene los siguientes ficheros y carpetas todo.war, hsqldb,readme.txt.

Ejecutando la aplicación de ejemplo sin un IDE

  1. Copia la carpeta hsqldb' al directorio raiz donde instalaste el Apache Tomcat. (ex.C:\)
  2. Copia todo.war en el directorio $TOMCAT_HOME\webapps.
  3. Inicia Apache Tomcat.
  4. Abre tu navegador y navega hasta http://localhost:8080/todo.

Ejecutando la aplicación de ejemplo con un IDE

  1. Copia la carpeta hsqldb en el directorio raiz donde se encuentra el workspace de tu eclipse. (ex.C:\).
  2. Arranca Eclipse.
  3. Selecciona Archivo > Importar .
  4. En la ventana de diálogo de la opción "Importar", selecciona Web > WAR file y después haz click siguiente.
  5. Localiza el fichero todo.war y seleccionalo (como fichero WAR para ser importado).
  6. Haz Click en Terminar para importar el proyecto web.
  7. Hz click con el botón derecho en todo en el proyecto y selecciona Ejecutar como > ejecutar en servidor
  8. Selecciona Apache > Tomcat v6.0 Server en la ventana de diálogo y haz click en Terminar
  9. Un navegador emergerá automáticamente para ejecutar el ejemplo del proyecto web "todo".

Todo.png

Todos los Escenarios

  • Introduce toda la información relativa a un evento y presiona el botón  Add  para insertarlo en la base de datos.
  • Selecciona cualquier fila en la tabla para mostrar la información del evento en los campos de abajo para que modificar su información, después presiona el botón  Update  para modificar la información.
  • Selecciona cualquier fila en la tabla y presiona el botón  Delete  para eliminar el "Event" seleccionado.

Modelo

En los siguientes párrafos, el esque de la base de datos, el objeto del dominio y el objeto DAO será introducido.

Esquema de la base de datos

Una tabla de la base de datos la cual va a almacenar los datos de nuestra aplicación, necesitará los siguientes atributos: event id, event name, event priority and event date.

El esquema de base de datos está listado abajo.

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

Objeto Dominio

Para la la tabla de arriba, creamos el objeto de dominio correspondiente, como se indica:

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;
    }

    // getter and setter methods are ommited, please refer to the source code.
}

Objeto de Acceso a Datos

Para que fácilmente se acceda a nuestra base de datos necesitaremos un objeto DAO con los siguientes métodos: findAll(),delete(),insert() and update().

public class EventDAO {
    // The implementation is ommited, please refer to the source code.
	public List<TodoEvent> findAll() {
	}
	
	public boolean delete(TodoEvent evt) {
	}
	
	public boolean insert(TodoEvent evt) {
	}
	
	public boolean update(TodoEvent evt) {
    }
}

La Vista

Tu primera componente ZK

El primer paso es crear un fichero el cuya extensión debe ser zul, pongamos todo.zul, y situamos este fichero bajo el directorio de nuestra aplicación web, por ejemplo, $TOMCAT_HOME/webapps/ProjectName/. Declaras un componente ZK de igual forma a como declaras un componente usando HTML.


Prueba a declarar tu primer componente  window  de la siguiente forma:


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


Después inicia Tomcat y usa el navegador para visitar la página, eg. http://localhost:8080/todo/todo.zul. El resultado se muestra abajo,  window  con el título 「To do List」.

Todo en ZK es un componente. Puedes cambiar el título, el alto y el borde de tu  window  Es muy sencillo e intuitivo. Intenta cambiar estos atributos y comprueba el resultado.

Relacciones jerárquicas entre los componentes de ZK

Lo siguiente, vamos a intentar enriquecer esta página con más componentes ZK. Para mostrar datos en una tabla, podemos usar un componente  listbox  el cual está diseñado para mostrar datos. Para insertar un listbox lo declaramos dentro de los tags del componente  window , como se indica:

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

En este ejemplo, el componente  listbox  es un componente hijo de  window. Sí, hay relacciones jerárquicas entre los componentes de ZK, te encontrarás una excepción UI si intentas declarar un componente dentro de un contexto equivocado, por ejemplo, al declarar un componente  window  como hijo de un componente  listbox .

Un componente anidado

Un listbox es un componente anidado, el cual soporta dos tipos de componentes hijos, listhead (aka: columna de la tabla), and listitem (aka: fila de la tabla). Con la declaración del  listbox, asiganamos el atributo id a 「box」, ahora podemos usar este atributo para referenciar el 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>

Aún no hemos terminado. Vamos a declarar tres componentes listheader dentro de los tags de listhead. Necesitamos tres columnas -- 「Item」, 「Priority」, and 「Date」 -- dentro de la tabla, como se indica:

<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>


Tenemos tres columnas en nuestra tabla, cada fila de la tabla también requerirá tres campos. Declaramos tres componentes listcell dentro de los tags 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 estructura anidada del componente  listbox  quedaría así,

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

Componentes para introducir información

En adición a mostrar estes eventos en el  listbox, necesitamos introducir información relativa al evento, incluyendo el evento name (campo texto), el evento priority (campo numérico) y el evento date (campo fecha). Para lograr esto, declaramos un we declare un textbox, un intbox y un datebox dentro de los tags del compoente  window  de la siguiente forma:

<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>

Componentes Layout

Para distinguir los componentes de entrada de datos (input) de los componentes listbox de abajo, declaramos un groupbox para agrupar los componentes. Esto dibujará un borde alrededor de los componentes que estén contenidos dentro del groupbox, en este caso, los componentes de entrada de datos (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>

Adicionalmente a los componentes  groupbox  declaramos un componente  caption  para mostrar una etiqueta 「Event」 a lo largo de la caja que agrupa a los componentes. El componente caption trabaja de forma similar al legendario elemento en HTML.

Controlador

Nuestros requisitos incluyen mostrar, añadir, editar y borrar sucesos/eventos. En los siguientes párrafos, implementaremos las interacciones entre nuestra aplicación web y la base de datos.

Definiendo un Controlador

El primer paso es definir un EventController el cual herede de org.zkoss.zk.ui.util.GenericForwardComposer.

Implementando org.zkoss.zk.ui.util.GenericForwardComposer

Crea un EventController el cual heredará de org.zkoss.zk.ui.util.GenericForwardComposer permitiéndote un fácil acceso a la vista y definir un CRUD mediante los métodos Java definidos.

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

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

    // Note: Something is omitted at here. You can view detail about this class on source code.

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

    public void onClick$add() {
    }

    public void onClick$update() {
    }

    public void onClick$delete() {
    }
}

Asociando el Controlador con la Vista

Para implmentar la interacción entre la Vista y el Controlador asignamos el atributo apply al componente window en la ruta de nuestro EventController.

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

......

Visualizando datos en una Vista

Para visualizar los datos recuperados de la base de datos en nuestra Vista solo requerimos tres pasos:


Activando el mecanismo de DataBinding

Para usar el mecanismoData Binding, deberemos activar el Data Binding Manager (org.zkoss.zkplus.databind.AnnotateDataBinderInit) en la parte superior de la página.

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

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

Asociando los datos con la vista

El paso siguiente es recuperar los datos de la base de datos mediante el EventController usando la expresión (win$composer.allEvents) para invocar EventController.getAllEvents(). El método EventController.getAllEvents() devuelve una lista que contiene todos los eventos almacenados en la base de datos que pueden ser asociados al atributo 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}">
....

Puedes seguir los siguientes pasos para definir una plantilla de Interfaz de Usuario para renderizar los datos dentro de la vista.

Definiendo una plantilla

Es posible definir una plantilla de interfaz de usuario para renderizar DataBinding dentro de los correspondientes componentes de interfaz de usuario. Esto se logra gracias a la utilización de los atributos que ofrece el componente "listitem" definiendo una varible para representar cada instancia a reflejar.

<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>

Para más información, por favor dirígete a Associate UI Components with a Collection.

Sincronización de vistas

Una vez el usuario selecciona un ToDoEvent en el listbox, Necesitamos mostrarlo en el componente groupbox también. Sería mucho mejor si este tedioso trabajo fuera realizado de forma automáticamente. Data Binding es la respuesta! Simplemente asocia los datos con todo lo relacionado con los componentes de UI. El DataBinding se sincronizará entonces con todos los componentes de Interfaz de Usuario una vez la propiedad ha sido modificada.

Definir una instancia "ToDoEvent" a un Controlador

Define una instnacia ToDoEvent' en EventController, y define métodos getter y setter para que puedan ser accesibles desde la vista.

// 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;
    }

Asociando múltiples componentes UI con la instancia EventController

Primero, asocia la instancia EventController con la propiedad selectedItem del listbox. Después, asocia las propiedades del ToDoEvent con el correspondiente componentes UI, incluyendo textbox, intbox, y datebox. Una vez el usuario selecciona un item en un listbox, la instnacia se actualizará en relación a los componentes 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}" />

Sincronizando la vista con la base de datos

Además de mostrar los datos de la base de datos en la vista, nos gustaría implementar eventos para añadir, actualizar y eliminar. Esta funcionalidad requiere de tres pasos, monitorizar la actividad del usuario, interactuando con los controladores para actualizar la base de datos y actualizar la vista.

Registrar el evento Listener en el Controlador

Para monitorizar la actividad del usuario, simplente registrarmos un evento listener onClick' en los siguientes tres botones add, update and delete. Cuando cliqueamos en estos botones que se corresponden a los métodos definidos en EventController estos serán invocados. Estos métodos son definidos así:

public class EventController extends GenericForwardComposer {
    private EventDAO eventDao = new EventDAO();
    // Omitted...
    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);
        }
    }
}
		<button id="add" label="Add" />
		<button id="update" label="Update" />
		<button id="delete" label="Delete" />

Actualizar la vista usando Databinding

Después de interactuar con la base de datos, el último paso es actualizar la vista. Simplemente notificar al Databinding para que actualice el modelo por ti, cuando el usuario cliquée en cualquier botón. Intenta registrar un atributo load-after en el atributo model del listbox, y el Databinding actualizará la vista automáticamente si el evento especificado es capturado.

<?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