QuickStart - Portal Demoiselle
Transcrição
QuickStart - Portal Demoiselle
Framework Demoiselle 2.0 QuickStart Emerson Saito Marlon Carvalho Rodrigo Hjort Serge Rehem Sobre o QuickStart ................................................................................................................. v 1. Instalação ........................................................................................................................ 1 1.1. Pré-requisitos .......................................................................................................... 1 1.2. Demoiselle Infra ....................................................................................................... 1 2. Criação da aplicação .......................................................................................................... 3 2.1. Nossa primeira aplicação ............................................................................................ 3 2.2. Construindo o projeto usando um arquétipo Maven ............................................................ 3 2.2.1. Linha de comando .......................................................................................... 2.2.2. Modo assistido com Eclipse .............................................................................. 2.3. Criando a entidade de domínio ..................................................................................... 2.4. Implementando a camada de persistência ....................................................................... 3 3 8 9 2.5. Implementando a camada de negócio ........................................................................... 10 2.6. Implementando a camada de apresentação .................................................................... 11 2.7. Executando no servidor ............................................................................................ 14 3. Melhorando a aplicação .................................................................................................... 17 3.1. Implementando funcionalidade de edição ....................................................................... 17 3.2. Exibindo mensagens para o usuário ............................................................................. 22 3.3. Criando regras de validação nos campos ....................................................................... 24 iii iv Sobre o QuickStart Este documento é um tutorial do tipo "passo a passo" que visa ilustrar de forma rápida, clara e prática a criação de uma aplicação simples utilizando o Demoiselle Framework 2.X. Nota Apesar de o Demoiselle Framework 2.X ser simples de usar, o desenvolvimento de aplicações não triviais requer o conhecimento das diversas tecnologias envolvidas na especificação Java EE, incluindo: • Linguagem Java • Servlets, JSP e Tag Libraries • JavaBeans • HTML e XML • Contêineres e Servidores Web Nota Esta documentação refere-se à release 2.2.X do Demoiselle Framework e pode diferir significativamente das versões anteriores. v vi Instalação 1.1. Pré-requisitos Software Versão Site (Download) Java Development Kit (JDK) 6.0 openjdk.org [http://openjdk.org/] Apache Maven 2.2 maven.apache.org [http:// maven.apache.org/docs/2.2.1/releasenotes.html] Eclipse IDE 3.7 www.eclipse.org [http://www.eclipse.org/ downloads/packages/release/indigo/r] m2eclipse plugin 0.12 m2eclipse.sonatype.org [http:// m2eclipse.sonatype.org/installingm2eclipse.html] JBoss Application Server 6.0 www.jboss.org [http://sourceforge.net/ projects/jboss/files/JBoss/ JBoss-6.0.0.Final/jboss-asdistribution-6.0.0.Final.zip/download] 1.2. Demoiselle Infra Para auxiliar no preparo do ambiente integrado de desenvolvimento utilizado na presente documentação, recomenda-se a utilização dos pacotes de software fornecidos pelo projeto Demoiselle Infra [http:// demoiselle.sourceforge.net/infra/]. Neste link você encontrará as orientações necessárias para a sua configuração. Nota Atualmente são disponibilizados pacotes exclusivamente para a plataforma GNU/Linux e distribuições baseadas no Debian, tal como Ubuntu. Se você não utiliza nenhum dos sistemas operacionais citados, terá que baixar e instalar todos os softwares listados acima. Para auxiliar um pouco o processo, disponibilizamos alguns vídeos aqui [http:// www.frameworkdemoiselle.gov.br/documentacaodoprojeto/tutoriais/videos/] de demonstração de algumas fases. 1 2 Criação da aplicação 2.1. Nossa primeira aplicação Para iniciar o uso do Demoiselle Framework 2.X, criaremos uma aplicação Java do tipo Web utilizando o Apache Maven [http://maven.apache.org/], através do plugin para IDE Eclipse (M2Eclipse) para gerenciar todo o clico de vida do Projeto, desde a criação até o deploy. Essa aplicação consistirá em um cadastro simples de bookmarks (links “Favoritos”) e será gerada com o auxílio de um arquétipo do Maven disponibilizado pelo projeto Demoiselle. Ela será preparada para utilizar as tecnologias de persistência JPA e de apresentação JSF nas versões mais recentes conforme a especificação Java EE 6. 2.2. Construindo o projeto usando um arquétipo Maven Importante O procedimento a seguir pode ser comumente executado de forma visual com o auxílio de um assistente (i.e., wizard) de dentro da IDE Eclipse, como será demonstrado logo após o modo linha de comando. 2.2.1. Linha de comando Para criar a aplicação usando o arquétipo em linha de comando, abra um terminal e execute o comando mvn do Maven com os argumentos ilustrados a seguir: mvn archetype:generate \ -DarchetypeGroupId=br.gov.frameworkdemoiselle.archetypes \ -DarchetypeArtifactId=demoiselle-jsf-jpa \ -DarchetypeVersion=2.2.0 \ -DarchetypeRepository=http://demoiselle.sourceforge.net/repository/release/ \ -DgroupId=br.gov.frameworkdemoiselle.sample \ -DartifactId=bookmark \ -Dversion=1.0.0-SNAPSHOT \ -DinteractiveMode=false 2.2.2. Modo assistido com Eclipse Para criar esse projeto utilizando a IDE Eclipse, acesse o menu File, New, Other... digite e selecione Maven Project: conforme mostrado na figura abaixo: 3 Capítulo 2. Criação da aplicação Na tela seguinte, recomenda-se manter os valores "default": Na tela abaixo, no combo-box chamado Catalog, selecione o item com o nome “Demoiselle” e no campo Filter digite “JSF” e em seguida selecione o item “demoiselle-jsf-jpa”: 4 Modo assistido com Eclipse Cuidado Se as opções anteriores não aparecem, é porque será necessário incluir o catálogo remoto de arquétipos Maven do Demoiselle. Caso contrário pule o subitem Incluindo catálogo remoto e siga as demais instruções. Cuidado A versão do arquétipo irá variar conforme surjam novas versões do Demoiselle. A imagem deste guia apresenta a versão 2.0.0, contudo, fique sempre atento para as novas versões do Demoiselle em nosso site e sempre utilize a versão do arquétipo mais recente. 2.2.2.1. Incluindo catálogo remoto Ainda na tela criação do novo projeto, clique no botão Configure à direita do combo-box Catalog, para que apareça a tela de configuração de arquétipos Maven no Eclipse. 5 Capítulo 2. Criação da aplicação Clique no botão Add Remote Catalog...: Na campo Catalog File coloque este conteúdo: http://demoiselle.sourceforge.net/ repository/archetype-catalog.xml. No campo Description informe: “Demoiselle”. Em seguida, clique no botão Verify... para certificar-se que o conteúdo está correto. Retorne então ao item anterior e siga as instruções. Na próxima tela preencha os campos conforme ilustrado a seguir e clique em Finish: 6 Modo assistido com Eclipse Ao término do processo será criado o projeto bookmark gerenciado pelo Maven e com a seguinte estrutura de diretórios: bookmark/ |-- pom.xml `-- src |-- main | | | | | | | | |-- java | `-- br | `-- gov | `-- frameworkdemoiselle | `-- sample | |-- business | |-- constant | |-- domain | | | | | | | | | | | |-- resources | | | | |-- demoiselle.properties |-- log4j.properties | | | | |-- messages.properties |-- META-INF | | | | | | | | `-- ValidationMessages.properties | | `-- webapp |-- home.xhtml |-|-|-|-`-- exception message persistence util view |-- beans.xml `-- persistence.xml | | |-- images | `-- logo.png | | |-- index.html |-- menu.xhtml | |-- template 7 Capítulo 2. Criação da aplicação | | | `-- WEB-INF `-- main.xhtml | | |-- faces-config.xml `-- web.xml `-- test |-- java | | `-- br `-- gov | `-- frameworkdemoiselle | `-- sample `-- resources 2.3. Criando a entidade de domínio Dentro do pacote br.gov.frameworkdemoiselle.sample.domain crie a classe Bookmark, a qual será responsável por representar um objeto de bookmark a ser persistido no banco de dados usando JPA: @Entity public class Bookmark { @Id @GeneratedValue private Long id; @Column private String description; @Column private String link; public Bookmark() { super(); } public Bookmark(String description, String link) { this.description = description; this.link = link; } } Nota Lembre-se de criar os respectivos métodos getter e setter para as propriedades dessa classe. Os dois construtores da classe Bookmark serão utilizados posteriormente na aplicação. As anotações @Entity, @Id, @GeneratedValue e @Column são fornecidas pela especificação JPA. 8 Implementando a camada de persistência 2.4. Implementando a camada de persistência Dentro do pacote br.gov.frameworkdemoiselle.sample.persistence crie a classe BookmarkDAO, a qual será responsável por manipular os dados: @PersistenceController public class BookmarkDAO extends JPACrud<Bookmark, Long> { private static final long serialVersionUID = 1L; } Dica A anotação @PersistenceController trata-se de um estereótipo fornecido pelo Demoiselle Framework 2.X para indicar que uma classe será tratada como controlador da camada de persistência na aplicação. A classe abstrata JPACrud faz parte do código de suporte fornecido pelo Demoiselle Framework 2.X (especificamente na extensão JPA). Ao utilizá-la, o desenvolvedor não precisará implementar métodos de manipulação de uma entidade, tais como busca, listagem, inclusão, alteração e exclusão de registros. Dessa forma, apenas métodos específicos do caso de uso necessitam ser criados manualmente. Nota Recomenda-se usar o sufixo “DAO” nessa classe para indicar que se trata de um objeto de acesso a dados (i.e., um DAO - Data Access Object). No diretório /src/main/resources/META-INF/, altere o arquivo persistence.xml com o conteúdo seguinte: <?xml version="1.0" encoding="UTF-8"?> <persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/ persistence/persistence_2_0.xsd"> <persistence-unit name="bookmark-ds"> <jta-data-source>java:/DefaultDS</jta-data-source> <class>br.gov.frameworkdemoiselle.sample.domain.Bookmark</class> <properties> <property name="hibernate.show_sql" value="true" /> <property name="hibernate.format_sql" value="false" /> <property name="hibernate.hbm2ddl.auto" value="update" /> <property name="hibernate.transaction.factory_class" value="org.hibernate.transaction.JTATransactionFactory" /> <property name="jta.UserTransaction" value="UserTransaction" /> </properties> </persistence-unit> 9 Capítulo 2. Criação da aplicação </persistence> Este arquivo armazenará as configurações de acesso ao banco de dados via JPA. Neste caso, o gerenciamento das conexões ficará a cargo do servidor de aplicações (ex: JBoss AS). Será usada a fonte de dados java:/ DefaultDS. No diretório /src/main/resources/, altere o arquivo demoiselle.properties com o conteúdo seguinte: frameworkdemoiselle.persistence.unit.name=bookmark-ds No diretório /src/main/resources/META-INF/, altere o arquivo beans.xml com o conteúdo seguinte: <?xml version="1.0"?> <beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_1.xsd"> <alternatives> <class>br.gov.frameworkdemoiselle.transaction.JTATransaction</class> </alternatives> </beans> 2.5. Implementando a camada de negócio Dentro do pacote br.gov.frameworkdemoiselle.sample.business crie a classe BookmarkBC, a qual será responsável por gerenciar as regras de negócio referentes aos bookmarks: @BusinessController public class BookmarkBC extends DelegateCrud<Bookmark, Long, BookmarkDAO> { private static final long serialVersionUID = 1L; @Startup @Transactional public void startup() { if (findAll().isEmpty()) { insert(new Bookmark("Demoiselle Portal", "http://www.frameworkdemoiselle.gov.br")); insert(new Bookmark("Demoiselle SourceForge", "http://sf.net/projects/demoiselle")); insert(new Bookmark("Twitter", "http://twitter.frameworkdemoiselle.gov.br")); insert(new Bookmark("Blog", "http://blog.frameworkdemoiselle.gov.br")); insert(new Bookmark("Wiki", "http://wiki.frameworkdemoiselle.gov.br")); insert(new Bookmark("Bug Tracking", "http://tracker.frameworkdemoiselle.gov.br")); insert(new Bookmark("Forum", "http://forum.frameworkdemoiselle.gov.br")); insert(new Bookmark("SVN", "http://svn.frameworkdemoiselle.gov.br")); insert(new Bookmark("Maven", "http://repository.frameworkdemoiselle.gov.br")); insert(new Bookmark("Downloads", "http://download.frameworkdemoiselle.gov.br")); } } 10 Implementando a camada de apresentação } O método startup() nessa classe será invocado automaticamente durante a inicialização da aplicação e fará com que a tabela seja populada com dados iniciais de bookmarks. Dica A anotação @BusinessController trata-se de um estereótipo fornecido pelo Demoiselle Framework 2.X para indicar que uma classe será tratada como controlador da camada de negócio na aplicação. A classe DelegateCrud faz parte do código de suporte fornecido pelo Demoiselle Framework 2.0. Ao utilizá-la, o desenvolvedor não precisará implementar métodos de negócio triviais de uma entidade e tampouco programar a injeção de dependência entre as camadas de negócio e persistência. Tal injeção será realizada de forma implícita. Nota Recomenda-se usar o sufixo “BC” nessa classe para indicar que se trata de um controlador de negócio (i.e., um BC - Business Controller). 2.6. Implementando a camada de apresentação Dentro do pacote br.gov.frameworkdemoiselle.sample.view crie a classe BookmarkListMB, a qual será responsável por exibir as informações sobre os bookmarks para o usuário: @ViewController public class BookmarkListMB extends AbstractListPageBean<Bookmark, Long> { private static final long serialVersionUID = 1L; @Inject private BookmarkBC bc; @Override protected List<Bookmark> handleResultList() { return bc.findAll(); } } Dica A anotação @ViewController trata-se de um estereótipo fornecido pelo Demoiselle Framework para indicar que uma classe será tratada como controlador da camada de apresentação (i.e., visão) na aplicação. 11 Capítulo 2. Criação da aplicação A classe AbstractListPageBean faz parte do código de suporte fornecido pelo Demoiselle Framework (especificamente na extensão JSF). Ao utilizá-la, o desenvolvedor não precisará implementar métodos específicos de navegação para uma tela de cadastro (i.e., do tipo CRUD). A anotação @Inject é fornecida pela especificação CDI. Ela realiza a injeção de dependência da camada de negócio dentro do artefato da camada de apresentação. Nota Recomenda-se usar o sufixo “MB” nessa classe para indicar que se trata de um bean gerenciado do JSF (i.e., um MB - Managed Bean). No diretório /src/main/webapp/, crie o arquivo bookmark_list.xhtml com o conteúdo seguinte: <ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:p="http://primefaces.prime.com.tr/ui" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets" template="/template/main.xhtml"> <ui:define name="body"> <h:form> <p:dataTable id="list" var="bean" value="#{bookmarkListMB.resultList}"> <f:facet name="header">#{messages['bookmark.list.table.title']}</f:facet> <p:column style="width:1%;"> <h:selectBooleanCheckbox value="#{bookmarkListMB.selection[bean.id]}" /> </p:column> <p:column style="width:5%;" sortBy="#{bean.id}"> <f:facet name="header">#{messages['bookmark.label.id']}</f:facet> <h:outputText value="#{bean.id}" /> </p:column> <p:column sortBy="#{bean.description}"> <f:facet name="header">#{messages['bookmark.label.description']}</f:facet> <h:commandLink action="#{bookmarkListMB.getNextView}" actionListener="#{bookmarkListMB.clear}"> <h:outputText value="#{bean.description}" /> <f:param name="id" value="#{bean.id}" /> </h:commandLink> </p:column> <p:column sortBy="#{bean.link}"> <f:facet name="header">#{messages['bookmark.label.link']}</f:facet> <h:commandLink action="#{bookmarkListMB.getNextView}" actionListener="#{bookmarkListMB.clear}"> <h:outputText value="#{bean.link}" /> <f:param name="id" value="#{bean.id}" /> </h:commandLink> </p:column> </p:dataTable> </h:form> </ui:define> </ui:composition> 12 Implementando a camada de apresentação Dica Nos arquivos XHTML listados neste exemplo foi empregado o framework PrimeFaces [http:// www.primefaces.org/], o qual foi um dos primeiros a oferecer suporte completo à especificação JSF 2.0. No diretório /src/main/webapp/, altere o arquivo menu.xhtml com o conteúdo seguinte: <ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:p="http://primefaces.prime.com.tr/ui" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets"> <h:form> <p:menubar> <p:submenu label="#{messages['menu.bookmark']}"> <p:menuitem value="#{messages['menu.menuitem.list']}" url="/bookmark_list.jsf" /> </p:submenu> <p:submenu> <f:facet name="label"> <p:menuitem value="#{messages['menu.menuitem.quit']}" url="http://www.frameworkdemoiselle.gov.br/" /> </f:facet> </p:submenu> </p:menubar> </h:form> </ui:composition> No diretório /src/main/resources/, altere o arquivo messages.properties incluindo as linhas a seguir: bookmark.list.table.title=Lista de Links bookmark.label.id=ID bookmark.label.link=Link bookmark.label.description=Descri\u00E7\u00E3o bookmark.label=Bookmark bookmark.alt.id=ID bookmark.alt.link=Link bookmark.alt.description=Descri\u00E7\u00E3o menu.bookmark=Bookmarks Nota O arquivo de recursos messages.properties armazenará textos no idioma default da aplicação (neste caso, em Português do Brasil). 13 Capítulo 2. Criação da aplicação Dica Ao invés de manter fixas as descrições em rótulos, links, botões e mensagens em uma aplicação, recomenda-se parametrizar esses textos em arquivos de recursos. Além de ser considerada boa prática, essa medida facilita uma posterior internacionalização da aplicação para diversos idiomas. 2.7. Executando no servidor A última etapa consiste na construção da aplicação Java Web e no respectivo deploy em um servidor de aplicações. Utilizando a IDE Eclipse, basta clicar com o botão direito no projeto bookmark e acessar o menu Run As, Run on Server. Em seguida, escolha um servidor compatível com Java EE 6 (ex: JBoss AS 6) e aguarde a inicialização deste. Na visão Console você verá as mensagens decorrentes do servidor de aplicações e da inicialização da aplicação bookmark agora hospedada nele. Dica Para executar em modo de depuração, na visão Servers, clique com o botão direito no servidor desejado e selecione a opção Debug. Nota Também é possível efetuar esses passos em linha de comando. Para isso, execute o comando mvn package, copie o arquivo bookmark.war resultante para a pasta de deploy do servidor 14 Executando no servidor (ex: JBOSS_HOME/server/default/deploy) e inicie este último através de seu comando próprio (ex: JBOSS_HOME/bin/run.sh). Em seguida, abra o navegador Web de sua preferência e acesse o endereço http://localhost:8080/bookmark. Esta é a página que deverá ser exibida com a aplicação bookmark em funcionamento: Figura 2.1. Página principal da aplicação Bookmark 15 16 Melhorando a aplicação 3.1. Implementando funcionalidade de edição Agora que a aplicação inicial já está rodando, iremos aumentar sua complexidade adicionando a funcionalidade de edição dos registros de bookmark. Dentro do pacote br.gov.frameworkdemoiselle.sample.view crie a classe BookmarkEditMB, a qual será responsável por controlar as modificações sobre os bookmarks efetuadas pelo usuário: @ViewController @PreviousView("/bookmark_list.xhtml") public class BookmarkEditMB extends AbstractEditPageBean<Bookmark, Long> { private static final long serialVersionUID = 1L; @Inject private BookmarkBC bc; @Override @Transactional public String delete() { bc.delete(getId()); return getPreviousView(); } @Override @Transactional public String insert() { bc.insert(getBean()); return getPreviousView(); } @Override @Transactional public String update() { bc.update(getBean()); return getPreviousView(); } @Override protected void handleLoad() { setBean(bc.load(getId())); } } 17 Capítulo 3. Melhorando a apli... Dica A anotação @Transactional trata-se de uma anotação fornecida pelo Demoiselle Framework para indicar que o método em questão será incluído na sessão transacional. Caso essa anotação esteja vinculada na classe, todos os seus métodos serão considerados transacionais. A classe AbstractEditPageBean faz parte do código de suporte fornecido pelo Demoiselle Framework (especificamente na extensão JSF). Ao utilizá-la, o desenvolvedor não precisará implementar métodos específicos de navegação para uma tela de cadastro (i.e., do tipo CRUD). Ainda no pacote br.gov.frameworkdemoiselle.sample.view altere a classe BookmarkListMB: @ViewController @NextView("/bookmark_edit.xhtml") @PreviousView("/bookmark_list.xhtml") public class BookmarkListMB extends AbstractListPageBean<Bookmark, Long> { private static final long serialVersionUID = 1L; @Inject private BookmarkBC bc; @Override protected List<Bookmark> handleResultList() { return bc.findAll(); } @Transactional public String deleteSelection() { boolean delete = false; Iterator<Long> iter = getSelection().keySet().iterator(); while (iter.hasNext()) { Long id = iter.next(); delete = getSelection().get(id); if (delete) { bc.delete(id); iter.remove(); } } return getPreviousView(); } } A anotação @NextView serve para definir a próxima visão a ser direcionado o fluxo de navegação JSF. De forma semelhante, a anotação @PreviousView define a visão anterior de um fluxo. O novo método deleteSelection() servirá para permitir a funcionalidade de exclusão de múltiplas linhas da tabela. A anotação @Transactional nele faz com que o método seja considerado como transacional, incluindo-o na respectiva sessão. No diretório /src/main/webapp/, crie o arquivo bookmark_edit.xhtml com o conteúdo seguinte: 18 Implementando funcionalidade de edição <ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:p="http://primefaces.prime.com.tr/ui" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets" template="/template/main.xhtml"> <ui:define name="body"> <h:form prependId="false"> <p:toolbar> <p:toolbarGroup align="left"> <p:commandButton value="#{messages['button.save']}" action="#{bookmarkEditMB.insert}" rendered="#{!bookmarkEditMB.updateMode}" ajax="false" /> <p:commandButton value="#{messages['button.save']}" action="#{bookmarkEditMB.update}" rendered="#{bookmarkEditMB.updateMode}" ajax="false" /> <p:commandButton value="#{messages['button.delete']}" onclick="confirmation.show()" rendered="#{bookmarkEditMB.updateMode}" type="button" immediate="true" ajax="false" /> <p:confirmDialog message="#{messages['label.confirm.delete']}" showEffect="bounce" hideEffect="explode" header="#{messages['label.dialog.delete']}" severity="alert" widgetVar="confirmation"> <h:commandButton value="#{messages['button.dialog.yes']}" action="#{bookmarkEditMB.delete}" immediate="true" ajax="false" /> <h:commandButton value="#{messages['button.dialog.no']}" onclick="confirmation.hide()" type="button" /> </p:confirmDialog> </p:toolbarGroup> </p:toolbar> <br /> <p:fieldset legend="#{messages['bookmark.label']}" toggleable="true" toggleSpeed="500"> <h:panelGrid id="fields" columns="3"> <h:outputLabel value="#{messages['bookmark.label.id']}: " for="id" styleClass="text-input" /> <h:outputText id="id" value="#{bookmarkEditMB.bean.id}" /> <p:message for="id" /> <h:outputLabel value="#{messages['bookmark.label.description']}: " for="description" styleClass="text-input" /> <h:inputText id="description" value="#{bookmarkEditMB.bean.description}" title="#{messages['bookmark.alt.description']}" /> <p:message for="description" /> <h:outputLabel value="#{messages['bookmark.label.link']}: " for="link" styleClass="text-input" /> <h:inputText id="link" value="#{bookmarkEditMB.bean.link}" title="#{messages['bookmark.alt.link']}" /> <p:message for="link" /> </h:panelGrid> </p:fieldset> </h:form> </ui:define> </ui:composition> Ainda no diretório /src/main/webapp/, modifique o arquivo bookmark_list.xhtml com o conteúdo seguinte: <ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" 19 Capítulo 3. Melhorando a apli... xmlns:p="http://primefaces.prime.com.tr/ui" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets" template="/template/main.xhtml"> <ui:define name="body"> <h:form> <p:toolbar> <p:toolbarGroup align="left"> <p:commandButton title="#{messages['button.new']}" image="ui-icon-document" action="#{bookmarkListMB.getNextView}" actionListener="#{bookmarkListMB.clear}" ajax="false" /> <p:commandButton title="#{messages['button.delete']}" image="ui-icon-trash" onclick="confirmation.show()" type="button" immediate="true" ajax="false" /> <p:confirmDialog message="#{messages['label.confirm.delete']}" showEffect="bounce" hideEffect="explode" header="#{messages['label.dialog.alert']}!" severity="alert" widgetVar="confirmation"> <h:commandButton value="#{messages['button.dialog.yes']}" action="#{bookmarkListMB.deleteSelection}" actionListener="#{bookmarkListMB.clear}" /> <h:commandButton value="#{messages['button.dialog.no']}" onclick="confirmation.hide()" type="button" /> </p:confirmDialog> </p:toolbarGroup> </p:toolbar> <p:dataTable id="list" var="bean" value="#{bookmarkListMB.resultList}"> <f:facet name="header">#{messages['bookmark.list.table.title']}</f:facet> <p:column style="width:1%;"> <h:selectBooleanCheckbox value="#{bookmarkListMB.selection[bean.id]}" /> </p:column> <p:column style="width:5%;" sortBy="#{bean.id}"> <f:facet name="header">#{messages['bookmark.label.id']}</f:facet> <h:outputText value="#{bean.id}" /> </p:column> <p:column sortBy="#{bean.description}"> <f:facet name="header">#{messages['bookmark.label.description']}</f:facet> <h:commandLink action="#{bookmarkListMB.getNextView}" actionListener="#{bookmarkListMB.clear}"> <h:outputText value="#{bean.description}" /> <f:param name="id" value="#{bean.id}" /> </h:commandLink> </p:column> <p:column sortBy="#{bean.link}"> <f:facet name="header">#{messages['bookmark.label.link']}</f:facet> <h:commandLink action="#{bookmarkListMB.getNextView}" actionListener="#{bookmarkListMB.clear}"> <h:outputText value="#{bean.link}" /> <f:param name="id" value="#{bean.id}" /> </h:commandLink> </p:column> </p:dataTable> </h:form> </ui:define> </ui:composition> No diretório /src/main/webapp/, altere o arquivo menu.xhtml conforme o conteúdo seguinte: 20 Implementando funcionalidade de edição <ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:p="http://primefaces.prime.com.tr/ui" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets"> <h:form> <p:menubar> <p:submenu label="#{messages['menu.bookmark']}"> <p:menuitem value="#{messages['menu.menuitem.new']}" url="/bookmark_edit.jsf" /> <p:menuitem value="#{messages['menu.menuitem.list']}" url="/bookmark_list.jsf" /> </p:submenu> <p:submenu> <f:facet name="label"> <p:menuitem value="#{messages['menu.menuitem.quit']}" url="http://www.frameworkdemoiselle.gov.br/" /> </f:facet> </p:submenu> </p:menubar> </h:form> </ui:composition> Tendo feito todas essas alterações, reconstrua o projeto Java e faça novo deploy no servidor de aplicações. Ao acessar a aplicação bookmark pelo browser, verá que agora existe uma opção nova no menu principal: Bookmarks, Novo. Executando-a, será exibida a página a seguir: Figura 3.1. Edição dos dados na aplicação Bookmark 21 Capítulo 3. Melhorando a apli... 3.2. Exibindo mensagens para o usuário Uma vez que o objetivo principal da aplicação foi concluído (i.e., listagem e edição de bookmarks), veremos algumas funcionalidades adicionais fornecidas pelo Demoiselle Framework, iniciando pelo tratamento de mensagens. Dentro do pacote br.gov.frameworkdemoiselle.sample.message crie a interface InfoMessages, a qual servirá para armazenar mensagens informativas a serem exibidas ao usuário: public interface InfoMessages { final Message BOOKMARK_DELETE_OK = new DefaultMessage("{bookmark-delete-ok}"); final Message BOOKMARK_INSERT_OK = new DefaultMessage("{bookmark-insert-ok}"); final Message BOOKMARK_UPDATE_OK = new DefaultMessage("{bookmark-update-ok}"); } Nota A unidade básica de manipulação de mensagens no Demoiselle Framework é a interface Message. Ou seja, basta que esta última seja implementada na aplicação para que o contexto de mensagens possa manipulá-la. A classe DefaultMessage é oferecida como implementação padrão dessa interface. No exemplo em questão, o texto das mensagens será recuperado do arquivo de recursos messages.properties previamente criado no diretório /src/main/resources/. Para isso, adicione as seguintes linhas nesse arquivo: bookmark-delete-ok=Bookmark exclu\u00EDdo\: {0} bookmark-insert-ok=Bookmark inserido: {0} bookmark-update-ok=Bookmark atualizado: {0} Dentro do pacote br.gov.frameworkdemoiselle.sample.business altere a classe BookmarkBC incluindo os trechos de código indicados a seguir: @BusinessController public class BookmarkBC extends DelegateCrud<Bookmark, Long, BookmarkDAO> { @Inject private MessageContext messageContext; ... @Override public void insert(Bookmark bookmark) { super.insert(bookmark); messageContext.add(InfoMessages.BOOKMARK_INSERT_OK, bookmark.getDescription()); } 22 Exibindo mensagens para o usuário @Override public void update(Bookmark bookmark) { super.update(bookmark); messageContext.add(InfoMessages.BOOKMARK_UPDATE_OK, bookmark.getDescription()); } @Override public void delete(Long id) { super.delete(id); messageContext.add(InfoMessages.BOOKMARK_DELETE_OK, id); } } No ponto contendo @Inject será injetado via CDI o contexto de mensagens presente na aplicação, ou seja, uma instância da interface MessageContext que poderá ser utilizada em qualquer método nessa classe. Aqui os métodos insert(), update() e delete() da classe DelegateCrud são sobrescritos para permitir com que o contexto de mensagens seja manipulado em cada invocação destes. O método add() de MessageContext faz com que a mensagem passada como parâmetro seja adicionada ao contexto, que ao final será exibida para o usuário na camada de apresentação. Nota O contexto de mensagens, representado pela interface MessageContext, é capaz de armazenar diversas mensagens em uma mesma requisição. Ele não é restrito à aplicações do tipo Web, isto é, pode ser usado também para aplicações do tipo desktop (i.e., Swing). Ao término das modificações propostas até aqui, reconstrua o projeto Java e faça novo deploy no servidor de aplicações. Acesse a aplicação bookmark e efetue inclusões, modificações e exclusões de bookmarks. As mensagens informativas devem aparecer em caixas de mensagens na tela, tal como ilustrado a seguir: 23 Capítulo 3. Melhorando a apli... Figura 3.2. Exibição de mensagens na aplicação Bookmark 3.3. Criando regras de validação nos campos Sendo aderente à especificação Java EE 6, o Demoiselle Framework recomenda e faz uso do mecanismo de validação provido pela especificação JSR-303 (Bean Validation) [http://jcp.org/en/jsr/detail?id=303]. A fim de testarmos mais essa funcionalidade, utilizaremos a implementação de validação Hibernate Validator. Para tal, abra o arquivo pom.xml do projeto bookmark e inclua nele a seguinte dependência: <dependencies> ... <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>4.1.0.Final</version> </dependency> </dependencies> Nota O objetivo dessa abordagem de validação é auxiliar na criação de restrições diretamente nas entidades de domínio. Tais restrições serão utilizadas de forma conjunta nas camadas de persistência e apresentação da aplicação. A vantagem é que elas são facilmente configuráveis, 24 Criando regras de validação nos campos bastando apenas incluir certas anotações (ex: @NotNull, @Size) nos campos da classe a ser validada. No pacote br.gov.frameworkdemoiselle.sample.domain altere a entidade de domínio Bookmark incluindo as anotações de validação nos campos description e link conforme ilustrado a seguir: @Entity public class Bookmark { @Id @GeneratedValue private Long id; @Column @NotNull @Size(min = 1, max = 20) private String description; @Column @NotNull @NotBlank @Size(max = 255) @URL private String link; ... } No campo description, a anotação @NotNull serve para impedir que o valor nulo seja atribuído a ele. Já a anotação @Size restringe a quantidade mínima e máxima de caracteres no campo. No campo link mais restrições são aplicadas. Além de não permitir o valor nulo (com @NotNull) e estipular o comprimento máximo de 255 caracteres (com @Size), o campo não pode ficar vazio (com @NotBlank) e seu conteúdo deve ser um endereço de Internet válido (com @URL). Dica Validações de campos específicos para a comunidade brasileira são oferecidos pelo componente Demoiselle Validation. Com ele, as seguintes anotações podem ser aplicadas nas classes de domínio: @Cep, @Cnpj, @Cpf, @InscricaoEstadual e @PisPasep. Assim que você efetuar as modificações, reconstrua o projeto Java e faça novo deploy no servidor de aplicações. Acesse a aplicação bookmark e, na tela de edição de bookmarks, deixe vazios os campos no formulário e clique em Salvar. Tente também preencher um endereço de Internet inválido no campo Link. Caixas de erro com as mensagens referentes as validações devem aparecer ao lado de cada campo, tal como ilustrado: 25 Capítulo 3. Melhorando a apli... Figura 3.3. Validação de campos na aplicação Bookmark Dica As mensagens exibidas na tela durante a validação estão contidas no arquivo de recursos ValidationMessages.properties presente no diretório /src/main/resources/. 26