Mi primera vista en ZK como desarrollador JSF (I).

0
19020

Mi primera vista en ZK como desarrollador JSF (I).

0. Índice de contenidos.


1. Introducción

ZK es un framework orientado a la capa de presentación que permite generar aplicaciones RIA,
aplicaciones ricas de internet, haciendo uso de una colección de componentes visuales que facilita
enormemente la tarea de desarrollar una interfaz de usuario interactiva. La comunicación de eventos entre
cliente y servidor se realiza por Ajax de una manera transparente sin necesidad de hacer uso de lenguajes de
programación en cliente: HTML y/o Javascript. Son esos componentes visuales los que encapsulan la renderización
en el navegador de la sintaxis adecuada de HTML y el comportamiento en Javascript para añadir la captura de eventos
en el cliente y la invocación a métodos en la capa de control en el servidor.

El objetivo de este tutorial es mostrar los aspectos básicos del framework desde el punto de vista de un desarrollador
con experiencia en otros frameworks de presentación y, en concreto, en JSF. Por definición, un framework de presentación
debe proporcionar el soporte necesario para llevar a cabo la internacionalización de la interfaz, hacer uso de plantillas,
validar la información de entrada, convertir tipos de datos complejos, mantener el estado de los objetos entre vistas,
configurar la capa de control y reglas de navegación,… en este tutorial comenzaremos a trabajar en estos conceptos, dando por hecho que
disponemos de conocimientos previos de JSF.

No se trata de realizar una comparativa entre ambos frameworks (ZK VS JSF), básicamente, porque no se pueden
comparar, no ofrecen lo mismo. Para realizar una comparativa con JSF tendríamos que elegir una librería de componentes
visuales para JSF, como Primefaces; todo se andará… para los que tengáis experiencia, sabréis que el primer
parráfo de esta introducción podría describir, de la misma forma, a ambas librerías de componentes visuales, tanto ZK
como Primefaces.

Sin llegar al nivel de componentes visuales RIA y basándonos en los conceptos que nos proporcionaría la
especificación de JSF, vamos a ver cómo comenzar a trabajar con ZK; y lo haremos haciendo una clara separación
de capas de modo tal que la lógica de negocio residirá en beans de Spring que inyectaremos en la capa de control
con el soporte nativo que nos proporciona ZK.

Para más información en castellano sobre el framework ZK, podéis acudir a
la introducción y tutoriales anteriores de ZK.


2. Entorno.

El tutorial, y el código que contiene, han sido escritos usando el siguiente entorno:

  • Hardware: Portátil MacBook Pro 15′ (2.4 GHz Intel Core i7, 8GB DDR3 SDRAM).
  • Sistema Operativo: Mac OS X Lion 10.7.4
  • Eclipse Kepler + m2e plugin
  • ZK 7.0.0 CE


3. Configuración.

En este punto vamos a ver la configuración básica en nuestro módulo web para soportar ZK y como de costumbre,
haciendo uso de maven, lo primero es declarar nuestras dependencias en el fichero pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
	<groupId>com.autentia.training</groupId>
  <artifactId>management-training-zk</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <name>management-training-zk</name>
  
	<organization>
		<name>Autentia Real Business Solutions S.L.</name>
		<url>http://www.autentia.com</url>
	</organization>

	<developers>
		<developer>
			<name>Jose Manuel Sánchez Suárez</name>
			<email>jmsanchez@autentia.com</email>
		</developer>
	</developers>

	<properties>
		<java.version>1.7</java.version>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<spring.version>4.0.0.RELEASE</spring.version>
		<zk.version>7.0.0</zk.version>
	</properties>
	
	<build>
		<finalName>management-training-zk</finalName>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.5.1</version>
				<configuration>
					<source>${java.version}</source>
					<target>${java.version}</target>
				</configuration>
			</plugin>
		</plugins>
	</build>

	<dependencies>
		
		<!-- Spring IoC support -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${spring.version}</version>
		</dependency>
		
		<dependency>
			<groupId>org.apache.velocity</groupId>
			<artifactId>velocity</artifactId>
			<version>1.6</version>
		</dependency>
		
	    <!-- ZK CE requirements -->      
		<dependency>
			<groupId>org.zkoss.zk</groupId>
			<artifactId>zk</artifactId>
			<version>${zk.version}</version>
		</dependency>
		<dependency>
			<groupId>org.zkoss.zk</groupId>
			<artifactId>zhtml</artifactId>
			<version>${zk.version}</version>
		</dependency>
		<dependency>
			<groupId>org.zkoss.zk</groupId>
			<artifactId>zml</artifactId>
			<version>${zk.version}</version>
		</dependency>
		<dependency>
			<groupId>org.zkoss.zk</groupId>
			<artifactId>zul</artifactId>
			<version>${zk.version}</version>
		</dependency>
		<dependency>
			<groupId>org.zkoss.common</groupId>
			<artifactId>zcommon</artifactId>
			<version>${zk.version}</version>
		</dependency>
		<dependency>
			<groupId>org.zkoss.common</groupId>
			<artifactId>zweb</artifactId>
			<version>${zk.version}</version>
		</dependency>
		<dependency>
			<groupId>org.zkoss.common</groupId>
			<artifactId>zel</artifactId>
			<version>${zk.version}</version>
		</dependency>
		<dependency>
			<groupId>org.zkoss.zk</groupId>
			<artifactId>zkbind</artifactId>
			<version>${zk.version}</version>
		</dependency>

		
		<dependency>
			<groupId>org.zkoss.zk</groupId>
			<artifactId>zkplus</artifactId>
			<version>${zk.version}</version>
		</dependency>
		
		<!-- javax activation -->
		<dependency>
			<groupId>javax.activation</groupId>
			<artifactId>activation</artifactId>
			<version>1.1-rev-1</version>
		</dependency>

		<!-- ZK Themes -->
		<dependency>
			<groupId>org.zkoss.theme</groupId>
			<artifactId>sapphire</artifactId>
			<version>${zk.version}</version>
		</dependency>
		<dependency>
			<groupId>org.zkoss.theme</groupId>
			<artifactId>silvertail</artifactId>
			<version>${zk.version}</version>
		</dependency>

		<!-- Java servlet -->
		<dependency>
		        <groupId>javax.servlet</groupId>
		        <artifactId>javax.servlet-api</artifactId>
		        <version>3.0.1</version>
		        <scope>provided</scope>
		</dependency>

		<!-- commons -->
		<dependency>
			<groupId>commons-io</groupId>
			<artifactId>commons-io</artifactId>
			<version>1.3.1</version>
		</dependency>
		<dependency>
			<groupId>commons-logging</groupId>
			<artifactId>commons-logging</artifactId>
			<version>1.1.1</version>
		</dependency>
		<dependency>
			<groupId>commons-digester</groupId>
			<artifactId>commons-digester</artifactId>
			<version>2.0</version>
		</dependency>
		<dependency>
			<groupId>commons-collections</groupId>
			<artifactId>commons-collections</artifactId>
			<version>3.2.1</version>
		</dependency>
		
		<!-- Log4j -->
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.16</version>
		</dependency>

		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-simple</artifactId>
			<version>1.6.4</version>
		</dependency>

		<dependency>
			<groupId>org.apache.geronimo.ext.tomcat</groupId>
			<artifactId>juli</artifactId>
			<version>7.0.23.1</version>
			<scope>test</scope>
		</dependency>

		<!-- Rome -->
		<dependency>
			<groupId>rome</groupId>
			<artifactId>rome</artifactId>
			<version>1.0</version>
		</dependency>
		
	</dependencies>
	
	<repositories>
		<repository>
			<id>zk repository</id>
			<url>http://mavensync.zkoss.org/maven2</url>
		</repository>
		<repository>
			<id>ZK EE Evaluation</id>
			<url>http://mavensync.zkoss.org/zk/ee-eval</url>
		</repository>
		<repository>
			<id>com.asual.maven.public</id>
			<name>Asual Public Repository</name>
			<url>http://www.asual.com/maven/content/groups/public</url>
		</repository>
	</repositories>
	
</project>

No son pocas y solo vamos a usar las de la versión community.

Una vez declaradas y teniendo el soporte de la especificación de servlets 3.0 no necesitaríamos más configuración que
incluir el fichero de configuración de zk, zk.xml dentro del directorio WEB-INF, aunque aún vacío.

<?xml version="1.0" encoding="UTF-8"?>
<zk>
	
</zk>

En la dependencia zk-7.0.0.jar ya se incluye el correspondiente web-fragment.xml que configura todo lo necesario para
el framework y mapea las siguientes extensiones contra el servlet de entrada de todas las peticiones del framework,
siguiendo el patrón front controller:

	<servlet-mapping>
		<servlet-name>DHtmlLayoutServlet</servlet-name>
		<url-pattern>*.zul</url-pattern>
	</servlet-mapping>
	<servlet-mapping>
		<servlet-name>DHtmlLayoutServlet</servlet-name>
		<url-pattern>*.zhtml</url-pattern>
	</servlet-mapping>

Este tipo de configurción automática también la tenemos con JSF 2.0 y cualquier otro framework servlet 3.0 compliant.


4. Internacionalización.

ZK proporciona un soporte nativo para internacionalizar los literales de nuestras interfaces de usuario basado,
por defecto, en ficheros de propiedades.

Como decía, por defecto, trata de encontrar un fichero zk-label_lang.properties en el directorio WEB-INF,
donde lang es el locale del idioma del cliente. El idioma del cliente se obtiene de forma automática de la configuración del navegador,
que llega a través de las cabeceras de la petición http.

Si queremos personalizar el nombre de los ficheros de propiedades o añadir más de uno podemos incluir la
siguiente configuración en el fichero zk.xml.

<system-config>
	    <label-location>/WEB-INF/classes/messages.properties</label-location>
</system-config>

Para hacer uso de los mensajes, dentro de las vistas zul podemos hacer referencía,
a través del Expression Language de ZK, al objeto labels.

<column hflex="2" label="${labels.name}" align="center" />

El objeto labels es un mapa, como en JSF, con lo que podemos acceder a las claves vía ${labels['actions.save']} donde action.save es una clave dentro del fichero.

Si dentro del fichero tuvieramos más de una misma clave con el mismo prefijo separado por puntos, se crearía un nuevo mapa dentro del mapa de labels que permitiría acceder a las claves vía ${labels.actions.save}.

También podemos recuperar los mensajes desde código java haciendo uso del método estático getLabel de la clase Labels.

Labels.getLabel("name");

Si tuviésemos la necesidad de usar una estrategia distinta, como
recuperar los mensajes de internacionalización de una tabla de base de datos
, al igual que vimos para JSF2, con ZK también podríamos hacerlo implementando un
LabelLocator propio.


5. Sistema de plantillas.

ZK proporciona un sistema de plantillas propio, similar al de facelets para JSF2 que permite definir un layout común para todas nuestras vistas de modo tal
que las páginas incrustan contenido en las secciones preparadas para ello de la plantilla. Así las distintas vistas se ocupan de su contenido concreto y todas las
secciones comunes se configuran en la plantilla.

Podemos definir una plantilla común incluyendo una página zul en un directorio de templates dentro del de WEB-INF

con un contenido similar al siguiente:

<?xml version="1.0" encoding="UTF-8"?>	 
<zk xmlns:n="native">

	<n:div id="wrapper">		
		<n:div id="header">
			<n:h1>${labels.app.title}</n:h1>
			<n:span id="logo">
				<image src="/wp-content/uploads/tutorial-data//resources/img/logo.png" />
			</n:span>
		</n:div>
		
		<n:div id="nav">
			<include src="/wp-content/uploads/tutorial-data//WEB-INF/templates/menu.zul" />
		</n:div>
		
		<n:div id="content">
			<n:h2><div self="@{insert(title)}" /></n:h2>
			
			<n:br />
			
			<div self="@{insert(content)}">
			</div>
		</n:div>
			
		<n:div id="footer">
			<n:small>${labels.app_technology}</n:small>
		</n:div>
	</n:div>
</zk>

Con las marcas @{insert(title)} definimos las regiones de la plantilla que las páginas pueden personalizar, donde title o content
es el nombre de la region. En realidad lo que hacemos es redefinir el contenido de los componentes de zk mediante el atributo self, de
este modo las páginas definen un contenido que se incrustará en esos componentes, no existe un componente de insercción propiamente dicho.

Las páginas que necesitan hacer uso de la plantilla pueden hacerlo de la siguiente forma:

<?xml version="1.0" encoding="UTF-8"?>
<?page title="${labels.actions.customers.list}" ?>
<?init class="org.zkoss.zk.ui.util.Composition" arg0="/WEB-INF/templates/defaultLayout.zul"?>
<zk>
	<label self="@define(title)" value="${labels.actions.customers.list}" />
	
	<div self="@define(content)" apply="org.zkoss.bind.BindComposer"
		viewModel="@id('vm') @init('com.autentia.training.masters.views.CustomersView')">
		<grid id="grid" 
			model="@load(vm.customers)"
			mold="paging" pageSize="10">
			<columns>
				<column hflex="2" label="${labels.name}" align="center" />
				...
			</columns>
			<template name="model">
				<row>
					<label value="@load(each.name)" />
					...
				</row>
			</template>
		</grid>
	</div>
	
</zk>

Para hacer uso de la plantilla con la directiva <?init y declarando la clase org.zkoss.zk.ui.util.Composition podemos pasar como
argumento la ubicación de la plantilla. En realidad es la ubicación o ubicaciones, puesto que acepta más de una plantilla.

Con las directivas @define(title) incluidas también en el atributo self de los componentes definimos el
contenido de las seciones. Podemos definir más de un contenido de modo tal que se irán incrustando en los componentes de
la plantilla de modo secuencial.

La plantilla no contiene la cabecera de html, puesto que la genera zk, con lo que la primera duda que se nos plantea es cómo redefinir
el título de la página. En la plantilla la directiva <?page title… no se procesa puesto que no se genera la cabecera de html con lo que
tenemos la opción de declararla como una página completa o definir dicha directiva en las páginas que hacen uso de la plantilla.
En el ejemplo, hemos optado por la segunda de las opciones.

Por último, en la plantilla:

  • estamos combinando componentes de zk con el espacio de nombres por defecto y componentes html nativos con el espacio de nombres «n». ZK tiene un componente div que no es más que un wrapper del div de html, nos puede interesar hacer uso del
    componente nativo de html para preparar una maquetación por capas haciendo uso del id, puesto que con el componente div de ZK ese id es autogenerado.
  • podemos realizar inclusiones de otras páginas, como la del menú, por claridad en el código y para reutilizarlo.

La página de menú, empezaría a tener un contenido como el que sigue:

<?xml version="1.0" encoding="UTF-8"?>

<zk>
	<menubar id="menubar" autodrop="true">
		<menuitem label="${labels.menu.customers}" href="/pages/masters/customers.zul"/>
		...
	</menubar>
</zk>

Mi primera vista en ZK comienza a tener el siguiente aspecto, donde el rectángulo rojo es en la región content y la región title es la azul.

Ya estamos usando un componente de tabla y paginación, aunque no es el objetivo de este tutorial; por cierto que
el listado de clientes lo he extraido de las empresas que a día de hoy tienen publicada una oferta de trabajo en infojobs pidiendo experiencia con ZK.


6. Generando la capa de control para mantener el estado y comportamiento de la vista.

Con ZK podemos trabajar de 4 formas distintas:

  • generando la vista en ZUL (XML) y la capa de control en java, con dos aproximaciones
    • MVC: declarando nuestros controladores como Composers y vinculando los componentes visuales de la vista
      con componentes java en la capa de control; si quisieramos encontrar algún paralelismo en JSF sería como declarar
      un binding entre un componente de la vista y un componente de la capa de control, manteniendo en los managed beans
      una instancia de los componentes visuales haciendo uso de las clases java que los implementan,
    • MVVM: sin necesidad de declarar nuestros controladores con ningún tipo de herencia, son POJOs que exponen
      el estado y el comportamiento; es como nosotros solemos trabajar con los Managed Beans de JSF.
  • generando tanto la vista como la capa de control en Java; como cuando en JSF generamos el contenido del
    árbol de componentes de forma dinámica creando las instancias de los componentes visuales en java y añadiéndolos
    al árbol,
  • generando tanto la vista como la capa de control en ZUL con ZKscript, como si usasemos JSP con scriptlets o
    JSF 1.2 con JSP y scriptlets; ZK desaconseja esta aproximación por falta de rendimiento.

En nuestra primera vista usaremos el modo MVVM por ser el más similar a cómo venimos trabajando con JSF.

Para declarar un controlador no se usa ninguna anotación ni hay que extender de ninguna clase porque es desde la vista
desde la que se declara que quieres vincular un componente, y los componentes hijos de este, al estado y comportamiento
de un controlador.

	<div apply="org.zkoss.bind.BindComposer"
		viewModel="@id('vm') @init('com.autentia.training.masters.views.CustomersView')">

Con la anotación @id se da un identificador a la instancia del controlador dentro de la sección de componentes de la página zul,
y con la anotación @init se hace referencia al controlador, paquete y nombre de la clase (cuidado con las refactorizaciones de paquetes).

Dentro de los componentes hijos podremos hacer referencia a las instancias de los objetos declarados en el controlador
con el prefijo de su id declarado en la anotación @id y las siguientes anotaciones, entre otras:

  • @load: para mostrar información,
  • @save: para almacenar información,
  • @bind: para mostrar y almacenar información,
  <grid id="grid" 
			model="@load(vm.customers)" >
			
  • @command: para declarar un evento de acción con un id declarado como un comando en un método del controlador,
  • 
      <textbox value="@bind(vm.nameToSearch)"/>
      <button label="Buscar" onClick="@command('search')"/>
    		
    

    En el controlador, para declarar un método de acción debemos usar la anotación @Command que, por defecto, declara
    un comando de acción con el nombre del método anotado:

    
      @NotifyChange("customers")
      @Command
      public void search(){
        ...	
    

    Y con la anotación @NotifyChange({"customers"}) junto al evento declarado en el Controlador con
    @Command es similar a la declaración de rerender o update que podemos usar con los componentes Ajax de JSF2,
    de tal manera que indicamos en ese punto qué componentes tienen que repintarse cuando se produce ese evento de acción.
    La anotación admite un asterisco como parámetro que signficaría que se repintarían todos los componentes visuales asociados
    a ese controlador, como el @form de JSF2.


    7. Inyección de dependencias de beans de Spring en la capa de control -ViewModel- de ZK.

    ZK proporciona un soporte nativo para enganchar tanto con la inyección de dependencias de Spring como de CDI.

    En el caso de Spring, podemos anotar la clase del controlador con @VariableResolver como sigue

    @VariableResolver(org.zkoss.zkplus.spring.DelegatingVariableResolver.class)
    public class CustomersView implements Serializable {
    
      @WireVariable
      private CustomerRepository customerRepository;
      
      ...
      
    

    y, como veis, las interfaces de los servicios de Spring con @WireVariable.

    También podríamos obtener una instancia de un bean haciendo uso de un método estático de una clase de utilidades de ZK
    llama SpringUtil.

    Con ello, ya tenemos cableados nuestros servicios con la lógica de negocio en la capa de control para poder
    ser consumidos en las vistas exponiendo y recogiendo información del cliente.


    8. Referencias.


    9. Conclusiones.

    En ocasiones puedes elegir framework y en otras te viene dado, de tal manera que debes intentar adaptar
    tu manera hacer las cosas al marco tecnológico en el que te encuentres en cada momento, pero siempre desde el
    punto de vista de las buenas prácticas y patrones de diseño que venías usando.

    En este primer tutorial hemos visto como comenzar a usar ZK, desde el punto de vista de los conceptos de JSF pero sin perder
    la perspectiva de que estamos trabajando con un framework distinto.

    Aún nos queda por cubrir muchos conceptos, stay tuned!.

    Un saludo.

    Jose

    jmsanchez@autentia.com


    10. ¿Necesitas formación?.

    En los cursos de formación que Autentia imparte sobre JSF y donde vemos librerías de componentes (Primefaces, Richfaces, ICEfaces, Apache Suite, ADF,…)
    aprendemos a diferenciar claramente entre especificación e implementación y las distintas opciones opensource que tenemos en el mercado para JSF,
    te invito a que le eches un vistazo al catálogo de cursos de Autentia,
    que siempre estamos dispuestos a ampliar y personalizar con las necesidades de nuestros clientes.

    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