Crear el interfaz de usuario programando directamente desde un Richlet

1
10918

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.


    zkLoader
    /zk/*

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:


    SearchRichlet
    tutorial.richlet.SearchRichlet

 

    SearchRichlet
    /search

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

1 COMENTARIO

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad