Buscar
Social
Ofertas laborales ES
« Oracle está considerando las actualizaciones automáticas para Java | Main | Groovy 2.1 »
domingo
ene272013

Crear el interfaz de usuario directamente desde un Richlet.

ZK Framework




Framework ZK

Crear el interfaz de usuario programando directamente desde un Richlet.

Enero de 2013, artículo original de Hawk Chen, Engineer, Potix Corporation

Contenido

  1. Introducción
  2. Aplicación de ejemplo
  3. Implementation
    1. Creando la Interfaz de Usuario
    2. Renderizando el modelo de datos
    3. Event Listener
  4. Configuración del Richlet
    1. Activar el soporte de Richlets
    2. Mapear la URL a la que responderá el Richlet
  5. Sumario
  6. Descargas

Introducción

Un Richlet es un pequeño programa en Java que construye el interfaz de usuario mediante programación en Java, y esto es una alternativa a escribir ficheros ZUL que se sirvan bajo petición del usuario.

Cuando un usuario hace un apetición mediante una URL (request) que está mapeada en el Richletf, ZK Loader hace responsable al Richlet de la construcción de la interfaz de usuario.

Esto les da a los desarrolladores todo el poder a la hora de crear los componentes. La elección entre páginas ZUML y Richlets depende de su preferencia.

En este artículo, demostraremos cómo usar un Richlet creando una pequeña aplicación que consistirá en un buscador. Para una explicacíon más detallada ver: Richlet en la ZK Developer's Reference.

Aplicación de ejemplo

La aplicación de ejemplo que vamos a construir es un simple catálogo de coches.

Esta aplicación tiene 2 funciones principales

  1. Buscar coches.

    Escribir una palabra clave en el campo de texto, hacer click en el botón de buscar y mostrar los resultados de la búsqueda en la lista contigua.

  2. Ver los detalles de un coche.

    Haciendo clic en uno de los coches de la lista, el área contigua mostrará los detalles del coche seleccionado, incluyendo el modelo, precio, descripción y vistra prévia.

Ejemplo del buscador

Implementación

Para implementar un Richlet, tu clase tiene que implementar el interfaz Richelt. A pesar de que, no es necesario implementarla tal cual. En vez de eso puedes extender GenericRichlet y solo sobreescribir el método Richlet.service(Page). Este método será el que se llame cuando se haga una petición al Richlet por parte del usuario.

public class SearchRichlet extends GenericRichlet {

@Override
public void service(Page page) throws Exception {
//...
}

@Override
public void init(RichletConfig config) {
//initialize resources, e.g. get initial parameters
}

@Override
public void destroy() {
//destroy resources
}
}

Para tener mejor control, puedes incluso implementar los métodos Richlet.init(RichletConfig) y Richlet.destroy() para inicializar y destruir cualquier cosa que necesite el Richlet para funcionar.

Creando la Interfaz de Usuario

Una de las funciones princpales de un Richlet es crear la interfaz de usuario. Es recomendable empezar leyendo los conceptos básicos sobre intefaz de usuario en ZK antes de crearla mediante Java.

  • El interfaz de usuario en ZK es un árbol de componentes, cada componente tiene un componente padre, y a su vez puede tener o no múltiples componentes hijos.
  • No todos los componentes aceptan como hijos a todos los tipos de componentes que existen, solo a aquellos que se correspondan, o incluso ninguno.

Por ejemplo, un Grid en ZUL acpeta columnas y Filas como hijos. Para más detalle mirar la documentación al respecto: ZK Component Reference

public class SearchRichlet extends GenericRichlet {

@Override
public void service(Page page) throws Exception {
Component rootComponent = buildUserInterface();
...
}

private Component buildUserInterface(){

//build search area
final Textbox keywordBox = new Textbox();
Button searchButton = new Button("Search");
searchButton.setImage("/img/search.png");

Hbox searchArea = new Hbox();
searchArea.setAlign("center");
searchArea.appendChild(new Label("Keyword:"));
searchArea.appendChild(keywordBox);
searchArea.appendChild(searchButton);

...
}
...
}

Línea 12: Para crear un componente, simplemente lo instanciamos.
Línea 14: Cada atributo de un componente tiene su correspondiente método setter que podemos usar para asignarle el valor correspondiente.
Línea 18: Para establecer una relación Padre-Hijo entre componentes, podemos usar el método appendChild(Component). Esto enlaza el componente indicado en el método, al final de la lista de componentes hijos (que ya tuviera) del componente padre. Hay otros métodos similares para hacer esto como setParent(Component), insertBefore(Component,Component). Puedes encontrar más información al respecto en la documentación

Renderizando el modelo de datos

Después de proveer el objeto Modelo al componente ListBox, normalmente necesitamos indicar cómo mostrar los datos que contiene. Necesitamos crear un objeto Render para ello.

Un Render es una clase Java en la que se indica cómo se va a mostrar cada dato del modelo. Lo creamos implementando la interfaz de tipo Render que corresponda a cada componente, para un Listbox usaremos ListitemRenderer. En la ZK Developer's Reference están la del resto de componentes.

Item renderer de un Listbox

class CarRenderer implements ListitemRenderer<Car>{

@Override
public void render(Listitem listitem, Car car, int index) throws Exception {
listitem.appendChild(new Listcell(car.getModel()));
listitem.appendChild(new Listcell(car.getMake()));
Listcell priceCell = new Listcell();
priceCell.appendChild(new Label("$"));
priceCell.appendChild(new Label(car.getPrice().toString()));
listitem.appendChild(priceCell);
}
}
  • En el método render(), nos encargamos de crear el interfaz del usuario que queremos añadiendo los componentes hijos al componente padre Listitem.

Despues de crear el Render necesitamos asignarlo al ListBox.

carListbox.setItemRenderer(new CarRenderer());

Event Listener

En nuestra aplicacíon de ejemplo, un usuario puede hacer click en el botón de "Search" para realizar su búsqueda, tenemos por lo tanto que escuchar el evento "onClick". Podemos resolverlo invocando al método AbstractComponent.addEventListener(String, EventListener) del comonente. El primer parámetro es el nombre del evento, y el segundo es un objeto que implmente la interfaz EventListener. En un EventListener, puedes manipular los componentes para añadir tu lógica de la aplicación, como puede ser cambiar atributos de otros componentes, crear nuevos componentes, o eliminar uno existente. Puedes ver todas las características de los componentes en la ZK Component Reference, y ver qué atributos puedes necesitar usar.

public class SearchRichlet extends GenericRichlet {

private Component buildUserInterface(){

...

searchButton.addEventListener(Events.ON_CLICK, new EventListener<Event>() {
//search
@Override
public void onEvent(Event event) throws Exception {
String keyword = keywordBox.getValue();
List<Car> result = carService.search(keyword);
carListbox.setModel(new ListModelList<Car>(result));
}

});

...
}
}

Línea 7: Puedes crear una clase a parte que implemente EventListener. En este ejemplo usamos una clase anónima por simplificar. Pero ojo, en un clúster debes implementar la versión serializable SerializableEventListener.
Línea 10: Escribe la lógica de tu aplicación dentro del método onEvent(), cosas como leer un valor con un get, cambiar un atributo de un componente o actualizar información

Otra función del ejemplo es que cuando el usuario selecciona un coche de la lista, mostramos sus detalles en el área de información. Para manejar esto, tenemos que escuchar el evento de seleccionar del componente Listbox, y entonces leer los atributos del coche y asignar los valores a los componentes correspondientes de la vista.

public class SearchRichlet extends GenericRichlet {

private Component buildUserInterface(){

...

carListbox.addEventListener(Events.ON_SELECT, new EventListener<SelectEvent>() {
//show selected item's detail
@Override
public void onEvent(SelectEvent event) throws Exception {
//get selection from listbox's model
Set<Car> selection = ((Selectable<Car>)carListbox.getModel()).getSelection();
if (selection!=null && !selection.isEmpty()){
Car selected = selection.iterator().next();
previewImage.setSrc(selected.getPreview());
modelLabel.setValue(selected.getModel());
makeLabel.setValue(selected.getMake());
priceLabel.setValue(selected.getPrice().toString());
descriptionLabel.setValue(selected.getDescription());
}
}
});

...
}
}

Configuración del Richlet

Hay 2 requisitos para que el Richlet esté disponible para la aplicación cliente.

  1. Activar el soporte de Richlets (en WEB-INF/web.xml)
  2. Mapear la URL (que puede ser estática o un patrón) a la que responderá el Richlet (in WEB-INF/zk.xml)

Activar el soporte de Richlets

Por defecto, los richlets están desactivados. Para activarlos, hay que añadir la siguiente declaracíon en el fichero WEB-INF/web.xml.

<servlet-mapping>
<servlet-name>zkLoader</servlet-name>
<url-pattern>/zk/*</url-pattern>
</servlet-mapping>

De este ejemplo, puedes cambiar /zk/* a otro patrón (que corresponda con una URL válida) que tu quieras, como por ejemplo /do/*. Fíjate que no puedes mapear la expresión como si de una extensión de un fichero se tratase (como por ejemplo *.do) o se procesará como una página ZUML en vez de como un Richlet.

Mapear la URL a la que responderá el Richlet

Cada Richlet que implementes, debes declararlo en la configuración WEB-INF/zk.xml de la siguiente forma:

<richlet>
<richlet-name>SearchRichlet</richlet-name>
<richlet-class>tutorial.richlet.SearchRichlet</richlet-class>
</richlet>

<richlet-mapping>
<richlet-name>SearchRichlet</richlet-name>
<url-pattern>/search</url-pattern>
</richlet-mapping>

Línea 6: Después de definir el Richlet, puedes mapearlo bajo tantas URLs como quieras mediante el elemento de configuración richlet-mapping

Puedes visitar http://localhost:8080/PROJECT_NAME/zk/search y ver tu Richlet. La URL especificada en el parámetro url-pattern debe empezar siempre con "/".

Si la URL termina en /*, se asocia a cualquier petición con el mismo prefijo. Para recibir la URL de la petición actual puedes chequear el valor que retorna el método getRequestPath de la página en la que te encuentres.

public class MyRichlet extends GenericRichlet {

@Override
public void service(Page page) throws Exception {
if ("/search/admin".equals(page.getRequestPath())){
//build admin UI
}else{
//build normal UI
}
...
}
}

Sumario

ZK es tan versátil que provee de multiples opciones para que seas tú quien elija cómo construir la Interfaz de usuario, o incluso varias al mismo tiempo, dependiendo de tus preferencias o entorno.

Descargas y recursos interesantes

Este documento es un extracto de la documentación oficial del Framework ZK, traducido y ampliado por Francisco Ferri. Colaborador de Potix (creadores del Framework ZK). Si quieres contactar con él puedes hacerlo en franferri@gmail.com, en twitter @franciscoferri o en LinkedIn

PrintView Printer Friendly Version

EmailEmail Article to Friend

Reader Comments (1)

No acabo de entender la necesidad de precisar nuevos sistemas de plantillas (como ZUL) para crear componentes visuales, existiendo muchos muy buenos ya de sobra conocidos. Parece que ninguno es lo suficientemente bueno y por eso se precisa crear y aprender uno nuevo que deja los proyectos muy dependientes en este aspecto. Agradecería me pudieran facilitar aportaciones en sentido contrario. Por ejemplo para Web, el ya casi abandonado y simplísimo Apache Click, utiliza por defecto Velocity y desde el 2010 que Casi implementa todo lo que se describe en este artículo, y de hecho me parece ver una extraordinaria similitud.

enero 28, 2013 | Unregistered CommenterFerdy

PostPost a New Comment

Enter your information below to add a new comment.

My response is on my own website »
Author Email (optional):
Author URL (optional):
Post:
 
Some HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>