wicket_ Apache Wicket Um framework simplificado para construir páginas Web dinâmicas Q ual desenvolvedor não gostaria de utilizar orientação a objetos na Web? Utilizar componentes reutilizáveis e independentes? Utilizar a pura programação Java e HTML sem fortes vínculos? O framework Apache Wicket pode nos ajudar nos questionamentos levantados devido a sua simplicidade e agilidade, e vem ganhando espaço no mercado para o desenvolvimento de aplicações Web. A principal diferença na utilização do Apache Wicket para o desenvolvimento de aplicações Web com outros frameworks da camada de visão é a utilização de componentes que mantêm seus estados (statefull) e reagem independentemente de outro componente na entrada de dados do usuário. O objetivo deste artigo é demonstrar e estimular os desenvolvedores com a criação de uma página web utilizando o framework Apache Wicket por meio de seus próprios componentes que interagem com as entradas do usuário. A metodologia para criação da página web, proposta neste artigo, compreende primeiramente o nivelamento conceitual sobre alguns pontos fundamentais: relativo a componentes, modelos, templates, application e session e posteriormente a aplicação básica com o Apache Wicket versão 1.5.7 e Spring Framework 3.0. Conceitos O Apache Wicket é um framework orientado a componentes que contém um suporte eficaz e independente a componentes que seguem um determinado modelo, possibilitando que novas instâncias sejam “plugadas” no framework com simplicidade. Trazendo de forma simples a separação de responsabilidades entre as classes Java e o HTML, onde o HTML é usado para criação da interface visual e o Java para o controle de estado e modelo. Os componentes do Apache Wicket se ligam facilmente a classes de modelo, como, por exemplo, a classe Pessoa, através da utilização de models sem a / 40 utilização de qualquer arquivo XML para configurar esse vínculo. Sendo um framework orientado a componentes e não a ações, possibilita tanto um suporte eficaz a componentes que seguem um determinado padrão ou modelo de utilização quanto possibilita que instâncias sejam “plugadas” no framework. Portanto, tudo no Apache Wicket é componente, sendo uma classe Java. Componente Como pilares da construção de uma página, os componentes são responsáveis por sua própria apresentação, como, por exemplo, o componente TextField, que já cria automaticamente sua identidade visual. Cada instância de um componente deve estar atrelada unicamente a um único ID. Caso ocorra duplicidade de ID o Apache Wicket lança uma exceção informando que o componente já está em uso. UsuarioPage Cadastrar Panel Form(“Formulário”) TextField(“Nome”) Button(“Salvar”) Figura 1. Componentes aninhados em uma árvore hierárquica. Os componentes podem estar associados a templates (marcações), onde os arquivos Java e HTML devem residir no mesmo pacote e conter a mesma nomenclatura, como, por exemplo, Page e Panel. Em componentes que não contêm associação a templates, os arquivos estão localizados dentro da superclasse, como, por exemplo, Label e Form. Luis Gustavo Santos Fernandez | [email protected] Formado em Engenharia da Computação pelo Centro Universitário de Brasília. Trabalha com desenvolvimento de software há 6 anos. http://www.futurextending.com.br O Apache Wicket é um framework orientado a componentes que não exige a utilização de códigos HTML especiais, focado em reutilização e que possibilita uma programação Web divertida. Essas são as motivações que levaram Jonathan Locke (autor do Wicket) a criar esse framework que tem ganhado espaço a cada dia no mercado de trabalho. O fator diferencial deste framework é a perfeita sincronia entre o que há de melhor em Tapestry e Echo. Listagem 1. Classe que representa uma página. public class Pratica extends WebPage{ public Pratica(){ add(new Label(“rotulo”)); add(new TextField<String>(“campoTexto”)); } } Listagem 2. HTML sem utilização de marcações Modelo A parte central do framework são as classes de modelos (Model) responsáveis pelo binding dos POJOs aos componentes do Wicket. Essas classes (Model) são identificadas facilmente, pois todo modelo implementa a interface IModel. Wicket POJO Usuário TextField(login) Wicket, “HTML Puro”. <html> <body> <span>Rotulo</span> <input type=”text” id=”campoTexto”/> </body> </html> Listagem 3. HTML com utilização de marcações Wicket, “HTML Modificado”. <html> <body> <span wicket:id=”rotulo”>Rotulo</span> <input type=”text” wicket:id=”campoTexto”/> </body> </html> Observe que na criação dos campos Label e TextField deve-se obrigatoriamente colocar o ID do componente correspondente ao markup dentro do HTML. Figura 2. Associação entre os componentes e o HTML. Model +login:String +senha:String PasswordTextField (senha) Figura 3. Vínculo POJO/Componentes. Markup/Tags Os documentos HTML que o Apache Wicket utiliza como template podem conter vários atributos especiais, denominados markup ou simplesmente tags. Para se evitar entraves com editores de HTML devido ao uso de tags específicos do Apache Wicket deve-se declarar o namespace “xmlns:wicket”. Listagem 4. Exemplos de utilização de namespace. <?xml version=”1.0” encoding=”UTF-8”?> <html xmlns=”http://www.w3.org/1999/xhtml” xmlns:wicket=”http://wicket.apache.org/dtds.data/wicketxhtml1.4-strict.dtd” > Ou <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Strict//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1strict.dtd”> <html xmlns=”http://www.w3.org/1999/xhtml” xmlns:wicket=”http://wicket.apache.org/dtds.data/wicketxhtml1.4-strict.dtd” > 41 \ Application A classe base para aplicações do Apache Wicket, application fornece todo o suporte para configurar o projeto. Dentro dessa classe pode-se inicializar o Spring, definir a página principal do projeto, configurar outras bibliotecas como wiQuery e JQwicket, dentre outras configurações. É facilmente configurável através do arquivo web.xml Listagem 5. Configurando o Application para Wicket 1.4.x. <?xml version=”1.0” encoding=”UTF-8”?> <!DOCTYPE web-app PUBLIC “-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN” “http://java.sun.com/dtd/web-app_2_3.dtd”> <web-app> <display-name>Exemplo MundoJ</display-name> <servlet> <servlet-name>OlaMundoJ</servlet-name> <servlet-class>wicket.protocol.http.WicketServlet </servlet-class> <init-param> <param-name>applicationClassName </param-name> <param-value>br.com.mundoj.application. MeuApplication</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>OlaMundoJ</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.html</welcome-file> </welcome-file-list> </web-app> <param-name>applicationClassName </param-name> <param-value>br.com.mundoj.application. MeuApplication</param-value> </init-param> </filter> <filter-mapping> <filter-name>OlaMundoJ</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app> Criando um projeto Wicket Para a criação de um projeto com recurso do Apache Wicket, primeiramente, é necessário que esteja instalado e configurado a ferramenta Maven versão 2.x ou 3.x. Em seguida, utiliza-se o archetype necessário à criação da estrutura básica (figura 7) fornecida no próprio site do Apache Wicket. Assim que executado o archetype, deve-se executar o comando mvn clean package para que as bibliotecas sejam baixadas de seus repositórios para um repositório local do Maven Listagem 7. Comando para execução do archetype para criação do projeto base. mvn archetype:generate -DarchetypeGroupId=org.apache. wicket -DarchetypeArtifactId=wicket-archetype-quickstart -DarchetypeVersion=1.5.7 -DgroupId=br.com.mundoj.wicket -DartifactId=mundoj Listagem 6. Configurando o Application para Wicket 1.5.x. <?xml version=”1.0” encoding=”UTF-8”?> <web-app xmlns:xsi=”http://www.w3.org/2001/ XMLSchema-instance” xmlns=”http://java.sun.com/xml/ns/javaee” xmlns:web=”http://java.sun.com/xml/ns/javaee/ web-app_2_5.xsd” xsi:schemaLocation=”http://java.sun.com/xml/ns/ javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd” version=”2.5”> <display-name>MundoJ</display-name> <filter> <filter-name>OlaMundoJ</filter-name> <filter-class>org.apache.wicket. protocol.http.WicketFilter</filter-class> <init-param> Figura 4. Estrutura base gerada através do archetype. / 42 Ao utilizar o archetype, é criada a classe Wicke- Listagem 10. Código para inicialização do SpringFratApplication (classe suporte para configurações ge- mework para Wicket 1.4.x na classe WicketApplication. rais) que é configurada através do arquivo web.xml @Override para a inicialização do framework Apache Wicket. Listagem 8. Configuração do WicketApplication cria- do através do archetype. <filter> <filter-name>wicket.mundoj</filter-name> <filter-class>org.apache.wicket. protocol.http.WicketFilter</filter-class> <init-param> <param-name>applicationClassName </param-name> <param-value>br.com.mundoj.wicket. WicketApplication</param-value> </init-param> </filter> <filter-mapping> <filter-name>wicket.mundoj</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> protected void init(){ addComponentInstantiationListener( new SpringComponentInjector(this)); } Listagem 11. Código para inicialização do SpringFramework para Wicket 1.5.x na classe WicketApplication. @Override public void init() { getComponentInstantiationListeners().add( new SpringComponentInjector(this)); } A anotação SpringBean Para a anotação ser utilizada na injeção de dependências do Spring Beans, seja um serviço ou um componente, têm-se como pré-requisito a instância Configurando o SpringFramework do aplicativo Wicket definida em uma variável de Para inserção do SpringFramework ao projeto, é segmento local, ou seja, deve-se criar a instância do necessário adicionar algumas bibliotecas dentro do WicketApplication dentro do arquivo web.xml. arquivo pom.xml, em especial a biblioteca wicket-spring, que fornece a injeção de dependência dentro Listagem 12. Exemplo de uso da anotação @Springdo Wicket. Bean e uma simples classe de serviço. Listagem 9. Código para inserção das dependências do SpringFramework e Wicket-Spring. <dependency> <groupId>org.apache.wicket</groupId> <artifactId>wicket-spring</artifactId> <version>${wicket.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>3.0.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>3.0.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>3.0.6.RELEASE</version> </dependency> @SpringBean private MeuServico meuServico{ @Service public class MeuServico{ //Metodos } } Criando templates Na criação da identidade visual de um projeto, deve-se atentar para a criação dos templates, um documento sem conteúdo, responsável somente pela apresentação visual (contendo cabeçalho e rodapé, por exemplo). Deste modo, a atenção dos desenvolvedores fica dirigida somente em construir o conteúdo dinâmico de cada página. O Apache Wicket fornece recursos para se utilizar de forma simplificada os templates. Para tornar isso mais compreensível, imagine que se tenha um template base criado por um Web Designer, no qual está especificado o cabeçalho, corO próximo passo é configurar o Wicket para re- po e rodapé da sua aplicação, onde se deve somente conhecer o SpringFramework que deve ser feito na alterar o conteúdo do corpo, dependendo da funcionalidade que se acesse. classe WicketApplication. 43 \ Listagem 13. HTML de exemplo para a geração do template base. <html> <head> <!-- links para CSS e JS --> </head> <body> <div id=”corpo”> </div> <div id=”rodape”> </div> </body> </html> Para colocar a marcação do Wicket wicket:child, modificando o HTML enviado pelo Web Designer, deve-se substituir o conteúdo de marcação pelo conteúdo do componente derivado da marcação wicket:extend, estendendo a marcação da superclasse com o conteúdo. Listagem 14. HTML modificado para ser utilizado pela aplicação como template base. <html xmlns:wicket=”http://wicket.apache.org”> <head> <!-- links para CSS e JS --> </head> <body> <div id=”corpo”> <wicket:child/> </div> <div id=”rodape”> </div> </body> </html> Através da herança “se diz” ao Wicket que as novas páginas utilizarão propriedades da superclasse, consequentemente a classe filha utilizará a estrutura de template desenhada. Listagem 15. Utilização da herança para reutilização do template. public class MundoJ extends BasePage{ } Listagem 16. HTML para o formulário. //Listagem 16. HTML para o formulário. <wicket:extend> <form wicket:id=”form”> <div> Nome: <input type=”text” wicket:id=”nome”/> </div> <div> Sexo: <span wicket:id=”sexo”/> </div> <div> Estado Civil: <select wicket:id=” estadoCivil”> </select> </div> <input type=”submit” value=”Salvar” wicket:id=”botaoSalvar”/> <input type=”submit” value=”Voltar” wicket:id=”botaoVoltar”/> </form> </wicket:extend> Cada elemento representado no HTML necessariamente terá que ter um componente associado na classe Java. A inicialização dos componentes acontece dentro do construtor da classe, é nesse momento que se adiciona os componentes. Para se estabelecer o vínculo do POJO (necessário implementar a interface java.io.Serializable) aos componentes, deve-se utilizar uma classe model, no caso deste artigo a classe CompoundPropertyModel. Listagem 17. POJO Pessoa. //Imports public class Pessoa implements Serializable{ private String nome; private Date dtNascimento; private Sexo sexo; private EstadoCivil estadoCivil; //getters and setters } O formulário contém os componentes como campo texto, rádio e combobox, o qual devemos adicioná-los dentro do nosso formulário. Criando formulário Simulando um cadastro Para simular um cadastro, supondo que o template base já tenha sido criado para a aplicação, deixando que somente as páginas de formulários com seus devidos campos sejam construídos de acordo com as funcionalidades, basta ter o HTML contendo as marcações do Apache Wicket e a classe Java correspondente. / 44 Os componentes do formulário, como campo texto, rádio e combobox, devem ser adicionados dentro do formulário. Basta adicionar o componente org. apache.wicket.markup.html.form.Form dentro da página (um componente WebPage para o Apache Wicket). O formulário tem a responsabilidade de manipular um POJO, correspondente ao seu caso de uso, e para isso utiliza-se um tipo genérico para “tipar” o formulário. Além da tipagem, deve-se vincular o Para esses componentes, o Wicket, por padrão, POJO ao seu model utilizando a classe org.apache. utiliza o método toString() para renderizar os valowicket.model .CompoundPropertyModel, responsá- res do rótulo de cada opção e sua posição dentro da vel por realizar o “binding do POJO ao HTML”. lista de valores. Para personalizarmos a renderização desses componentes, pode-se utilizar a classe org. Listagem 18. Criando o formulário para o POJO apache.wicket.markup.html.form.IChoiceRenderer. Pessoa. Esse componente separa os valores do “id” e do “displayValue” dos componentes para renderizar as inForm<Pessoa> formulario = new Form<Pessoa>(“form”); formações personalizadas. formulario.setModel(new CompoundPropertyModel<Pess oa>(p)); add(formulario); Adicionando um campo-texto A adição do campo-texto ao formulário é bem simples, basta criar uma instância do objeto org.apache.wicket.markup.html.form.TextField e colocar o ID correspondente no HTML. Listagem 19. Adicionando o campo-texto ao formulário. formulario.add(new TextField<String>(“nome”)); Adicionando um campo de rádio e combobox Listagem 22. Adicionando o campo combobox ao formulário e utilizando o ChoiceRenderer. //A classe EstadoCivil utilizada é um enum IChoiceRenderer<EstadoCivil> rendererCombo = new ChoiceRenderer<EstadoCivil> (“descricao”, “sigla”); DropDownChoice<EstadoCivil> combo = new DropDownChoice<EstadoCivil> (“estadoCivil”, Arrays.asList(EstadoCivil.values()), rendererCombo); formulario.add(combo); Para cada elemento contido na lista criada através do enum EstadoCivil será criado um novo elemento visual, no caso de DropDownChoice será criado um novo “option”. Listagem 23. HTML gerado pela renderização dos Para os campos de escolha, como o campo rádio elementos do DropDownChoice. ou combobox, é necessário criar uma lista de objetos referente àquele campo. Essa lista pode ser estática <select id=”estadoCivil” name=”estadoCivil”> <option selected=”selected” ou um retorno de uma consulta ao banco de dados. A value=””>Selecione</option> vinculação do componente através do ID correspon<option value=”C”>Casado</option> dente no HTML é imprescindível. <option value=”S”>Solteiro</option> Listagem 20. Adicionando o campo rádio ao formulário. //A classe Sexo utilizada é um enum. List<Sexo> listaSexo = Arrays.asList(Sexo.values()); RadioChoice<Sexo> radioChoice = new RadioChoice<Sexo>(“sexo”, listaSexo); formulario.add(radioChoice); <option value=”55”>Viúvo</option> <option value=”18”>Divorciado</option> </select> Esses componentes oferecem a possibilidade de reprogramarmos o componente e substituir o método wantOnSelectionChangedNotifications, forçando os ids e a volta de valores para o servidor a cada mudança de valores. Para cada elemento contido na lista de objetos, criada através do enum Sexo, será renderizado um Adicionando o botão de submit Para conclusão do cadastro, é necessário um novo elemento visual, ou seja, um novo “input” do botão para submeter os dados inseridos pelo usuátipo “radio”. rio que, neste artigo, se utiliza do componente org. Listagem 21. HTML gerado pela renderização dos apache.wicket.markup.html.form.Button. Deve-se elementos do Radio. observar que, dentro de um formulário, pode haver diferentes componentes de botão com diferentes <span> comportamentos. <input name=”sexo” type=”radio” checked=”checked” A propriedade de modelo para o botão é o “vavalue=”M” id=”id90-M”/> <label for=”id90-M”>Masculino</label> lue”, e esse atributo servirá de rótulo para o botão. <input name=”sexo” type=”radio” value=”F” Quando se submeter o formulário por padrão (click id=”id90-F”/> no botão), o método onSubmit() é invocado primei<label for=”id90-F”>Feminino</label> ramente e logo em seguida o método onSubmit() do </span> formulário. 45 \ Caso o comportamento do botão seja de “Voltar” Listagem 27. Enum Sexo e Estado Civil. pode-se utilizar a propriedade defaultFormProcessing definindo-o como false fazendo com que as validações de formulários sejam ignoradas. public enum Sexo { Listagem 24. Criando o botão voltar ignorando a validação do formulário. Button botaoVoltar = new Button(“botaoVoltar”); botaoVoltar.setDefaultFormProcessing(false); formulario.add(botaoVoltar); } public enum EstadoCivil { SOLTEIRO(“SO”, “Solteiro”), CASADO(“CS”, “Casado”), DIVORCIADO(“DV”, “Divorciado”), VIUVO(“VV”, “Viuvo(a)”); private String sigla; private String descricao; Para a navegação entre as páginas se utilizará o método setResponsePage que define qual página irá responder ao request. private EstadoCivil(String sigla, String descricao){ this.sigla = sigla; this.descricao = descricao; } Listagem 25. Criando o botão salvar e reimplementando o método onSubmit(). public String getSigla() { return sigla; } Button botaoSalvar = new Button(“botaoSalvar”){ //Re-implementando o metodo onSubmit @Override public void onSubmit() { //lógica para persistência dos dados //Retorno de página exemplo 1 setResponsePage(PaginaIndex.class); //Retorno de página exemplo 2 setResponsePage(new PainaIndex()); //Retorno de página exemplo 3 setResponsePage(webPage); } }; formulario.add(botaoSalvar); M, F; } public String getDescricao() { return descricao; } Listagem 28. BasePage.java //A funcionalidade dessa classe é ser base para o // template da aplicação public class BasePage extends WebPage{ } Versão final do HTML e das classes Java Listagem 26. WicketApplication.java public class WicketApplication extends WebApplication { @Override public Class<MundoJ> getHomePage() { //Página de inicialização da aplicação return MundoJ.class; } @Override public void init() { //Inicializando o Spring para Wicket 1.5 getComponentInstantiationListeners().add( new SpringComponentInjector(this)); } } / 46 Listagem 29. BasePage.html <html xmlns:wicket=”http://wicket.apache.org”> <head> <!-- links para CSS e JS --> </head> <body> <div id=”corpo”> <wicket:child/> </div> <div id=”rodape”> </div> </body> </html> Listagem 30. MundoJ.java public class MundoJ extends BasePage{ public MundoJ(){ Pessoa p = new Pessoa(); Form<Pessoa> formulario = new Form<Pessoa>(“form”); formulario.setModel( new CompoundPropertyModel<Pessoa>(p)); formulario.add(new TextField<String>(“nome”)); List<Sexo> listaSexo = Arrays.asList(Sexo.values()); RadioChoice<Sexo> radioChoice = new RadioChoice<Sexo>(“sexo”, listaSexo); formulario.add(radioChoice); IChoiceRenderer<EstadoCivil> rendererCombo = new ChoiceRenderer<EstadoCivil>(“descricao”, “sigla”); DropDownChoice<EstadoCivil> combo = new DropDownChoice<EstadoCivil>(“estadoCivil”, Arrays.asList(EstadoCivil.values()), rendererCombo); formulario.add(combo); Button botaoVoltar = new Button(“botaoVoltar”); botaoVoltar.setDefaultFormProcessing(false); formulario.add(botaoVoltar); Button botaoSalvar = new Button(“botaoSalvar”){ //Re-implementando o metodo onSubmit @Override public void onSubmit() { setResponsePage(Home.class); }; formulario.add(botaoSalvar); } } add(formulario); Estado Civil: <select wicket:id=”estadoCivil”> </select> </div> <input type=”submit” value=”Salvar” wicket:id=”botaoSalvar”/> <input type=”submit” value=”Voltar” wicket:id=”botaoVoltar”/> </form> </wicket:extend> Considerações finais O artigo demonstra como é simples e prática a utilização do framework Apache Wicket, que vem cada vez mais ganhando espaço no mercado, onde temos a separação dos códigos dinâmicos e códigos estáticos (Java e HTML + JavaScript). A utilização desse framework permite aos designers a liberdade de criar a identidade visual de um sistema, sem que o mesmo se preocupe com qual componente o desenvolvedor vai utilizar e que poderá afetar sua criação. O Apache Wicket é um framework da camada de apresentação, cuja responsabilidade é manipular o request e response. A simplicidade na sua utilização está em acoplar outros frameworks para serem utilizados como serviços ou persistências de dados, utilizando o Spring Framework ou Guice para injeção de dependências e JPA/Hibernate para a persistência de dados (exemplos). A utilização do Apache Wicket pode ser resumida em uma palavra: “simplicidade”. } /referências Listagem 31. MundoJ.html <wicket:extend> <form wicket:id=”form”> <div> Nome: <input type=”text” wicket:id=”nome”/> </div> <div> Sexo: <span wicket:id=”sexo”/> </div> <div> > Apache Wicket: http://wicket.apache.org/ > Migrando versão 1.4.x para 1.5.x: https://cwiki.apache. org/WICKET/migration-to-wicket-15.html > Exemplos práticos: http://www.wicket-library.com/ wicket-examples/ajax/ > Reference library: https://cwiki.apache.org/WICKET/ reference-library.html > Spring Framework: http://www.springsource.org/ > Wicket-Spring: https://cwiki.apache.org/WICKET/spring. html 47 \