wicket_ Apache Wicket Apache Wicket Um framework simplificado para construir páginas Web dinâmicas Qual 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 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. / 40
Luis Gustavo Santos Fernandez luisgustavo.fernandez@gmail.com 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 Wicket, HTML Puro. <html> <span>rotulo</span> <input type= text id= campotexto /> Listagem 3. HTML com utilização de marcações Wicket, HTML Modificado. <html> <span wicket:id= rotulo >Rotulo</span> <input type= text wicket:id= campotexto /> 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. Modelo A parte central do framework são as classes de modelos (Model) responsáveis pelo binding dos PO- JOs aos componentes do Wicket. Essas classes (Model) são identificadas facilmente, pois todo modelo implementa a interface IModel. Wicket POJO TextField(login) PasswordTextField (senha) Model Figura 3. Vínculo POJO/Componentes. Usuário +login:string +senha:string 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/xhtml1- strict.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 WicketApplication (classe suporte para configurações gerais) que é configurada através do arquivo web.xml para a inicialização do framework Apache Wicket. Listagem 8. Configuração do WicketApplication criado 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> Configurando o SpringFramework Para inserção do SpringFramework ao projeto, é necessário adicionar algumas bibliotecas dentro do arquivo pom.xml, em especial a biblioteca wicket- -spring, que fornece a injeção de dependência dentro do Wicket. 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> O próximo passo é configurar o Wicket para reconhecer o SpringFramework que deve ser feito na classe WicketApplication. Listagem 10. Código para inicialização do SpringFramework para Wicket 1.4.x na classe WicketApplication. protected void init(){ addcomponentinstantiationlistener( new SpringComponentInjector(this)); Listagem 11. Código para inicialização do SpringFramework para Wicket 1.5.x na classe WicketApplication. 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 do aplicativo Wicket definida em uma variável de segmento local, ou seja, deve-se criar a instância do WicketApplication dentro do arquivo web.xml. Listagem 12. Exemplo de uso da anotação @Spring- Bean e uma simples classe de serviço. @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, corpo e rodapé da sua aplicação, onde se deve somente alterar o conteúdo do corpo, dependendo da funcionalidade que se acesse. 43 \
Listagem 13. HTML de exemplo para a geração do template base. <html> <head> <!-- links para CSS e JS --> </head> <div id= corpo > <div id= rodape > 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> <div id= corpo > <wicket:child/> <div id= rodape > 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{ 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. Listagem 16. HTML para o formulário. //Listagem 16. HTML para o formulário. <wicket:extend> <form wicket:id= form > Nome: <input type= text wicket:id= nome /> Sexo: <span wicket:id= sexo /> Estado Civil: <select wicket:id= estadocivil > </select> <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 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 / 44
o formulário. Além da tipagem, deve-se vincular o POJO ao seu model utilizando a classe org.apache. wicket.model.compoundpropertymodel, responsável por realizar o binding do POJO ao HTML. Listagem 18. Criando o formulário para o POJO Pessoa. Form<Pessoa> formulario = new Form<Pessoa>( form ); 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 Para os campos de escolha, como o campo rádio ou combobox, é necessário criar uma lista de objetos referente àquele campo. Essa lista pode ser estática ou um retorno de uma consulta ao banco de dados. A vinculação do componente através do ID correspondente no HTML é imprescindível. 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); Para cada elemento contido na lista de objetos, criada através do enum Sexo, será renderizado um novo elemento visual, ou seja, um novo input do tipo radio. Listagem 21. HTML gerado pela renderização dos elementos do Radio. <span> <input name= sexo type= radio checked= checked value= M id= id90-m /> <label for= id90-m >Masculino</label> <input name= sexo type= radio value= F id= id90-f /> <label for= id90-f >Feminino</label> </span> Para esses componentes, o Wicket, por padrão, utiliza o método tostring() para renderizar os valores do rótulo de cada opção e sua posição dentro da lista de valores. Para personalizarmos a renderização desses componentes, pode-se utilizar a classe org. apache.wicket.markup.html.form.ichoicerenderer. Esse componente separa os valores do id e do displayvalue dos componentes para renderizar as informações personalizadas. 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 elementos do DropDownChoice. <select id= estadocivil name= estadocivil > <option selected= selected value= >Selecione</option> <option value= C >Casado</option> <option value= S >Solteiro</option> <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. Adicionando o botão de submit Para conclusão do cadastro, é necessário um botão para submeter os dados inseridos pelo usuário que, neste artigo, se utiliza do componente org. apache.wicket.markup.html.form.button. Deve-se observar que, dentro de um formulário, pode haver diferentes componentes de botão com diferentes comportamentos. A propriedade de modelo para o botão é o value, e esse atributo servirá de rótulo para o botão. Quando se submeter o formulário por padrão (click no botão), o método onsubmit() é invocado primeiramente e logo em seguida o método onsubmit() do formulário. 45 \
Caso o comportamento do botão seja de Voltar pode-se utilizar a propriedade defaultformprocessing definindo-o como false fazendo com que as validações de formulários sejam ignoradas. 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); Para a navegação entre as páginas se utilizará o método setresponsepage que define qual página irá responder ao request. Listagem 25. Criando o botão salvar e reimplementando o método onsubmit(). Button botaosalvar = new Button( botaosalvar ){ //Re-implementando o metodo onsubmit 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); Listagem 27. Enum Sexo e Estado Civil. public enum Sexo { M, F; public enum EstadoCivil { SOLTEIRO( SO, Solteiro ), CASADO( CS, Casado ), DIVORCIADO( DV, Divorciado ), VIUVO( VV, Viuvo(a) ); private String sigla; private String descricao; private EstadoCivil(String sigla, String descricao){ this.sigla = sigla; this.descricao = descricao; public String getsigla() { return sigla; 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 { public Class<MundoJ> gethomepage() { //Página de inicialização da aplicação return MundoJ.class; public void init() { //Inicializando o Spring para Wicket 1.5 getcomponentinstantiationlisteners().add( new SpringComponentInjector(this)); Listagem 29. BasePage.html <html xmlns:wicket= http://wicket.apache.org > <head> <!-- links para CSS e JS --> </head> <div id= corpo > <wicket:child/> <div id= rodape > / 46
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 public void onsubmit() { setresponsepage(home.class); ; formulario.add(botaosalvar); add(formulario); Estado Civil: <select wicket:id= estadocivil > </select> <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 > Nome: <input type= text wicket:id= nome /> Sexo: <span wicket:id= sexo /> > 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 \