Integre a estrutura de aplicativo da Internet avançada ZK com o Informix para criar aplicativos do mundo real

Desenvolvimento de aplicativo da Web rápido para o Informix

Este tutorial apresenta um exemplo do mundo real que integra o IBM® Informix® e o ZK, uma estrutura de rich Internet application (RIA). O Informix é o principal produto IBM RDBMS, enquanto o ZK é uma estrutura de aplicativo da Web com base em Java com suporte para aplicativos Ajax. Esta estrutura orientada a evento permite a criação de interfaces com usuário avançadas com mínimo conhecimento e uso do JavaScript. A abordagem centrada em servidor exclusiva do ZK permite sincronização de componentes e eventos em todo o cliente e o servidor via o mecanismo central.

Timothy Clare, Technology Evangelist, Potix Corp.

Photo of author Timothy ClareTimothy Clare é divulgador de tecnologia para a Potix Corporation, que produz a estrutura ZK. Ele trabalha com várias tecnologias móveis e da Web há mais de 10 anos.



Sachin K Mahajan , Software Developer, IBM  

Sachin Mahajan photoSachin Mahajan fez mestrado na University of Utah, em Salt Lake City, Utah. Ele trabalhou em pequenas e médias empresas de nos EUA e na Índia realizando várias funções técnicas e gerenciais.



06/Set/2011

Antes de iniciar

Introdução

O ZK é semelhante ao Ajax sem JavaScript. É uma estrutura eficiente composta por um mecanismo orientado por evento com base em Ajax, um conjunto avançado de componentes XHTML e XUL e uma linguagem de marcação chamada ZUML com o objetivo de criar interfaces com o usuário com recursos avançados. Para um exemplo detalhado da potência do ZK e um exemplo da vida real, consulte um link para o artigo Rich Internet applications using ZK nos Recursos .

O objetivo deste tutorial é desenvolver um aplicativo de amostra avançado usando a estrutura ZK framework e um banco de dados Informix. O ZK é uma estrutura Ajax de software livre que facilita a criação de sites conduzidos por Ajax usando Java. Os desenvolvedores podem usar a estrutura orientada por evento do ZK e linguagens de marcação para criar aplicativos eficientes de maneira rápida e eficiente.

Pré-requisitos

Este tutorial o conduzirá por cada etapa do processo e é voltado para novos usuários do ZK. Embora não seja necessária nenhuma experiência com o JavaScript, os usuários devem ter alguma experiência com Java antes de começar.

Antes de iniciar, certifique-se de fazer o seguinte:

  • Ter instalado um contêiner de servlet, por exemplo, o Apache Tomcat nos Recursos .
  • Ter instalado o ZK. O link para fazer o download do ZK está localizado nos Recursos deste tutorial.
  • Ter instalado o driver JDBC para Informix. Consulte o catálogo Recursos para obter o link.
  • Ter instalado o Informix 11.50 ou posterior. O Recursos inclui um link para fazer o download de uma versão de teste ou gratuita do Informix. Este tutorial foi desenvolvido usando o Informix 11.50.TC4 Developer Edition.

Design do aplicativo ZK

Este aplicativo segue o padrão arquitetural model-view-controller (MVC), separando a lógica de negócios da interface com o usuário, permitindo a separação das interfaces com o usuário (contidas nos arquivos zul) da lógica de negócios Java. Esta separação de interesses leva a um código mais limpo de com maior capacidade de manutenção.

Consulte a seção Download deste tutorial para obter um link para o arquivo ZK-Informix-Article-src.zip que contém vários arquivos. A lista a seguir categoriza esses arquivos com relação ao padrão MVC:

  • Modelo: Department.java, Employee.java, EmployeesDAO.java, DepartmentDAO.java, BaseDAO.java, DatabaseInformation.java, QuerySet.java, EmployeeQuerySet.java, DepartmentQuerySet.java, SqlPropertyLoader.java
  • Visualização: main.zul, employees.zul, departments.zul
  • Controlador: DatabaseSetupController.java, DepartmentController.java, EmployeeController.java, MainController.java

Observe que o arquivo DatabaseInformation.java contém todas as configurações que o aplicativo usará ao acessar o banco de dados. Se preferir, é possível alterar manualmente as configurações desse arquivo, e então acessar main.zul.


Implementando o modelo

Esta seção apresenta a implementação do modelo usando o ZK. Como você viu na lista da seção anterior, o modelo contém nove arquivos. Entretanto, o modelo não é complexo e o maior volume de arquivos é apenas uma abstração do autor.

Projetando o esquema do banco de dados

Para o exemplo usado neste tutorial, duas tabelas são necessárias, uma chamada employees e outra chamada departments. Os atributos para as tabelas estão listados como segue.

Tablela 1. Tabela Employees
CampoType
Idvarchar(50)
Nomevarchar(50)
Sobrenomevarchar(50)
IdadeInteger
Departmentidvarchar(50)
Tablela 2. Tabela Departments
CampoType
Idvarchar(50)
Nomevarchar(50)

Bibliotecas do modelo

Para a camada de modelo, o software object/relational mapping (ORM), como Hibernate e TopLink, não foram usados para manter o aplicativo o mais simples possível. O aplicativo de exemplo utiliza JDBC puro adoçado com o DbUtils de apache.org.

Como o Web site Apache indica, DbUtils é "Um pequeno conjunto de classes projetadas para facilitar o trabalho com o JDBC. O código de limpeza de recursos do JDBC é um trabalho trivial e propenso a erros, então essas classes removem todas as tarefas de limpeza do código, deixando o que realmente se deseja fazer com JDBC em primeiro lugar: consultar e atualizar dados."

Tendo estabelecido as bibliotecas necessárias, você agora aprenderá sobre a inicialização dos drivers, a criação do nosso modelo de domínio e a criação de uma camada para acessar o banco de dados.

Inicialização dos drivers do Informix

Quando o aplicativo inicia, é melhor inicializar os drivers do Informix. O ZK fornece muitos pontos nos quais os desenvolvedores podem injetar código usando interfaces. Para alcançar isso, é preciso implementar a interface WebAppInit e inicializar o driver no método init de JQuery. A Listagem 1 mostra a classe que faz a inicialização.

Lista 1. Inicialização dos drivers
public class WebAppInitialization implements WebAppInit {
	
	@Override
	public void init(WebApp wapp) throws Exception {
		//let's initialize the class
		Class.forName("com.informix.jdbc.IfxDriver");
	}

}

Depois de implementar a classe de inicialização, é preciso indicar ao ZK quanto à implementação. É possível fazer isso editando o arquivo zk.xml localizado no diretório WEB-INF. O XML é usado para descrever o local do listener de inicialização personalizado.

Lista 2. Inicialização do XML
	<listener>
	    	<listener-class>org.zkforge.utils.WebAppInitialization</listener-class>
	</listener>

A Listagem 2 mostra o código necessário para registrar a classe de inicialização com o ZK.

Tendo tratado da inicialização dos drivers, agora é hora de começar a colocar o banco de dados em prática, começando com o objeto de domínio.

Criando o objeto de domínio

Para manipular o banco de dados, você implementa um objeto de domínio. As Listagens 3 e 4 são extratos dos dois beans. As implementações das funções de manipulação foram removidas. Consulte a seção de Download deste tutorial para mais detalhes sobre o código de origem completo.

Lista 3. Extrato do bean Department
public class Department {
	private String _id, _name = "";
	
	public Department() {
		//Default construct for QueryRunner
	}
	
	public Department(String id,
					  String name) {
		this._id = id;
		this._name = name;
	}
	//mutators follow
}
Lista 4. Extrato do bean Employee
public class Employee {
	private int _age = 0;
	private String _id, _firstName, _lastName = "";
	private Department _department = null;
	
	public Employee() {
		//default constructor for Employee
	}
	
	public Employee(String id, String firstName, String lastName, int age,
    Department department) {
		this._id = id;
		this._firstName = firstName;
		this._lastName = lastName;
		this._age = age;
		this._department = department;
		}
	
	//mutators follow
	}

Os objetos de domínio estão completos, então agora são necessárias classes para recuperá-los do banco de dados, inserir os objetos de acesso de dados.

Criação do objeto de acesso de dados

Para interagir com o banco de dados, é implementado um objeto DAO. Para proporcionar melhor abstração, uma classe base abstrata chamada AbstractDAO é criada. Essa classe é genérica e fornece as seguintes funções:

  • getAll: Recupera todas as entradas da tabela relevante e retorna uma lista de beans do tipo T
  • get(String id): Recupera a entrada do banco de dados em que o ID da entrada corresponde ao argumento. O método retorna um bean preenchido do tipo T.
  • delete(T entry): Exclui a entrada do banco de dados que corresponde ao tipo T
  • Insert(T entry: Insere no banco de dados a entrada do tipo T
  • Update(T entry): Atualiza os dados relevantes no banco de dados usando o tipo T

DepartmentDAO e EmployeeDAO então se estendem de AbstractDAO para herdar sua funcionalidade base. Essas duas classes herdam a funcionalidade de AbstractDAO.

EmployeeDAO fornece personalização adicional para retornar um bean Employee que contenha um bean Department preenchido.

Lista 5. Personalização de EmployeeDAO
private EmployeeDAO() {
	super(Employee.class, _querySet, new
    BeanListHandler<Employee>(Employee.class) {
	public List<Employee> handle(ResultSet rs) throws
SQLException {
		final List<Employee> employees = new ArrayList<Employee>();		
	  		while(rs.next()) {
				employees.add(getEmployeeFromRow(rs));
						}
					return employees;
				}
			}, new BeanHandler<Employee>(Employee.class) {
			public Employee handle(ResultSet rs) throws SQLException {	
					if(!rs.next()) {
					return null;
				}					
				return getEmployeeFromRow(rs);
				}
			});
}

A Listagem 5 demonstra essa personalização em que os clientes BeanListHandler e BeanHandler são criados para o funcionário. Então é fornecida uma implementação de uma manipulação que chama um método getEmployeeFromRow convertendo um ResultSet em um Employee. Para mais informações, consulte o código de origem.

Como fornecemos consultas para o AbstractDAO?

Tendo estudado o DepartmentDAO e o EmployeeDAO, você pode ver que não há consultas presentes na classe. As consultas foram abstraídas e são enviadas para AbstractDAO através do seu construtor usando a interface QuerySet.

A interface, mostrada na Listagem 6, define os métodos básicos que retornam consultas para o tipo T. Nesse caso, DepartmentQuerySet e EmployeeQuerySet fornecem a implementação desses métodos para seus respectivos beans.

Lista 6. Interface QuerySet
public interface QuerySet<T> {
	String getAllQuery();
	String getQuery(String id);
	String getInsertQuery(T object);
	String getUpdateQuery(T object);
	String getDeleteQuery(T object);
	String getTableName();
}

Como um dado interessante à parte, as classes DepartmentQuerySet e EmployeeQuerySet usam pacotes configuráveis de recursos para carregar consultas a partir de um arquivo de propriedade.

Você agora tem um bom conhecimento sobre a implementação do modelo. Podemos, portanto, seguir adiante para ver e discutir como ele é implementado.


Implementação da visualização

Nesta seção, você aprenderá sobre o planejamento e a implementação de uma GUI usando a ampla variedade de controles Ajax fornecidos pelo ZK.

Criação da interface

A estrutura ZK usa a marcação ZUML para descrever GUIs, e armazena a marcação dentro de arquivos *.zul. ZUML é um conceito eficiente que permite aos desenvolvedores rapidamente implementar GUIs complexas. Nas seções a seguir, você verá como usar o ZUML para implementar interfaces eficientes.

Usando componentes ZK

A maioria das pessoas está familiarizada com as linguagens de marcação devido ao amplo uso de HTML e XML, então o ZUML do ZK deve instantaneamente ter uma aparência familiar. Em primeiro lugar, uma janela simples é definida.

Lista 7. Arquivo zul simples
<window id="win"  title="Welcome to the employee demo!" 
border="normal" apply="org.zkforge.controllers.MainController">
</window>

Como mostrado na Listagem 7, os atributos ID, title e border são usados para definir certas propriedades da janela. O atributo ID é uma referência do ZK ao controle, title define o texto e border define o tipo de borda da janela.

Um dos conceitos mais eficientes no ZK é seu modelo de componente. O modelo proporciona aos desenvolvedores a capacidade de colocar componentes uns dentro dos outros. Em geral, a maioria dos componentes no ZK pode ser filha de qualquer outro componente. Isso é chamado de aninhamento de componentes.

Aninhamento de componentes do ZK

Neste exemplo, é melhor dividir a funcionalidade entre departments e employees, e não fazer as duas áreas sobreporem-se. Portanto, um método fácil de separação é necessário ao permitir que se façam e desfaçam alternações rapidamente.

Por sorte, o ZK tem centenas de componentes para escolher. Neste caso, parece que uma caixa de guias funcionaria melhor. Portanto, a caixa de guias é aninhada dentro da janela, conforme mostrado na Listagem 8.

Lista 8. Componentes aninhados
<?page title="Welcome to the employee demo!" contentType="text/html;charset=UTF-8"?>
<window id="win"  title="Welcome to the employee demo!" border="normal" 
apply="org.zkforge.controllers.MainController">
		<tabbox hflex="true" id="tbTabs">
	        <tabs>
	            <tab label="Employees" />
	            <tab label="Departments" />
	        </tabs>
	        <tabpanels>
	        	<tabpanel>        		
	        	</tabpanel>
	        	<tabpanel>
	        	</tabpanel>
	        </tabpanels>
	    </tabbox>
	</window>

A saída da Listagem 8 é mostrada na Figura 1.

Figura 1. Saída Main.zul
Saída Main.zul

Alguns conceitos precisam ser realçados aqui. Primeiro, um observador notará o atributo apply para a janela e um atributo hflex na caixa de guias. Um atributo apply é usado quando se deseja vincular a UI do ZK a um GenericForwardComposer. O GenericForwardComposer, que atua como controlador no paradigma MVC para o ZK, será discutido em detalhes na próxima seção.

O atributo hflex é usado para dispor os componentes horizontalmente. Isso é complementado pelo vflex, que permite controle de layout vertical. Tanto o hflex quanto o vflex informam ao ZK como o pai do componente deve distribuir o espaço entre seus filhos. Neste caso, o autor usou verdadeiro como a caixa de guias como o único filho da janela. Definir hflex para verdadeiro indica que o componente deve preencher todo o espaço disponível. Usando hflex e vflex, é possível criar layouts complicados com eficiência. Analisar o hflex e o vflex em mais detalhes está além do escopo deste tutorial. Para mais informações, consulte o Guia de Referência do Desenvolvedor do ZK.

Tendo implementado a visualização do esqueleto para o main.zul, agora é necessário seguir adiante para projetar a visualização de department e employee.

Projeção da visualização de department e employee

Os autores precisaram tomar uma decisão quanto à implementação das visualizações. Primeiro, as duas visualizações poderiam ser colocadas diretamente no main.zul, ou poderiam ser divididas em arquivos separados e incluídas usando o componente incluir do ZK.

Decidiu-se separar a lógica department e employee em arquivos distintos e incluir esses arquivos usando o componente incluir do ZK. Os motivos para essa decisão foram os seguintes:

  1. Main.zul será mais limpo. Não precisando colocar toda a marcação XML no main.zul é muito melhor para você quando tenta entender o código, e fornece a cada seção mais capacidade de manutenção.
  2. Separa os interesses de UI da ligação de dados. Separação em dois arquivos zul fornece excelente separação de interesses de UI. Também permite o carregamento dinâmico de cada zul como coberto na seguinte seção do controlador.

O segundo motivo será discutido em detalhes mais adiante nesta seção do tutorial. Ao mesmo momento, o foco do tutorial está centrado nos arquivos zul individuais - departments.zul e employee.zul.

Departments.zul

O Departments.zul é simples. Ele contém uma caixa de listagem para mostrar uma lista de departamentos. Abaixo disso está uma caixa de grupos com uma caixa de texto que representa o nome do departamento, bem como três botões para acionar as opções create, read, update e delete (CRUD).

Lista 9. Departments.zul
<?page title="new page title" contentType="text/html;charset=UTF-8"?>
<div id="departmentdiv" hflex="true">
	<listbox id="lstDepartment" multiple="false" rows="5">
	    <auxhead>
	 	<auxheader label="Departments" colspan="4" />
	     </auxhead>
		<listhead>
			<listheader label="ID" width="150px" />
			<listheader label="Name" width="300px" />
		</listhead>
		<listitem>
			<listcell label="" />
			<listcell label="" />
		</listitem>
	   </listbox>
     	   <groupbox>
		<caption label="Department" />
		Name:
		<textbox id="txtDepartmentName" cols="25"
			value="" />
		<button id="btnAddDepartment" label="Add" width="36px"
			height="24px" />
		<button id="btnUpdateDepartment" label="Update" width="46px"
			height="24px" />
		<button id="btnDeleteDepartment" label="Delete" width="46px"
			height="24px" />
	</groupbox>
</div>

A Listagem 9 mostra um extrato de departments.zul sem ligação de dados, que será discutida na seção do controlador. A Listagem 9 não causar nenhuma confusão; os atributos ID, height, width e label são a linha de atributos da caixa de listagem que dita quantas linhas estão visíveis. O atributo multiple é um operador booleano para especificar se é necessário ou não selecionar diversos itens.

Com relação a componentes, uma caixa de listagem é usada para exibir uma variedade de itens em uma lista e tem suporte para a seleção de ditos itens. A caixa de grupo é usada para agrupar visualmente componentes de grupo e dar a eles um título (neste caso, é referido como legenda). Os únicos componentes que podem causar confusão são os seguintes:

  • Auxhead/Auxheader: O controle é usado para exibir um cabeçalho no alto da caixa de listagem. Isso pode abranger tantas colunas quantas forem necessários.
  • Listheader: O cabeçalho de listagem determina os cabeçalhos de cada coluna da caixa de listagem. Observe que há quatro colunas, assim, lista quatro elementos de cabeçalho.
  • Listcell: Cada célula de listagem contém as informações para cada coluna. O número de células de listagem precisa corresponder ao número de cabeçalhos de listagem.

A Figura 2 demonstra a saída renderizada da Listagem 9.

Figura 2. O departments.zul renderizado
O departments.zul renderizado

Como demonstrado, o ZK usa zul para fornecer aos desenvolvedores e designers uma sintaxe simples com base em XML similar àquela de HTML.

Descrição do arquivo Employee.zul

O Employees.zul é muito similar ao departments.zul, exceto por dois itens: o intbox e a caixa de listagem mostrados na Listagem 10. Se você olhar com atenção para a caixa de listagem, verá que tem um atributo chamado mold que é definido como select.

Um mold é uma maneira de representar um controle. Diferentes molds podem mudar radicalmente a aparência de um componente. Uma caixa de listagem pode ter dois molds chamados default e select. O departments.zul demonstrou o mold default, que tem aparência e comportamento semelhantes a uma caixa de listagem aparecendo no Windows ou no Linux. Entretanto, uma caixa de listagem no mold select tem aparência e comportamento semelhantes a uma caixa de combinação. Para mais informações, consulte a Referência de Componente do ZK .

Além disso, um observador atento também verá o componente intbox. Um intbox é similar a uma caixa de texto, porém, tem suporte apenas para números inteiros. Se a cadeia de caracteres for inserida, a validação da caixa falhará.

Lista 10. Employee.zul
	<?page title="new page title" contentType="text/html;charset=UTF-8"?>
	<div id="employeediv" hflex="true">
		<listbox id="lstEmployee" multiple="false" rows="5">
			<auxhead>
				<auxheader label="Employees" colspan="4" />
			</auxhead>
			<listhead>
			  <listheader label="ID" width="150px" />
			  <listheader label="First Name" width="300px" />
			  <listheader label="Last Name" width="300px" />
			  <listheader label="Age" width="150px" />
			</listhead>
			<listitem>
			  <listcell label="" /><listcell label="" /><listcell label="" />
			  <listcell label="" />
			</listitem>
		</listbox>
		<groupbox>
			<caption label="Employee" />
			First Name:<textbox id="txtFirstName" cols="25"
				value="" />
			Last Name:<textbox id="txtLastName" cols="25"
				value="" />
			Age:<intbox id="intAge" cols="1"
				value="" />
			Department:<listbox id="lstDepartment" mold="select" model="">
				<listitem />
			</listbox>
			<button id="btnAddEmployee" label="Add" width="36px"
				height="24px" />
			<button id="btnUpdateEmployee" label="Update" width="46px"
				height="24px" />
			<button id="btnDeleteEmployee" label="Delete" width="46px"
				height="24px" />
		</groupbox>
	</div>

A Figura 3 mostra o resultado renderizado de employees.zul como incluído na Listagem 10.

Figura 3. O employees.zul renderizado
O employees.zul renderizado

Tendo explorado ambos os arquivos separados, o tutorial agora volta para o main.zul para discutir como é possível incluir esses arquivos separados em outros arquivos zul.

Incluindo arquivos zul em outros arquivos zul

O ZK fornece um componente especial chamado include. O componente include é usado para incluir saída gerada por outro servlet. O servlet pode ser qualquer coisa, um JSF, JSP e mesmo outra página ZUML. No caso deste aplicativo, outra página zul precisa ser incluída. A sintaxe básica de um componente include é mostrada na Listagem 11.

Lista 11. Sintaxe de Include
	<include src="/module/departments.zul" />

Como demonstrado, o atributo src é usado para especificar o arquivo que se deseja incluir.

Há duas maneiras de incluir outro documento ZUML: lista e defer. Por padrão, é definido para automático, o que significa que o modo real é decidido automaticamente.

O modo automático (padrão) decide o modo com base na página que deve ser incluída. Se a página terminar com uma extensão zul ou zhtml, o modo list é assumido. Caso contrário, o modo defer é assumido.

No modo list , os componentes definidos na página incluída são instanciados instantaneamente e adicionados como filhos do componente include. No modo defer , o componente include inclui a página passando pelo contêiner do Servlet. Assim, não há problema em incluir nenhum tipo de página, e não está limitado a documentos ZUML.

O modo defer significa que uma instância da Página será criada no ZK. Quando uma solicitação do ZK é feita para renderizar uma nova página, uma nova página será criada e os componentes que são criados durante essa solicitação pertencerão a essa página. O autor usa a vantagem do aplicativo, uma vez que permite que tanto departments.zul quanto employee.zul funcionem como entidades completamente separadas de main.zul.

Para uso neste aplicativo, o modo include é definido para defer , como mostrado na Listagem 12.

Lista 12. Uso de defer
<include mode="defer" src="/module/departments.zul" />

Você irá beneficiar-se disso quando desejar recarregar os arquivos zul incluídos. Isso leva o tutorial naturalmente a falar sobre controladores, que é o que mantém o modelo e a visualização juntos.


Implementação do controlador

Esta seção fornece um guia passo a passo do controlador e suas funções. O controlador trata de toda a lógica de negócios do aplicativo e responde a eventos acionados a partir da interface com o usuário. Atualmente, o aplicativo de amostra inclui os eventos add, update e delete para employees e departments.

Definição de um controlador

Para criar um controlador, a classe org.zkoss.zk.ui.util.GenericForwardComposer deve ser estendida. Um exemplo de controlador é mostrado na Listagem 13.

Lista 13. Exemplo de controlador
public class MainController extends GenericForwardComposer {
	private static final long serialVersionUID = -3135206455666969851L;	
}

O criador então precisa estar associado com a visualização relevante. Anteriormente, o uso de apply foi abordado ligeiramente em Aninhamento de componentes do ZK. Na seção a seguir, o relacionamento é apresentado em mais detalhes.

Associação do controlador com a visualização

Para implementar a interação entre a visualização e o controlador, a ligação de dados é usada neste exemplo. Para implementar a ligação de dados, o atributo apply de um componente precisa ser definido. A maioria dos componentes tem suporte para o atributo apply.

A Listagem 14 demonstra o uso do atributo. O MainController é responsável por lidar com o fluo do usuário. Neste exemplo, foi decidido que a caixa de guias seria usada, e o usuário alternaria entre as guias department e employee. O código do MainController é demonstrado na Listagem 15.

Lista 14. Main.zul
<?page title="Welcome to the employee demo!" contentType="text/html;charset=UTF-8"?>
<window id="win"  title="Welcome to the employee demo!" border="normal" 
apply="org.zkforge.controllers.MainController">
	<tabbox hflex="true" id="tbTabs">
        <tabs>
            <tab label="Employees" />
            <tab label="Departments" />
        </tabs>
        <tabpanels>
        	<tabpanel>
        		<include mode="defer" src="/module/employees.zul" />
        	</tabpanel>
        	<tabpanel>
        		<include mode="defer" src="/module/departments.zul" />
        	</tabpanel>
        </tabpanels>
    </tabbox>
</window>

A Listagem 15 apresenta como capturar um evento e invalidar um componente.

Lista 15. MainController.java
public class MainController extends GenericForwardComposer {
	private static final long serialVersionUID = -3135206455666969851L;	
	Tabbox tbTabs;
	public void onSelect$tbTabs(ForwardEvent e) {
		Object o = e.getOrigin().getTarget();
		if (o instanceof Tab) {
			Tab t = (Tab)o;
			Tabpanel tp = t.getLinkedPanel();
			tp.invalidate();
		}
	}
}

Captura de eventos

A captura de evento no ZK é fácil de implementar e fornece aos desenvolvedores um grande poder. A Listagem 16 mostra uma assinatura da função para capturar o evento onSelect da caixa de guias tbTabs. O evento onSelect é acionado quando um usuário altera as guias.

A assinatura do método pode ser dividida em três partes. Em primeiro lugar, o tipo return é nulo e o método é público. O nome do método consiste no nome do evento, seguido por um sinal monetário ($) e pelo nome do componente cujo evento você deseja capturar. Por fim, neste caso, o tipo de evento é um ForwardEvent. Usando essa técnica, é possível capturar qualquer evento de qualquer componente ZK em um criador que esteja adequadamente conectado à visualização.

Lista 16. Assinatura da função para captura de evento
	public void onSelect$tbTabs(ForwardEvent e)

Por que invalidar um componente (recarregando um include)?

O tópico para o motivo para invalidar é relevante neste escopo do aplicativo. Entretanto, essa pergunta é baseada em outra mais significativa: Como compartilhar informações do banco de dados entre diferentes controles e garantir que sejam todos atualizados?

Uma das melhores maneiras de fazer isso é implementar uma lista compartilhada de itens de banco de dados entre todos os clientes concomitantes acessando os recursos. Essa implementação deve ser encadeada de maneira segura e pode ser facilmente realizada no ZK. Entretanto, para os fins deste tutorial, introduziria complicação desnecessária que poderia levar a confusão.

Portanto, foi tomada a decisão de manter departments e employees separados e recarregar os conteúdos de cada guia ao alternar. Assim, qualquer informação será recarregada pelo banco de dados.

Consequentemente, será preciso ter isso em mente ao revisar as decisões tomadas nesta seção.

Lista 17. Alternância de guias
	public void onSelect$tbTabs(ForwardEvent e) {
			Object o = e.getOrigin().getTarget();
			
			if (o instanceof Tab) {
				Tab t = (Tab)o;
				Tabpanel tp = t.getLinkedPanel();
				tp.invalidate();
			}
		}

A Listagem 17 mostra o código relevante do MainController. A primeira linha do método recupera o evento original e então recupera o alvo de um evento. Neste caso, é a Guia da caixa de guias.

O painel de guias da Guia então é recuperado. O painel de guias é a área em que os componentes são renderizados na caixa de guias, e cada Guia tem um painel de guias associados. Neste caso, o painel de guias então é validado.

É preciso lembrar que os conteúdos do painel de guias eram, na verdade, o componente include que inclui departments.zul e employee.zul, respectivamente. Além disso, o modo include de cada um foi definido para defer, o zul é solicitado novamente através do servlet, e os dados de cada um são recarregados.

Uso da ligação de dados para carregar dados do Informix

Para explicar totalmente a ligação de dados, apenas um dos dois arquivos zul, departments.zul ou employee.zul, é relevante. Para este tutorial, employee.zul será discutido por ser mais o complexo dos dois.

A visualização está vinculada ao controlador usando o atributo apply como discutido em Associação do controlador com a visualização. Agora o mecanismo de ligação de dados do ZK precisa ser ativado para esta página. Lembre, por o modo include estar adiado, cada zul é considerado uma entidade separada. Isso significa que eles podem ter cada um a própria instância de ligação de dados. Para inicializar o componente de ligação de dados Annotated, use a linha mostrada na Listagem 18.

Lista 18. Inicialização do componente de ligação de dados
<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" root="./departmentdiv"?>

Funcionalidades Employee.zul e EmployeeController.java, passo a passo

Para facilitar a explicação de como a ligação de dados funciona, a Listagem 19 contém a origem completa de employees.zul. Este tutorial agora passará por cada parte relevante e incluirá, quando necessário, as partes relevantes do controlador aplicado.

Lista 19. código completo de employees.zul
<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" root="./employeediv"?>
<div id="employeediv" apply="org.zkforge.controllers.EmployeeController"
	hflex="true">
	<listbox id="lstEmployee" multiple="false" rows="5"
		model="@{employeediv$composer.getAllEmployees, 
        load-after='btnAddEmployee.onClick, 
        btnDeleteEmployee.onClick, btnUpdateEmployee.onClick'}"
		selectedItem="@{employeediv$composer.currentEmployee}">
		<auxhead>
			<auxheader label="Employees" colspan="4" />
		</auxhead>
		<listhead>
			<listheader label="ID" width="150px" />
			<listheader label="First Name" width="300px" />
			<listheader label="Last Name" width="300px" />
			<listheader label="Age" width="150px" />
		</listhead>
		<listitem self="@{each='employee'}" value="@{employee}">
			<listcell label="@{employee.id}" />
			<listcell label="@{employee.firstName}" />
			<listcell label="@{employee.lastName}" />
			<listcell label="@{employee.age}" />
		</listitem>
	</listbox>
	<groupbox>
		<caption label="Employee" />
		First Name:
		<textbox id="txtFirstName" cols="25"
			value="@{employeediv$composer.currentEmployee.firstName}" />
		Last Name:
		<textbox id="txtLastName" cols="25"
			value="@{employeediv$composer.currentEmployee.lastName}" />
		Age:
		<intbox id="intAge" cols="1"
			value="@{employeediv$composer.currentEmployee.age}" />
		Department:
		<listbox id="lstDepartment" mold="select"
			model="@{employeediv$composer.getAllDepartments}"
			selectedItem="@{employeediv$composer.currentEmployee.department}">
			<listitem self="@{each='department'}"
				label="@{department.name}" />
		</listbox>
		<button id="btnAddEmployee" label="Add" width="36px"
			height="24px" />
		<button id="btnUpdateEmployee" label="Update" width="46px"
			height="24px" />
		<button id="btnDeleteEmployee" label="Delete" width="46px"
			height="24px" />
	</groupbox>
</div>

Inicialização da ligação de dados em employees

A inicialização da ligação de dados é a primeira linha que é necessária. Entretanto, há uma diferença entre a linha demonstrada na Listagem 18 e a linha mostrada na Listagem 19. Observe a adição de um atributo extra chamado root. Este atributo root pega um nome de componente e determina que o componente de ligação de dados é inicializado apenas para esse componente e seus filhos. Assim, nesta situação, o componente root do componente de ligação de dados anotado é o componente div com o id de departmentdiv. A Listagem 20 demonstra a linha relevante.

Lista 20. Inicialização do componente de ligação de dados
<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" root="./departmentdiv"?>

Carregamento dos dados do controlador

É hora de começar a preencher os dados. Isso é feito ligando as funções do controlador t para recuperar os dados do modelo com nossa caixa de listagem. A caixa de listagem completa zul é descrita na Listagem 21.

Lista 21. A caixa de listagem com a ligação de dados
<listbox id="lstEmployee" multiple="false" rows="5"
model="@{employeediv$composer.getAllEmployees, load-after='btnAddEmployee.onClick, 
    btnDeleteEmployee.onClick, btnUpdateEmployee.onClick'}"
		selectedItem="@{employeediv$composer.currentEmployee}">
		<auxhead>
			<auxheader label="Employees" colspan="4" />
		</auxhead>
		<listhead>
			<listheader label="ID" width="150px" />
			<listheader label="First Name" width="300px" />
			<listheader label="Last Name" width="300px" />
			<listheader label="Age" width="150px" />
		</listhead>
		<listitem self="@{each='employee'}" value="@{employee}">
			<listcell label="@{employee.id}" />
			<listcell label="@{employee.firstName}" />
			<listcell label="@{employee.lastName}" />
			<listcell label="@{employee.age}" />
		</listitem>
	</listbox>

O código de origem do controlador em model="@{employeediv$composer.getAllEmployees}" e selectedItem="@{employeediv$composer.currentEmployee}" retornou uma lista do tipo Employee, e um bean do tipo Employee, respectivamente. O fragmento de código para isso é mostrado na Listagem 22.

Lista 22. EmployeeController source snippet - getAllEmployees and CurrentEmployee
public List<Employee> getAllEmployees() {
		try {
			return _empDAO.getAll();
		} catch (SQLException e) {
			UiUtils.showMessage(e.getMessage());
			log.error(e);
		}
		
		return null;
	}

public Employee getCurrentEmployee() {
		return _currentEmployee;
	}

public void setCurrentEmployee(Employee e) {
		this._currentEmployee = e;
	}

O método do controlador que é responsável por recuperar todos os dados de funcionário é chamado getAllEmployees(). Esse método pode ser acessado na visualização configurando o atributo de modelo da caixa de listagem para e mployeediv$composer.getAllEmployees, como mostrado na Listagem 23.

Lista 23. Ligação para getAllEmployees
model="@{employeediv$composer.getAllEmployees}”

A expressão de ligação de dados pode ser dividida. Observe que a expressão iniciando com employeediv, que é o nome do componente raiz, também contém o atributo apply. É, então seguida por um sinal monetário e criador.

Quando o ZK avalia isso, significa que está procurando por componentes com o id employeediv e recuperando seu criado.

Um ponto (.) então é anexado e seguido pelo nome da função que deve ser acessada. Isso atribuirá o modelo ao resultado da função getAllEmployees no controlador.

Em segundo lugar, a linha mostrada na Listagem 24 usa o mesmo mecanismo para recuperar a referência para o criador de employeediv. Então é seguida por currentEmployee.

Lista 24. Ligação de dados do item selecionado
	selectedItem="@{employeediv$composer.currentEmployee}"

Também é preciso observar que a Listagem 24 apresenta uma função e um bean chamado currentEmployee. Isso demonstra que os dados que ligam a sintaxe para acessar beans e funções diferem. Isso é apresentado na Tabela 3.

Tablela 3. Acesso do componente de ligação de dados ao controlador
Identificador de acessoDescrição
fullFunctionNamePara acessar uma função no controlador através da ligação de dados, é necessário usar o nome completo da função.
beanNameAo acessar um bean a partir do controlador, é necessário apenas usar o nome do bean. Não há necessidade de incluir get ou set. Entretanto, o bean em questão deve ter ambos.

O atributo selectedItem é definido para controlar qual bean é selecionado na caixa de listagem. Quando a seleção é alterada, o ZK automaticamente atualizará o bean de acordo.

Exibição dos dados

Para exibir os dados dentro de uma caixa de listagem, é preciso um modelo. Criando um modelo, como o descrito na Listagem 25, a caixa de listagem pode representar com eficiência os dados.

Lista 25. Modelo de exibição da caixa de listagem
<listhead>
	<listheader label="ID" width="150px" />
	<listheader label="First Name" width="300px" />
	<listheader label="Last Name" width="300px" />
	<listheader label="Age" width="150px" />
</listhead>
<listitem self="@{each='employee'}" value="@{employee}">
	<listcell label="@{employee.id}" />
	<listcell label="@{employee.firstName}" />
	<listcell label="@{employee.lastName}" />
	<listcell label="@{employee.age}" />
</listitem>

Os dados são ligados e renderizados dentro da caixa de listagem. Isso é alcançado utilizando o autoatributo do item de listagem para atribuir variáveis que representariam, cada uma, um funcionário. O componente de ligação de dados então será colocado em loop através de cada employee e produzirá o código do modelo mostrado na Listagem 25. Cada célula de listagem, portanto, será ligada ao respectivo bean e seus mutantes.

Uma metodologia similar é aplicada aos componentes na caixa de grupo que representa o item selecionado. Cada um deles é ligado aos dados específicos do bean currentEmployee usando as técnicas discutidas ao longo desta seção. Portanto, conforme o currentEmployee muda ao selecionar um employee diferente na caixa de listagem, as caixas de texto relevantes também são atualizadas. Ainda, observe que há uma caixa de listagem no mold select que segue as mesmas convenções discutidas em Employee.zul. Essas técnicas aplicam-se em todo o ZK.

O extrato relevante é mostrado na Listagem 26.

Lista 26. Extrato mostrando as informações currentEmployee
First Name: <textbox id="txtFirstName" cols="25"
		value="@{employeediv$composer.currentEmployee.firstName}" />
Last Name: <textbox id="txtLastName" cols="25"
			value="@{employeediv$composer.currentEmployee.lastName}" />
Age: <intbox id="intAge" cols="1"
			value="@{employeediv$composer.currentEmployee.age}" />
Department: <listbox id="lstDepartment" mold="select"
			model="@{employeediv$composer.getAllDepartments}" 
            selectedItem="@{employeediv$composer.currentEmployee.department}">

Você carregou e produziu os dados, então é hora de começar a manipulá-los.

Operações CRUD na UI

Até agora, os dados foram carregados e exibidos, mas o objetivo dos aplicativos da Web é a manipulação de dados. Assim, os métodos add, create, update e delete precisam ser criados. Isso é feito usando os três botões mostrados na Listagem 27.

Lista 27. Botões CRUD
<button id="btnAddEmployee" label="Add" width="36px"
			height="24px" />
		<button id="btnUpdateEmployee" label="Update" width="46px"
			height="24px" />
		<button id="btnDeleteEmployee" label="Delete" width="46px"
			height="24px" />

Esses botões estão vinculados a funções no controlador que captura os eventos. As funções são mostradas na Listagem 28.

Lista 28. Eventos de clique do controlador
//click events
	public void onClick$btnAddEmployee() {
		if(lstDepartment.getSelectedItem() != null) {
			String firstName = txtFirstName.getText();
			String lastName = txtLastName.getText();
			Department dep = null;
			int iAge = Integer.parseInt(intAge.getText());
			
			Selectable selectable = (Selectable)lstDepartment.getModel();
			Set<?> selectedSet = selectable.getSelection();
			
			if (selectedSet.size() == 1) {
				dep = (Department)selectedSet.toArray()[0];
			}
			
			Employee employee = new Employee(firstName + lastName + 
            UUID.randomUUID(), //id
									  firstName,
									  lastName,
									  iAge,
									  dep);
			
			try {
				_empDAO.insert(employee);
			} catch (SQLException e) {
				UiUtils.showMessage(e.getMessage());
				log.error(e);
			}
		}
		else {
			UiUtils.showMessage("Please select a department!");
		}
			 
	}
	
	public void onClick$btnUpdateEmployee() {
		if((lstDepartment.getSelectedItem() != null)
			&& (lstEmployee.getSelectedItem() != null)) {
			
			Employee employee = 
              (Employee)(lstEmployee.getSelectedItem().getValue());
			
			try {
				_empDAO.update(employee);
			} catch (SQLException e) {
				UiUtils.showMessage(e.getMessage());
				log.error(e);
			}
		}
		else {
			UiUtils.showMessage("Please select an employee and department!");
		} 
	}
	
	public void onClick$btnDeleteEmployee() {
		
		if(lstEmployee.getSelectedItem() != null) {
			Employee employee = 
              (Employee)(lstEmployee.getSelectedItem().getValue());
			
			try {
				_empDAO.delete(employee);
			} catch (SQLException e) {
				UiUtils.showMessage(e.getMessage());
				log.error(e);
			}
		}
		else {
			UiUtils.showMessage("Please select an employee!");
		}
			 
	}

A Listagem 28 realça a lógica de negócios por trás das operações CRUD. A maioria é autoexplicativa e são chamadas Java básicas. Um item que você pode observar é que o cada componente é referido diretamente a partir do código.

Para ativar essa função, é preciso apenas especificar o tipo de componente e seu id no controlador e o ZK farão resto através de conexão automática. Por exemplo, a Listagem 29 mostra que as declarações são suficientes para tornar o acesso aos componentes possível a partir da Listagem 28.

Lista 29. Declarações do componente
Listbox lstEmployee;
	Listbox lstDepartment;
	
	//text boxes
	Textbox txtFirstName;
	Textbox txtLastName;
	
	//int boxes
	Intbox intAge;

O último ponto de discussão é como o ZK saberia atualizar o modelo de caixa de listagem após atualizar, adicionar ou excluir um item. Isso é uma simples questão de atribuir load-after no atributo de modelo na caixa de listagem para os eventos de botão relevantes que atualizam o modelo. Quando um desses eventos é acionado, o modelo será recarregado. A Listagem 30 demonstra o código necessário para isso. Dividi-lo é tão simples quanto especificar o id do componente seguido por um ponto (.), e o nome do evento.

Lista 30. Load-after
model="@{employeediv$composer.getAllEmployees, 
load-after='btnAddEmployee.onClick, btnDeleteEmployee.onClick, 
btnUpdateEmployee.onClick'}"

Criação do banco de dados e execução do aplicativo de amostra

Criação de um banco de dados de funcionário

A premissa do aplicativo é criar um aplicativo básico do departamento pessoal. O aplicativo conterá dois objetos principais chamados employees (funcionários) e departments (departamentos). Cada funcionário deve pertencer a apenas um department, mas um departamento pode ter muitos funcionários.

Para tornar mais fácil desenvolver o banco de dados, o SQL é fornecido na Listagem 31.

Lista 31. SQL descrevendo o banco de dados e tabelas necessários
create database employeedb;
	create table departments(
		id varchar(50),
		name varchar(50),
		primary key (id) );
									 
	create table employees(
		id varchar(50),
		firstname varchar(50),
		lastname varchar(50),
		age integer,
		departmentid varchar(50),
		primary key (id),
		foreign key (departmentid) references departments(id));

Execução do aplicativo de amostra

O exemplo de aplicativo está disponível na seção Download deste tutorial. Faça o download do arquivo e extraia-o para a pasta de sua escolha.

Execução do aplicativo de amostra sem um IDE

Para executar o aplicativo de amostra sem usar um IDE (Eclipse), realize os seguintes procedimentos.

  1. Copiar zkinformix.war para $TOMCAT_HOME\webapps.
  2. Iniciar o Apache Tomcat
  3. Navegar para http://localhost:8080/zkinformix

Execução do aplicativo de amostra com um IDE

Para executar o aplicativo de amostra usando um IDE (eclipse), realize os seguintes procedimentos.

  1. Copie o driver Informix (ifxjdbc.jar) para $TOMCAT_HOME\common\lib.
  2. Inicie o Eclipse.
  3. Clique em File > Import.
  4. No diálogo, selecione arquivo Web > WAR e, em seguida, clique em Next.
  5. Use o botão buscar para localizar zkinformix.war.
  6. Clique em Finish para importar o projeto da Web.
  7. Clique com o botão direito em zkinformix no explorador de projetos e selecione Run As > Run on Server.
  8. Selecione Apache > Tomcat v6.0 Server no diálogo de tipo de servidor e clique em Finish.
  9. Um navegador será iniciado automaticamente mostrando o exemplo zkinformix.

Conclusão

Este tutorial apresentou os conceitos fundamentais e melhores práticas para usar o ZK com o Informix. Pode haver muitos tópicos aprofundados que possam ser abordados em outro tutorial. No final deste tutorial, você deve ter obtido um bom entendimento de como o ZK funciona, e quão fácil é fazer interface com o Informix para criar um aplicativo da Web com recursos avançados.


Download

DescriçãoNomeTamanho
Example code for this tutorialZK-Informix-Article-src.zip10KB

Recursos

Aprender

Obter produtos e tecnologias

Discutir

Comentários

developerWorks: Conecte-se

Los campos obligatorios están marcados con un asterisco (*).


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


A primeira vez que você entrar no developerWorks, um perfil é criado para você. Informações no seu perfil (seu nome, país / região, e nome da empresa) é apresentado ao público e vai acompanhar qualquer conteúdo que você postar, a menos que você opte por esconder o nome da empresa. Você pode atualizar sua conta IBM a qualquer momento.

Todas as informações enviadas são seguras.

Elija su nombre para mostrar



Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Los campos obligatorios están marcados con un asterisco (*).

(Escolha um nome de exibição de 3 - 31 caracteres.)

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


Todas as informações enviadas são seguras.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Information Management, Software livre, Tecnologia Java
ArticleID=755435
ArticleTitle=Integre a estrutura de aplicativo da Internet avançada ZK com o Informix para criar aplicativos do mundo real
publish-date=09062011