O jQuery popularizou o uso de seletores na sintaxe de folha de estilo em
cascata (CSS)
para recuperar elementos do Modelo de Objeto de
Documento (DOM), e para aplicar operações a esses elementos. Um dos
muitos benefícios de usar o jQuery é que não há mais a dificuldade de
percorrer árvores DOM complicadas usando JavaScript.
O ZK é uma estrutura Ajax voltada a eventos, baseada em componentes,
conhecida por sua programação Java e integração com tecnologias Java
EE. Ele traz a experiência de programação do desktop para o Ajax.
Para
os apreciadores de HTML, a UI do ZK pode ser reunida usando marcação e
uma linguagem de expressões.
Neste artigo, explore como a união do código Java no
lado do servidor com o jQuery pode ajudar você a enfrentar os desafios
do desenvolvimento de aplicativos Ajax corporativos.
O jQuery e o ZK
juntos podem integrar tecnologias para ajudar você a entregar
experiências de UI ricas e responsivas com maior facilidade e
eficiência. Faça o Download do código de amostra usado neste artigo.
jQuery. Uma biblioteca JavaScript rápida, concisa, de
navegador cruzado que torna fácil construir aplicativos da Web e páginas
da Web. O jQuery simplifica: a criação de animação, de comunicações a
solicitações do servidor, exame de documento e manipulação de eventos.
Desafios do desenvolvimento de aplicativos Ajax
Seguem alguns desafios típicos enfrentados por desenvolvedores de aplicativos Ajax de nível empresarial.
Complexidades
O Ajax é complexo. Com o padrão de comunicação do Ajax, uma página da Web não necessita ser atualizada em sua totalidade uma vez que elementos no DOM podem ser atualizados individualmente. Em um aplicativo corporativo, delegar sofisticadas lógicas de negócios do servidor para o cliente e cuidar de cada chamada Ajax manualmente é um esforço vigoroso.
Programação no lado do servidor
Soluções Ajax no lado do servidor não são capazes de alavancar os recursos no cliente para construir uma experiência de usuário mais responsiva, funções off-line ou computação distribuída e armazenamento de dados no cliente. Estas soluções não reduzem a área de cobertura da memória no servidor e, consequentemente, aumentam a escalabilidade do aplicativo.
Programação no lado do cliente
A programação no lado do cliente apresenta mais preocupações com
segurança e custos de desenvolvimento. Lógica de negócios e dados
sensíveis são deixados expostos nos navegadores, tornando aplicativos
vulneráveis a ataques. A Programação no lado do cliente envolve extensa
implementação JavaScript, o que se tornaria um desafio se você estivesse
acostumado com o desenvolvimento de aplicativos com a tecnologia Java
EE.
Dados imensos
Outro problema comum surge quando a camada UI deve apresentar muitos
dados em uma visualização. Por exemplo, considere uma tabela HTML
regular. Quando a origem de dados se torna grande, é possível:
- Arriscar sobrecarregar o cache do navegador,
deixando o tráfego mais lento devido ao pré-carregamento do grande
conjunto de dados - Implementar manualmente um mecanismo no
servidor para fazer um subconjunto de dados de interesse disponível na
visualização sempre que um usuário fizesse essa solicitação.
Para eliminar esses obstáculos, uma solução viável é usar uma estrutura
em que o estado do cliente e do servidor permaneçam em sincronia
automaticamente.
Você pode alavancar toda tecnologia segura do Java EE
no lado do servidor, ao mesmo tempo que usa computação no lado do
cliente para responsividade e controle de UI.
A arquitetura de fusão servidor + cliente do ZK
A arquitetura inovadora do ZK fornece os meios para maximizar
completamente todas as tecnologias disponíveis tanto no lado do servidor
quanto do cliente. Você pode acessar os widgets do lado do cliente
diretamente se quiser. Esta seção esclarece alguns dos benefícios da
arquitetura de fusão servidor + cliente do ZK.
Loader e mecanismo AU do ZK
O Loader ZK entrega uma solicitação URL:
- Criando os componentes UI nas páginas desejadas
- Carregando os dados necessários nos componentes
- Renderizando-os dentro de uma página HTML
- Enviando-os de volta ao cliente, juntamente com o mecanismo de cliente do ZK
O mecanismo ZK de Asynchronous Update (AU) e o
Mecanismo de Cliente controlam as comunicações Ajax, protegendo você da
complexidade de manipulação das chamadas Ajax. A figura 1 mostra o
Loader ZK, o mecanismo AU do ZK e o Mecanismo de Cliente do ZK.
Figura 1. Visão geral da arquitetura de fusão ZK
Solucionando as complexidades do Ajax
Os mecanismos de Cliente e AU desempenham o papel de lançador e coletor,
e um canal com a fila de eventos a ser processada. O resultado é uma
manipulação de evento assíncrona e simplificada para as preferências da
programação desktop.
Alavancando tecnologias no lado do servidor
Devido ao servidor manter um conjunto de componentes ZK em JVM
correspondentes ao conjunto de widgets do ZK residentes no navegador
como objetos JavaScript, o estado da página é mantido em sincronia em
ambos os lados.
Qualquer manipulação de eventos que lide com lógica de
negócios ou dados sensíveis é mantida no lado do servidor. As alterações
de estados resultantes nos componentes ZK no servidor são refletidas de
volta aos widgets ZK no lado do cliente quando o processamento do
evento estiver completo. Nenhuma lógica de negócios é exposta no lado do
cliente.
Alavancando tecnologias no lado do Cliente
Widgets ZK são objetos JavaScript do lado do Cliente escritos com
jQuery, então eles possuem os mesmos procedimentos do jQuery. Já que
existe em ambos, cliente e servidor, uma completa representação de
componentes e seus estados, você tem a opção de programar no cliente ou
servidor. A figura 2 mostra um exemplo.
Figura 2. Tecnologia ZK no Lado do Cliente
Manipulando grandes quantidades de dados
Às vezes você precisa resolver a questão de manipulação de grandes
quantidades de dados no lado do cliente. Os componentes grade, caixa de
listagem e árvore do ZK, usados para exibir registros de dados, tem um
recurso de carregamento sob demanda para que os dados não sejam
renderizados no navegador até que sejam necessários em uma visualização.
Há também um recurso de paginação com o qual grandes quantidades de
dados podem ser distribuídas em múltiplas páginas. Com estes recursos, a
complexidade de exibir quantidades imensas de dados é reduzida
significativamente.
Soluções usando ZK
Para explorar a arquitetura de fusão servidor + cliente do ZK, você
vai analisar uma amostra de aplicativo de visualização de estoque de
prova de conceito, de duas formas diferentes: usando uma solução
puramente voltada ao servidor como referência, e distribuindo a
manipulação de eventos entre servidor e cliente.
O aplicativo de visualização de estoque irá ler um
registro histórico de estoque em XML, e exibirá os dados em formato
tubular e um gráfico de linha. O aplicativo também incluirá uma caixa de
procura que autocompleta uma procura, tal como o Google Suggest. A
figura 3 mostra o aplicativo.
Figura 3. Aplicativo de visualização de estoque
Solução no lado do servidor usando MVC ZK
Para a abordagem voltada ao servidor, a amostra adapta a abordagem model view controller (MVC) do ZK.
Modelo
O modelo é composto por três classes Java, dois objetos de Dados e um objeto DAO. Um objeto Estoque pode corresponder a muitos Preços.
public class Stock {
private int _id;
private String _name;
private List<Price> _priceItems = new ArrayList<Price>();
....
//métodos getter e setter
}
public class Price {
private String _date;
private double _open;
private double _high;
private double _low;
private double _close;
private int _volumn;
....
//métodos getter e setter
}
A classe StockDAO analisa os dados históricos do estoque em data.xml e cria os objetos Estoque e Preço na memória. Cada objeto Estoque é incluído na lista vinculada “stocks”.
public class StockDAO {
private List<Stock> stocks = new LinkedList<Stock>();
public List findAll() {...} // returns all stock items in data.xml
public Stock getStock(int id) {...}
}
Visualização
A visualização é implementada usando a linguagem de marcações do ZK. A página de apresentação principal, index.zul, é particionada usando layout de borda.
A divisão do lado esquerdo abriga a caixa de procura e a lista de nomes do estoque, e a divisão central contém o elemento incluir que serve como marcador para price.zul. O registro de dados para cada estoque é exibido no componente grade e exibido no componente gráfico em price.zul. Na listagem index.zul exibida na listagem 1:
- Na linha 1, a tag init diz ao Loader do ZK para
inicializar o Gerenciador de ligação de dados do ZK de forma que uma
fonte de dados possa ser ligada automaticamente a componentes da UI, e
vice-versa. - Na linha 2, apply=”StockController” denota que a classe
StockController do pacote padrão servirá como controlador do componente borderlayout. - Na linha 12, model=”@{main$composer.stocks}” converte para definir a listbox com o modelo de dados obtido da classe StockController ‘ getStocks().
- Da linha 14 à 16, um componente listitem é criado para cada objeto de estoque e seu nome é atribuído ao rótulo da listcell.
Listagem 1. index.zul
1. <?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit"?>
2. <borderlayout id="main" apply="StockController">
3. <west title="ZK Finance" size="250px" flex="true"
4. splittable="true" minsize="210" maxsize="500" collapsible="true">
5. <panel>
6. <toolbar>
7. <label value="Search:" />
8. <textbox id="searchBox" ctrlKeys="#down#up"
9. focus="true" sclass="demo-search-inp" />
10. </toolbar>
11. <panelchildren>
12. <listbox id="itemList" model="@{main$composer.stocks}"
13. fixedLayout="true" vflex="true">
14. <listitem self="@{each='stock'}" value="@{stock}">
15. <listcell label="@{stock.name}" />
16. </listitem>
17. </listbox>
18. </panelchildren>
19. </panel>
20. </west>
21. <center>
22. <include id="detail"/>
23. </center>
24. </borderlayout>
Na listagem price.zul exibida na listagem 2:
- Na linha 1, como antes, o Gerenciador de ligação de dados do ZK é inicializado.
- Na linha 2, apply=”PriceController” denota que a classe PriceController do pacote padrão servirá como o controlador de componente de janela.
- Na linha 3, model=”@{main2$PriceController.prices}” converte para definir a grade com o modelo de dados obtido da classe PriceController
‘ getPrices(). - Da linha 13 à 20, um componente de linha é criado para cada objeto preço e seu valor é atribuído a um rótulo.
Listagem 2. price.zul
1. <?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit"?>
2. <window id="main2" apply="PriceController">
3. <grid id="history" model="@{main2$PriceController.prices}" >
4. <columns menupopup="auto">
5. <column label="Date" />
6. <column label="Open" />
7. <column label="High" />
8. <column label="Low" />
9. <column label="Close" />
10. <column label="Volumn" />
11. </columns>
12. <rows>
13. <row self="@{each='price'}">
14. <label value="@{price.date}"/>
15. <label value="@{price.open}"/>
16. <label value="@{price.high}"/>
17. <label value="@{price.low}"/>
18. <label value="@{price.close}"/>
19. <label value="@{price.volumn}"/>
20. </row>
21. </rows>
22. </grid>
23. <chart id="line" width="500" height="250" type="line"
24. fgAlpha="128" model="@{main2$PriceController.cateModel}"/>
25. </window>
Controlador
Os controladores são classes que possuem as mesmas características de rg.zkoss.zk.ui.util.GenericForwardComposer do ZK, que liga automaticamente os objetos de dados com os componentes da UI. Na classe StockController que controla a visualização no componente borderlayout no index.zul:
- Na linha 8, o borderlayout com id=main é registrado com um listener de eventos onCreate que define o item de estoque padrão a ser exibido na visualização.
- Na linha 13, a caixa de listagem com id=itemList é registrada com um listener de eventos onSelect que obtém o listitem selecionado na listbox e define o componente include com id=detail? como a página de origem para exibição dos dados de estoque e plot de linha.
- Na linha 18, a caixa de texto com id=searchBox é registrada com um listener de eventos onChanging
que itera através dos itens de estoque e retorna uma lista de estoques
correspondente a entrada do usuário a cada vez que o valor da caixa de
texto é alterado. O evento no argumento é convertido para org.zkoss.zk.ui.event.InputEvent de forma que a entrada do usuário possa ser atribuída à cadeia de caracteres key. - Na linha 34, o método getStocks() retorna todos os itens de estoque listados no data.xml.
Listagem 3. StockController.java
1. public class StockController extends GenericForwardComposer {
2. Textbox searchBox;
3. Listbox itemList;
4. Include detail;
5. StockDAO dao = new StockDAO();
6. private static String DETAIL_URL = "price.zul";
7.
8. public void onCreate$main(){
9. itemList.setSelectedIndex(0);
10. Events.postEvent(new Event(Events.ON_SELECT, itemList));
11. }
12.
13. public void onSelect$itemList(){
14. int id = ((Stock)itemList.getSelectedItem().getValue()).getId();
15. detail.setSrc(DETAIL_URL + "?id=" + id);
16. }
17.
18. public void onChanging$searchBox(InputEvent event) {
19. String key = event.getValue();
20. LinkedList item = new LinkedList();
21. List items = dao.findAll();
22.
23. if (key.trim().length() != 0) {
24. for (Iterator iterator = items.iterator(); iterator.hasNext();) {
25. Stock st = (Stock) iterator.next();
26. if (st.getName().toLowerCase()
27. .indexOf(key.toLowerCase()) != -1)
28. item.add(st);
29. }
30. itemList.setModel(new ListModelList(item));
31. } else itemList.setModel(new ListModelList(items));
32. }
33.
34. public List getStocks(){
35. return dao.findAll();
36. }
37. }
Na classe PriceController que controla a visualização nos componentes grade e gráfico no price.zul:
- Na linha 14, o parâmetro id anexado à solicitação para o price.zul é buscado. A classe
org.zkoss.zk.ui.Executions é um wrapper para uma solicitação não Ajax. - Na linha 21, os valores para o modelo de gráfico de linhas são definidos.
- Na linha 25, o método getPrices() é declarado para que possa ser chamado pelo EL no componente grade no price.zul. Isso funciona, pois a classe PriceController possui as mesmas características de org.zkoss.zk.ui.util.GenericAutowireComposer, que liga os componentes da UI com os objetos de dados.
Listagem 4. PriceController
1. public class PriceController extends GenericAutowireComposer {
2.
3. private StockDAO dao = new StockDAO();
4. private CategoryModel cateModel;
5. private List items;
6.
7. public PriceController() {
8. init();
9. }
10.
11. public void init() {
12. //get stock id
13. int id = Integer.parseInt((String)
14. Executions.getCurrent().getParameter("id"));
15. Stock stock = dao.getStock(id);
16. items = stock.getPriceItems();
17. //create category model for chart
18. cateModel = new SimpleCategoryModel();
19. for (Iterator iterator = items.iterator(); iterator.hasNext();) {
20. Price price = (Price) iterator.next();
21. cateModel.setValue(stock.getName(), price.getDate(),
22. Price.getClose());
23. }
24. }
25. public List getPrices(){
26. return items;
27. }
28. public CategoryModel getCateModel() {
29. return cateModel;
30. }
31. }
Através desse exemplo, as chamadas assíncronas necessárias para alcançar
a função de caixa de procura, e a atualização de dados dinâmica na
tabela e no gráfico, são tratadas inteiramente pelo Mecanismo de Cliente
do ZK e Mecanismo AU. Instruções são executadas no servidor. O cliente
apenas recebe as atualizações nos componentes UI e no modelo de dados.
Solução de fusão Servidor + cliente
Vamos observar o mesmo aplicativo com a metodologia de fusão servidor +
cliente. O candidato óbvio para implementação no lado do cliente é a
caixa de procura, em que a responsividade é prioritária e apenas os
nomes dos itens de estoque, não seus dados, precisam ser analisados e
exibidos.
Neste caso, a classe StockController não é mais
necessária, pois a manipulação de eventos na caixa de procura será
implementada somente no cliente. O exemplo modifica o index.zul e o
renomeia para hybrid.zul.
Na listagem hybrid.zul abaixo, observe as seguintes construções do ZK:
- O namespace do cliente ZK deve ser declarado: <zk
xmlns:w=”http://www.zkoss.org/2005/zk/client”> (O namespace w, de widgets, é uma convenção do ZK) - Na linha 2, o atributo apply=”StockController” é retirado do
borderlayout porque a caixa de procura e a caixa de listagem que mostram os nomes do estoque serão atualizadas diretamente no cliente. - Na linha 8, o evento onChanging do textbox agora é declarado para ser tratado no cliente com a anotação w:
- Na linha 9, obtém-se a listbox e o seu método update() definido pelo usuário, é chamado. A expressão this.$f(‘list’) é equivalente a
inp.getFellow(“list”) em Java, que obtém o componente listbox com id=”list”. - Na linha 13, o método bind_ callback da classe zk.Widget é substituído para executar o método update() e configurar o primeiro item da lista como o selecionado depois que alistbox é ligada à árvore DOM.
- Na linha 28, zUtl.parseXML() é um método utilitário para análise de documentos XML. jq() é feita a notação para o seletor jQuery no ZK de modo que a notação do jQuery $() pode ainda ser usada sempre que aplicável.
- Na linha 38, um novo widget listitem é criado com seu valor de rótulo e ID definido para cada item de estoque e é anexado à listbox como seus widgets filhos.
- Da linha 56 à 70, o evento onSelect da listbox é tratado diretamente pela implementação de um método de serviço para a solicitação assíncrona no servidor.
O exemplo recupera o uuid para a listitem que está sendo selecionada e anexa à solicitação para a página price.zul, que exibe os dados de estoque e o gráfico de linha.
Listagem 5. hybrid.zul
1. <zk xmlns:w="http://www.zkoss.org/2005/zk/client">
2. <borderlayout id="main">
3. <west title="ZK Finance" size="250px" flex="true"
4. splittable="true" minsize="210" maxsize="500" collapsible="true">
5. <panel>
6. <panelchildren>
7. <textbox id="inp">
8. <attribute w:name="onChanging">
9. this.$f('list').update(event.data.value);
10. </attribute>
11. </textbox>
12. <listbox id="list" onSelect="" rows="10" width="300px">
13. <attribute w:name="bind_">
14. function (desktop, skipper, after) {
15. this.$bind_.apply(this, arguments);
16. var self = this;
17. after.push(function () {
18. self.update();
19. self.firstChild.setSelected(true);
20. });
21. }
22. </attribute>
23. <attribute w:name="update"><![CDATA[
24.
25. (function () {
26. var data;
27. function loadData(w) {
28. var xmlDoc = zk.xml.Utl.parseXML(jq(w).html().replace(/<!--|-->/g,'').trim()),
29. ids = xmlDoc.getElementsByTagName("id"),
30. labels = xmlDoc.getElementsByTagName("name");
31. data = [];
32. jq(ids).each(function (i) {
33. data.push({id: this.firstChild.nodeValue, label:
34. labels[i].firstChild.nodeValue});
35. });
36. }
37.
38. function createItems (listbox, data) {
39. if (!data.length) return;
40. jq(data).each(function () {
41. listbox.appendChild(new zul.sel.Listitem({label: this.label, uuid: this.id}));
42. });
43. }
44. return function (txt) {
45. txt = txt || '';
46. if (!data) loadData(this.$f('data'));
47. this.clear();
48. createItems(this, jq.grep(data, function (item) {
49. return item.label.toLowerCase().indexOf(txt.toLowerCase()) != -1;
50. }));
51. this.stripe();
52. };
53. })()
54. ]]></attribute>
55. </listbox>
56. <zscript>
57. public class MyService implements org.zkoss.zk.au.AuService {
58. public boolean service(org.zkoss.zk.au.AuRequest request, boolean everError) {
59. final String cmd = request.getCommand();
60. if (cmd.equals(Events.ON_SELECT)) {
61. String uuid = ((List)request.getData().get("items")).get(0);
62. System.out.println("selected:" + uuid);
63. content.setSrc("price.zul?id=" + uuid);
64. return true;
65. }
66. return false;
67. }
68. }
69. list.setAuService(new MyService());
70. </zscript>
71. <include id="data" src="data.xml" comment="true"/>
72. </panelchildren>
73. </panel>
74. </west>
75. <center>
76. <include id="content" src="price.zul?id=1"/>
77. </center>
78. </borderlayout>
79. </zk>
É possível fazer o download do código de amostra. Observe a melhoria na responsividade da caixa de procura.
Resumo
Neste artigo, você explorou como melhorar seu desenvolvimento Ajax no ZK
aproveitando os méritos da programação dos lados de ambos, servidor e
cliente. O ZK sincroniza os estados do aplicativo automaticamente nos
dois lados.
Você pode usufruir da produtividade das tecnologias Java EE,
ao mesmo tempo que tem a escolha de implementar funções no lado do
cliente. Sua abordagem de implementação torna-se dependente dos
requisitos de aplicativos corporativos que você constrói e não dos
méritos ou restrições da estrutura de desenvolvimento.
Recursos
Aprender
- “Rich Internet applications using ZK”
(developerWorks, janeiro de 2010) apresenta a você o ZK e lhe dá um
exemplo real de seu uso, executando no Apache Tomcat e conectando-se a
um banco de dados MySQL. - Leia sobre ZK 5.0 e jQuery
e ZK 5.0
e jQuery, parte 2 e obtenha uma introdução, um demo, e saiba como implementar os controles ZK, construir um exemplo, e muito mais. - Saiba mais sobre namespace do cliente
e programação no lado do cliente. - Leia sobre Widget ZK, a superclasse de todas as classes widget.
- ZK MVC Made Easy
discute em detalhes as três classes de utilidades e os
três métodos auxiliares fornecidos pelo ZK que irão ajudar você a
escrever aplicativos no padrão model view controller de maneira mais
fácil. - Aprenda mais sobre a Ligação de dados ZK
(um mecanismo que automatiza o código de ligação para cópia de dados
entre componentes da UI e a fonte de dados) e o gerenciador de ligação
de dados.
Obter produtos e tecnologias
- Faça o Download gratuito do ZK.
Discutir
- Crie seu perfil do My developerWorks hoje e configure uma watchlist no Ajax.
Conecte-se e fique conectado com o My developerWorks. - Compartilhe seus conhecimentos: Junte-se a um de nossos grupos developerWorks focados em tópicos web.
- Roland Barcia fala sobre Web 2.0 e middleware nesse blog.
- Siga Marcadores compartilhados em tópicos Web.
- Obtenha respostas rapidamente: Visite o fórum Web 2.0 Apps.
- Obtenha respostas rapidamente: Visite o fórum Ajax.
***
artigo publicado originalmente no developerWorks Brasil, por Lance Lu e Sachin K Mahajan
Lance Lu é divulgador de tecnologia para a estrutura ZK. Antes de aderir
ao ZK, ele era Engenheiro Avançado em uma empresa que projeta
microprocessadores de 32 bits, em Taiwan. Foi também Gerente de Produto
em um fabricante de dispositivos médicos, no Canadá. Lance é bacharel em
matemática formado pela Universidade de Victoria, no Canadá. Seus
interesses acadêmicos incluem física, filosofia, psicologia, matemática e
ciência da computação.
Sachin K Mahajan tem um diploma de Mestrado da University of Utah, em Salt Lake
City, EUA. Ele trabalhou em empresas grandes e pequenas nos Estados
Unidos e Índia, executando várias funções técnicas e gerenciais. Sachin
trabalha atualmente na divisão Lotus do IBM Software Group.