Tutorial Facelets
Olá a todos, este é o primeiro tutorial que aborda o assunto de Facelets aqui no JavaWora. Acredito que todos que gostam de Java Server Faces estão super acostumados com a tecnologia, mas aqueles que usavam Struts e html puro, uma vez no mundo do JSF, uma das principais dificuldades (contornáveis é claro) era compreender a lógica das tags que de certa forma se distância do HTML convencional, o que eu até discordo em partes, afinal acho que um <html:text/> não se aproxima tanto de <input type=”text”/>, mas tudo bem, sabemos que da mesma forma aprender Struts não é uma tarefa das mais fáceis. Enfim vamos ao que interessa.
Um dos pontos que mais desagrada empresas que vão utilizar JSF é a distância do HTML convencional, portanto uma dificuldade de que designers possam efetuar atualizações, manutenções e coisas do gênero em uma página, pois bem, para “simplificar” toda essa dificuldade, foi desenvolvido uma tecnologia chamada de Facelets, aqueles que já viram o Tapestry verão muitas semelhanças, apontada como uma das inspiradoras para o Facelets.
No Tapestry utilizávamos a palavra chave jwcid (Java Web Component Id), para que o Framework substituísse aquele conteúdo por um componente desejado, e eis que apresento a palavra mágica do Facelets: jsfc (Java Server Faces Component). Não se engane isso não é uma cópia descarada, mas uma inspiração do primo de JSF, mas qual a mágica de tal palavrinha no caso de Facelets?O que ganhamos com isso?
Imagine o seguinte, você recebe a pagina HTML do designer, e você tem que alterar tudo aquilo, porque é tudo diferente do que você usa. Seus problemas acabaram! Basta você por uma palavrinha mágica em componentes, por exemplo:
<input type=”text”/>
Adicione:
<input type=”text” jsfc=”h:inputText” value=”#{cadastro.nome}”/>
Mágico, não acham? Um reaproveitamento de código maravilhoso e louvável. Outro ponto que nos interessa em reaproveitamento é a criação de um template, tiles é um bom framework mas deixa a desejar em alguns pontos. Com Facelets podemos definir um template declarativamente, de forma que a página sabe em qual template está inserida, reduzindo o esforço para descobrir seus componentes.
Para criar um template apenas devemos assinar os componentes da página por meio de <ui:insert name="menu"> dentre as tags do facelets, caso queiramos inserir o conteúdo de um html naquele tag na página que define o template, utilizamos então: <ui:include src="/templates/menu.xhtml"/>. No momento em que vamos utilizar um determinado template numa página, basta declará-lo: <ui:composition template="/templates/common.xhtml">, e inserir o que estmos sobrescrevendo por meio de <ui:define name="body">conteúdo</ui:define> no espaço delimitado pelas tags em conteúdo. Mais uma vez, simples, muito simples. O Facelets ainda possui componentização, Ájax integrado, dentre outras funcionalidades, mas vamos nos focar no core aqui, que é templates e reaproveitamento de html original.
O suporte de IDES ao Facelets ainda é fraco, o NetBeans possui um suporte, já no universo eclipse, temos o Exadel e agora o novíssimo Red Hat Developer Studio, os melhores na minha opinião. O exemplo deste tutorial foi desenvolvido com a implementação da Sun e no tomcat 5.5, no tomcat 6 algumas mudanças são necessárias. Os jars necessários são:
- common-annotations.jar
- commons-beanutils.jar
- commons-collections.jar
- commons-digester.jar
- commons-logging.jar
- el-api.jar
- el-ri.jar
- jsf-api.jar
- jsf-facelets.jar
- jsf-impl.jar
- jsf-tlds.jar
- jstl.jar
- standard.jar
O web-xml necessário está na Figura 1. Criaremos três Classes para nossa lógica, são elas:
package br.com.facelets.bean; public class Login { private String userName; private String senha; public Login() { } //sets e gets omitidos @Override public int hashCode() { final int PRIME = 31; int result = 1; result = PRIME * result + ((senha == null) ? 0 : senha.hashCode()); result = PRIME * result + ((userName == null) ? 0 : userName.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; final Login other = (Login) obj; if (senha == null) { if (other.senha != null) return false; } else if (!senha.equals(other.senha)) return false; if (userName == null) { if (other.userName != null) return false; } else if (!userName.equals(other.userName)) return false; return true; } } |
package br.com.facelets.bean; import javax.faces.context.FacesContext; import br.com.facelets.business.CadastroSaver; public class Cadastro { private String nome; private String senha; private String userName; public String getLogin() { return userName; } public void setLogin(String login) { this.userName = login; } //sets e gets omitidos public String salvar(){ Login login = new Login(); login.setUserName(userName); login.setSenha(senha); CadastroSaver.salvar(login, this); return "ok"; } public String logar(){ Login login = new Login(); login.setUserName(userName); login.setSenha(senha); Cadastro cadastro = CadastroSaver.busca(login); if(cadastro!=null){ FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("user", cadastro); return "ok"; }else{ FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put("erro", "login/senha inválidos"); return "erro"; } } } |
package br.com.facelets.business; import java.util.Hashtable; import br.com.facelets.bean.Cadastro; import br.com.facelets.bean.Login; public class CadastroSaver { private static final Hashtable public static void salvar(Login login,Cadastro cadastro){ saver.put(login, cadastro); } public static Cadastro busca(Login login){ return saver.get(login); } } |
E agora o faces-config e as páginas propriamente ditas.
<?xml version="1.0" encoding="UTF-8"?> <faces-config version="1.2" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xi="http://www.w3.org/2001/XInclude" 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/web-facesconfig_1_2.xsd"> <managed-bean> <managed-bean-name>cadastro</managed-bean-name> <managed-bean-class>br.com.facelets.bean.Cadastro</managed-bean-class> <managed-bean-scope>request</managed-bean-scope> <managed-property> <property-name>nome</property-name> <property-class>java.lang.String</property-class> <value/> </managed-property> <managed-property> <property-name>login</property-name> <property-class>java.lang.String</property-class> <value/> </managed-property> </managed-bean> <navigation-rule> <from-view-id>/pages/dados.xhtml</from-view-id> <navigation-case> <from-outcome>ok</from-outcome> <to-view-id>/pages/inputname.xhtml</to-view-id> <redirect/> </navigation-case> </navigation-rule> <navigation-rule> <from-view-id>/pages/login.xhtml</from-view-id> <navigation-case> <from-outcome>ok</from-outcome> <to-view-id>/pages/greeting.xhtml</to-view-id> <redirect/> </navigation-case> <navigation-case> <from-outcome>erro</from-outcome> <to-view-id>/pages/login.xhtml</to-view-id> </navigation-case> </navigation-rule> <application> <view-handler>com.sun.facelets.FaceletViewHandler</view-handler> <resource-bundle> <base-name>resources</base-name> <var>msg</var> </resource-bundle> <message-bundle>resources</message-bundle> </application> </faces-config> |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"> <body bgcolor="#ffffff"> <table style="border:1px solid #CAD6E0" align="center" cellpadding="0" cellspacing="0" border="0"> <tbody> <tr> <td colspan="2" valign="bottom" height="1" bgcolor="#CAD6E0"> <table> <tr> <td> <a href="dados.jsf">Incluir dados</a> </td> </tr> <tr> <td> <a href="login.jsf">Login</a> </td> </tr> </table> </td> </tr> </tbody> </table> </body> </html> |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"> <span jsfc="f:loadBundle" basename="resources" var="msg"/> <head> <title> <ui:insert name="pageTitle">JavaWora</ui:insert> </title> <style type="text/css"> body { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14px; } .header { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 18px; } .bottom { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 9px; text-align: center; vertical-align: middle; color: #8E969D; } </style> </head> <body bgcolor="#ffffff"> <table style="border:1px solid #CAD6E0" align="center" cellpadding="0" cellspacing="0" border="0" width="400"> <tbody> <tr> <td class="header" align="center" valign="middle" width="100%" bgcolor="#E4EBEB"> <ui:insert name="pageHeader">JavaWora Facelets</ui:insert> </td> </tr> <tr> <td height="1" width="100%" bgcolor="#CAD6E0"></td> </tr> <tr> <td width="100%"> <table width="100%" style="height:150px" align="left" cellpadding="0" cellspacing="0" border="0"> <tbody> <tr> <td align="center" width="10%" valign="middle"> <ui:insert name="menu"> <ui:include src="/templates/menu.xhtml"/> </ui:insert> </td> <td align="center" width="75%" valign="middle"> <ui:insert name="body">Page Body</ui:insert> </td> </tr> </tbody> </table> </td> </tr> <tr> <td colspan="2" valign="bottom" height="1" width="100%" bgcolor="#CAD6E0"></td> </tr> </tbody> </table> </body> </html> |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" template="/templates/common.xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" /> <title>Cadastro</title> </head> <ui:define name="body"> <form jsfc="h:form" id="cadastro"> <table> <tr> <td>Nome*:</td> <td> <input type="text" jsfc="h:inputText" value="#{cadastro.nome}" id="nome" label="#{msg.lbl.nome}" required="true" requiredMessage="#{msg.erroRequired}"/> </td> <td><h:message for="nome" id="erroNome"></h:message> </td> </tr> <tr> <td>login*:</td> <td> <input type="text" jsfc="h:inputText" value="#{cadastro.login}" id="login" label="#{msg.lbl.login}" required="true" requiredMessage="#{msg.erroRequired}"/> </td> <td><h:message for="login" id="erroLogin"></h:message> </td> </tr> <tr> <td>senha*:</td> <td> <input type="text" jsfc="h:inputSecret" value="#{cadastro.senha}" id="senha" label="${msg.lbl.senha}" required="true" requiredMessage="#{msg.erroRequired}"/> </td> <td><h:message for="senha" id="erroSenha"></h:message> </td> </tr> <tr> <td>Estado Civil:</td> <td> <select jsfc="h:selectOneMenu" value="#{cadastro.idEstado}" id="eCivil" label="#{msg.lbl.estadoCivil}"> <option jsfc="f:selectItem" itemValue="1" itemLabel="Casado"></option> <option jsfc="f:selectItem" itemValue="2" itemLabel="Solteiro"></option> <option jsfc="f:selectItem" itemValue="3" itemLabel="Divorciado"></option> </select> </td> </tr> <tr> <td colspan="2" align="center"> <input type="submit" value="Salvar" jsfc="h:commandButton" action="#{cadastro.salvar}"/> </td> </tr> </table> </form> </ui:define> </ui:composition> |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:c="http://java.sun.com/jstl/core"> <ui:composition template="/templates/common.xhtml"> <ui:define name="pageTitle"> Bem Vindo </ui:define> <ui:define name="pageHeader"> Home </ui:define> <ui:define name="body"> ${msg.prompt} </ui:define> </ui:composition> </html> |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"> <f:loadBundle basename="resources" var="msg" /> <ui:composition template="/templates/common.xhtml"> <ui:define name="body"> #{msg.greeting} <span jsfc="h:outputLabel" value="#{sessionScope.user.nome}"/>! </ui:define> </ui:composition> </html> |
Experimente abrir a pagina de login no firefox, ie, ou qualquer ferramenta WYSIWYG (acho q é isso) e veja que os parametros estão lá, até a pagina, mas como isso é possível? Ora como eu disse trata-se de uma página simples xhml, a propósito podemos trabalhar com xhtml diretamente em facelets, ou mesmo jsps, mas xhtml é mais legal. A aplicação consiste em efetuar um cadastro e logo após um login para verificar se os dados foram armazenados. |
O compilador descreve o erro e lhe auxilia com a arvores de componentes gerada e os dados do que estavam presentes. Legal né! Pois agora troque a sentença para false. Você verá que o erro agora é apresentado como na figura 3. Bonito não?!
Obrigado e até mais!
10 comentários:
14/9/07
Onde posso baixar os jar, necessarios para o Tomcat 6????
14/9/07
Estou utilizando a implementação da Apache, o myfaces.
17/9/07
trabalhar com o myfaces e o facelts requer algumas alterações.
Primeiro para o caso de usar Tomcat 6 retire o jar "el-api".
Para usar com o myfaces, a lista de jars altera um pouco:
-commons-annotations
-commons-beanutils
-commons-codec
-commons-collections
-commons-digester
-commons-el
-commons-fileupload
-commons-lang
-commons-logging
-el-ri
-jsf-facelets
-jstl
-myfaces-api
-myfaces-impl
E finalmente o web.xml deve ser alterado para os parâmetros do myfaces.
29/11/07
Amigo,
Pq vc não inclui as tags abaixo no seu web.xml?
[context-param]
[param-name]javax.faces.CONFIG_FILES[/param-name]
[param-value]/WEB-INF/faces-config.xml[/param-value]
[/context-param]
30/11/07
Por default ele busca um arquivo faces-config.xml, com esse mesmo nome, caso não encontre declarativamente no web.xml, ou seja é desnecessário quando se usa apenas um arquivo de configuração do faces.
16/5/08
Excelente post! Atualmente estamos com uma enorme carência de blogs nacionais sobre JavaServer Faces. Tutoriais e how-to's são um ótimo começo de difundir esta tecnologia.
Só uma coisa, o código do post meio complicado de ler, talvez se você utilizasse algum plugin para formatar códigos ficaria bem melhor de ler.
Enfim, parabéns!
30/9/08
Bom dia Alexandre.
Li o tutorial e segui a receita passo-a-passo para fazer rodar a aplicação, mas estou tendo problemas quando tento executar estou recebendo tendo esta exception:
SEVERE: Missing Built-in Tag Libraries! Make sure they are included within the META-INF directory of Facelets' Jar
07:57:27,050 ERROR [STDERR] Sep 30, 2008 7:57:27 AM com.sun.facelets.FaceletViewHandler handleRenderException
SEVERE: Error Rendering View[/pages/inputname.xhtml]
java.lang.NullPointerException
at com.sun.facelets.compiler.NamespaceHandler.apply(NamespaceHandler.java:49)
at com.sun.facelets.compiler.EncodingHandler.apply(EncodingHandler.java:25)
at com.sun.facelets.impl.DefaultFacelet.apply(DefaultFacelet.java:95)
at com.sun.facelets.FaceletViewHandler.buildView(FaceletViewHandler.java:510)
at com.sun.facelets.FaceletViewHandler.renderView(FaceletViewHandler.java:553)
at org.ajax4jsf.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:108)
at org.ajax4jsf.application.AjaxViewHandler.renderView(AjaxViewHandler.java:189)
at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:106)
at com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:251)
at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:144)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:245)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:630)
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:436)
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:374)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:302)
at org.apache.jasper.runtime.PageContextImpl.doForward(PageContextImpl.java:694)
at org.apache.jasper.runtime.PageContextImpl.forward(PageContextImpl.java:665)
at org.apache.jsp.index_jsp._jspService(index_jsp.java:59)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:369)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:337)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:266)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:189)
at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:90)
at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:96)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:157)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:309)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:601)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
at java.lang.Thread.run(Unknown Source)
Tem alguma ideia do que eu não fiz para receber esta Exception?
Abraços,
Marcelo.
30/9/08
Veja se a lista de jars corresponde ao que eu informei.
E observe bem como está o web.xml, e se o faces-config também está devidamente configurado.
21/12/08
Seria muito bom se colocasse pra download o WAR do projeto e/ou os arquivos para download.
14/8/09
Interessante....
Estou utilizando o facelets hoje em dia no meu trabalho ( 14 agosto 2009 ) e estou começando a gostar dele...
Mas tenho que admitir que sem sombra de dpúvidas.. ainda fico com o Apache Wicket ( http://wicket.apache.org/ ).
Parabéns pelo tutorial... facilitou o início no desenvolvimento com facelets.
Postar um comentário