9 de jan de 2013

Criando Componentes com JSF 2.1 + Facelets


A versão do JSF usada neste exemplo foi o apache myfaces 2.1. Caso você esteja usando uma versão diferente pode haver alguma classe que esteja definida em outro pacote ou até mesmo com outro nome.

Vamos criar o componente <textoComum id="clientId" valor="TEXTO" /> que simplesmente escreve o texto definido no atributo 'valor'  dentro da tag html span:    <span id=clientId >TEXTO</span>



Crie uma classe que extenda javax.faces.component.UIComponentBase. Você deve sobrescrever o método encodeBegin que se encarrega de renderizar o componente.

package test.components;

import java.io.IOException;

import javax.faces.component.UIComponentBase;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;

public class TextoComum extends UIComponentBase {
    public static final String COMPONENT_FAMILY = "test.components";

    @Override
    public void encodeBegin(FacesContext context) throws IOException {
        ResponseWriter writer = context.getResponseWriter();
        String clientId = getClientId(context);
        String valor = (String) getAttributes().get("valor");
        writer.startElement("span", this);
        writer.writeAttribute("id", clientId, "id");
        writer.write(valor);  
        writer.endElement("span");
    }

    @Override
    public String getFamily() {
        return COMPONENT_FAMILY;
    }
}

Para registrar a classe acima como um componente inclua no arquivo faces-config.xml o seguinte:

<component>
    <component-type>test.components.TextoComum</component-type>
    <component-class>test.components.TextoComum</component-class>
</component>
Você também pode usar a anotação @FacesComponent para registrar a classe como componente:

@FacesComponent("test.components.TextoComum")
public class TextoComum extends UIComponentBase {
    . . .
}

A precedência da configuração em xml é maior do que em anotações então se você usar ambas o xml irá prevalecer.

Depois você deve definir a tag do componente  em um arquivo xml. Essa será a tag usada nas views (páginas xhtml). Crie o arquivo test.taglib.xml na pasta WEB-INF:

<?xml version="1.0" encoding="UTF-8"?>
<facelet-taglib 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/web-facelettaglibrary_2_0.xsd"
    version="2.0">
    <namespace>http://br.com.test</namespace>
    
    <tag>
        <tag-name>textoComum</tag-name>
        <component>
            <component-type>test.components.TextoComum</component-type>
        </component>
    
        <attribute>
            <name>id</name>
            <required>false</required>
            <type>java.lang.String</type>
        </attribute>
    
        <attribute>
            <name>valor</name>
            <required>true</required>
            <type>java.lang.String</type>
        </attribute>
    </tag>
 
</facelet-taglib>
Este arquivo é o descritor da sua taglib. Você pode adicionar outras tags nesse mesmo arquivo.

Para carregar as definições de suas tags você deve adicionar o <context-param>  javax.faces.FACELETS_LIBRARIES no web.xml da aplicação:

<context-param>
    <param-name>javax.faces.FACELETS_LIBRARIES</param-name>
    <param-value>/WEB-INF/test.taglib.xml</param-value>
</context-param>

para incluir mais de um arquivo xml com as definições das tags você deve separar os caminhos com ponto e vírgula.

Agora você pode usar a tag que acabou de criar em suas views. Veja como deve ficar a página teste.xhtml para usar a tag textoComum:

<!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:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:test="http://br.com.test">
<h:head>
</h:head>
<h:body>
    <test:textoComum valor="DEU CERTO!!!" />
</h:body>
</html>

Um pouco mais de recursos


É possível incluir automaticamente arquivos como css e javascript no xhtml onde você usar o componente . Para isso existe a anotação @ResourceDependency que indica quais arquivos devem ser incluídos quando o componente for renderizado. Os arquivos incluídos com essa anotação devem ficar na pasta SuaAplicacao/resources. Você pode por exemplo incluir o javascript do jquery e renderizar um script que usa o jquery para fazer alguma coisa especifica do seu componente. Bibliotecas de componentes como o Primefaces utilizam esse recurso, encapsulando alguns plugins do jquery como componentes JSF. Abaixo é mostrado como deve ser usada a anotação @ResourceDependency:

@ResourceDependencies({
    @ResourceDependency(library = "jquery", name = "jquery.js")
})
public class TextoComum extends UIComponentBase {
    public static final String COMPONENT_FAMILY = "test.components";

    @Override
    public void encodeBegin(FacesContext context) throws IOException {
        ResponseWriter writer = context.getResponseWriter();
        String clientId = getClientId(context);
        String valor = (String) getAttributes().get("valor");
        writer.startElement("span", this);
        writer.writeAttribute("id", clientId, "id");
        writer.write(valor);
        writer.endElement("span");
        writer.startElement("script", this);
        writer.writeAttribute("id", clientId + "_s", null);
        writer.writeAttribute("type", "text/javascript", null);
  
        writer.write("$(function() {");
        String separatorChar = Character.toString(UINamingContainer.getSeparatorChar(context));
        String componentIdSelector = "'#" + clientId.replace(separatorChar, "\\\\:") + "'";
        writer.write("$(" + componentIdSelector + ").css('color', 'red');");
  
        writer.write("});");
  
        writer.endElement("script");
    }

    @Override
    public String getFamily() {
        return COMPONENT_FAMILY;
    }

}

Na classe acima o jquery é usado para alterar a cor do texto gerado para vermelho. O arquivo jquery.js deve estar na pasta /resources/jquery.

Nenhum comentário:

Postar um comentário