JSF 2 fu: Assistentes JSF

Implemente um assistente com JSF 2 e CDI

Nesta parte de JSF 2 fu, você verá como combinar JSF 2 com Contexts and Dependency Injection (CDI) para implementar um assistente Ajaxified. Você verá modelos de JSF e Ajax em ação e saberá como usar o escopo de conversação e injeção de dependência de CDI.

David Geary, President, Clarity Training, Inc.

David GearyO autor, palestrante e consultor David Geary é o presidente da Clarity Training, Inc. onde ensina desenvolvedores a implementarem aplicativos da Web usando JSF e Google Web Toolkit (GWT). Ele fez parte dos Grupos de Especialistas do JSTL 1.0 e do JSF 1.0/2.0, foi coautor do Exame de Certificação de Desenvolvedor da Web da Sun e contribuiu para projetos de software livre, incluindo o Apache Struts e o Apache Shale. Graphic Java Swing de David foi um dos livros de Java mais vendidos de todos os tempos e Core JSF (coescrito com Cay Horstman) é o livro de JSF mais vendido. David fala frequentemente em conferências e para grupos de usuários. É frequentador assíduo do tour de NFJS desde 2003, deu cursos na Java University e foi duas vezes votado como JavaOne rock star.



29/Set/2010

Java™ Enterprise Edition (Java EE) 6 inclui muitas tecnologias poderosas, incluindo JSF 2. Uma dessas tecnologias, Contexts and Dependency Injection (CDI), padroniza de muitas formas os conceitos cultivados por anos em outras estruturas.

Neste artigo, mostrarei como combinar JSF 2 e CDI para implementar um assistente para todos os tipos de quiz realizados on-line. CDI me fornece injeção de dependência, métodos de produtor e um escopo de conversação. Eu usarei os três para implementar um assistente que possa ser usado facilmente por qualquer quiz on-line de múltipla escolha.

Sobre esta série

A série JSF 2 fu, uma continuidade à introdução de três artigos de David Geary com o mesmo nome, permitirá que você desenvolva e aprimore suas habilidades em estrutura JSF 2 como um mestre em kung fu. A série atual busca uma visão mais aprofundada da estrutura e de seu ecossistema circunvizinho. E oferece uma visão não convencional que mostra como algumas tecnologias Java EE, como Contextos e Injeção de Dependência, se integram com o JSF.

Entretanto, este artigo não se trata apenas de CDI. Mostrarei como:

  • Usar modelos de facelets para minimizar o código e maximizar a reutilização
  • Transformar assistentes em Ajax para uma experiência mais tranquila do usuário
  • Usar a injeção de dependência de CDI para simplificar o código
  • Implementar e usar métodos do produtor de CDI para usar beans com perfeição em suas visualizações
  • Aproveitar as vantagens do escopo de conversação de CDI para implementar casos de uso de solicitação múltipla

O código de origem completo para os exemplos do artigo estão disponíveis para download. Consulte a barra lateral Running the sample code para um link de download e um ponteiro a fim de obter instruções de implementação.

O assistente de quiz

A Figura 1 mostra o assistente de quiz em ação:

Figura 1. O assistente de quiz
O assistente de quiz

Inicialmente, o aplicativo contém um link isolado que inicia o assistente: <h:commandLink value="#{msgs.startWizard}" action="#{wizard.start}"/>. O texto do link (Start the wizard) vem com um arquivo de propriedades e é representado pela expressão msgs.startWizard no valor do link. A internacionalização é JSF 101 de cerca de 2004, portanto, não se preocupe com esses detalhes aqui. Observar que todo o aplicativo está localizado é o suficiente, portanto, todas as cadeias de caractere são obtidas do arquivo messages.properties.

Executando o código de amostra

O código desta série tem como base a execução de JSF 2 em execução em um contêiner corporativo, como GlassFish ou Resin. Consulte a primeira parte da série, "JSF 2 fu: componentes Ajax" para um tutorial passo a passo sobre a instalação e a execução do código para esta série com GlassFish. Consulte Download para obter o código de amostra deste artigo.

O link Start the wizard leva os usuários à página do assistente de quiz, aos quais são apresentadas perguntas, uma por vez, como mostrado nas duas imagens na parte inferior em Figura 1. Eu controlo o estado ativo dos botões do assistente por meio de Ajax simples e um bean de servidor, como lhe mostrarei na seção O Ajax deste artigo.

A Figura 2 mostra a última pergunta, seguida por um resumo das respostas do usuário. O botão Finish ficará ativo apenas quando o usuário estiver na última pergunta; clicar nesse botão leva o usuário à página de resumo.

Figura 2. A página de resumo
A página de resumo

Agora que você sabe como o assistente de quiz funciona, mostrarei como ele é implementado.


O aplicativo de quiz

Os arquivos do aplicativo de quiz são mostrados na Figura 3:

Figura 3. Os arquivos do aplicativo
Os arquivos do aplicativo

Implementei um assistente de quiz com um modelo JSF 2 (/templates/wizardTemplate.xhtml) usado pela visualização do assistente (/quizWizard/wizard.xhtml).

Além do modelo e da visualização, eu tenho facelets — tudo no diretório quizWizard — para cada uma das partes do assistente:

  • O cabeçalho (/quizWizard/heading.xhtml)
  • A pergunta (/quizWizard/question.xhtml)
  • Os botões de opções (quizWizard/choices.xhtml)
  • Os botões Next, Previous e Finish (quizWizard/controls.xhtml)

O facelet index.xhtml inicia o aplicativo com o link Start the wizard, e o facelet done.xhtml exibe um resumo das perguntas e das respostas.

É isso para o cliente. No servidor, o aplicativo tem três beans, dois dos quais vou abordar na sequência.


Os beans de pergunta do aplicativo

O bean Question, mostrado na Listagem 1, é na verdade uma pergunta, um conjunto de opções de resposta e uma resposta:

Listagem 1. O bean Question
package com.clarity;

import java.io.Serializable;

public class Question implements Serializable {
  private static final long serialVersionUID = 1284490087332362658L;

  private String question, answer;
  private String[] choices;
  private boolean answered = false; // next button is enabled when answered is true
  
  public Question(String question, String[] choices) {
    this.question = question;
    this.choices = choices;
  }

  public void setAnswer(String answer) {
    this.answer = answer;
    answered = true;
  }

  public String getAnswer()    { return answer;   }
  public String getQuestion()  { return question; }
  public String[] getChoices() { return choices;  }
  public boolean isAnswered()  { return answered; }

  public void setAnswered(boolean answered) { this.answered = answered; }  
}

O aplicativo também mantém um array de perguntas na classe Questions, o que é mostrado na Listagem 2:

Listagem 2. O bean Questions
package com.clarity;

import java.io.Serializable;

import com.corejsf.util.Messages;

public class Questions implements Serializable {
  private static final long serialVersionUID = -7148843668107920897L;

  private String question;
  private Question[] questions = {      
    new Question(
       Messages.getString("com.clarity.messages", "expandQuestion", null),
       new String[] { 
         Messages.getString("com.clarity.messages", "hydrogen", null),
         Messages.getString("com.clarity.messages", "helium", null),
         Messages.getString("com.clarity.messages", "water", null),
         Messages.getString("com.clarity.messages", "asphalt", null)
       }),
       
   new Question(
       Messages.getString("com.clarity.messages", "waterSGQuestion", null),
       new String[] { 
         Messages.getString("com.clarity.messages", "onedotoh", null),
         Messages.getString("com.clarity.messages", "twodotoh", null),
         Messages.getString("com.clarity.messages", "onehundred", null),
         Messages.getString("com.clarity.messages", "onethousand", null)
       }),
       
   new Question(
       Messages.getString("com.clarity.messages", "numThermoLawsQuestion", null),
       new String[] { 
         Messages.getString("com.clarity.messages", "one", null),
         Messages.getString("com.clarity.messages", "three", null),
         Messages.getString("com.clarity.messages", "five", null),
         Messages.getString("com.clarity.messages", "ten", null)
       }),
       
   new Question(
       Messages.getString("com.clarity.messages", "closestSunQuestion", null),
       new String[] { 
         Messages.getString("com.clarity.messages", "venus", null),
         Messages.getString("com.clarity.messages", "mercury", null),
         Messages.getString("com.clarity.messages", "mars", null),
         Messages.getString("com.clarity.messages", "earth", null)
       })         
  };
  
  public int size()                        { return questions.length; }
  public String getQuestion()              { return question; }
  public void setQuestion(String question) { this.question = question; }
  public Question[] getQuestions()         { return questions; }
}

Listagem 1 e Listagem 2 são imperceptíveis — elas simplesmente me fornecem uma lista de perguntas no servidor — exceto para o fato de que eu programaticamente obtenho cadeias de caracteres de um pacote configurável de recursos com um método auxiliar. É possível ver como o método funciona fazendo o download do código para este artigo, e você poderá ler sobre isso em Core JavaServer Faces (consulte Recursos).

É isso para beans de aplicativo, exceto para o bean Wizard, que atua como um controlador para o assistente. É onde o único código Java realmente interessante reside nesse aplicativo. Eu abordo o bean Wizard na seção CDI: injeção de dependência e conversações.

Agora que você está mais por dentro dos arquivos no aplicativo e os beans de pergunta, mostrarei como implementar a visualização do assistente.


O modelo e a visualização

Para a maioria dos assistentes, é possível generalizar com segurança a anatomia do assistente, como detalhado na Figura 4:

Figura 4. Anatomia do assistente
Anatomia do assistente

A Listagem 3 mostra o modelo que encapsula essa anatomia:

Listagem 3. O modelo do assistente (templates/wizardTemplate.xhtml)
<!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">

  <h:head>
    <title>
      <ui:insert name="windowTitle">
        #{msgs.windowTitle}
      </ui:insert>
    </title>
  </h:head>
  
  <h:body>  
    <h:outputStylesheet library="css" name="styles.css" target="head"/>       
    
    <ui:insert name="heading"/>
          
    <div class="wizardPanel">
    
      <div class="subheading">
        <ui:insert name="subheading"/>
      </div>
      
       <div class="work">
         <ui:insert name="work"/>
       </div>
       
      <div class="controls">
        <ui:insert name="controls"/>
      </div>
      
    </div>      
        
  </h:body>
</html>

A implementação específica do assistente de quiz é mostrada na Listagem 4:

Listagem 4. O facelet do assistente (quizWizard/wizard.xhtml)
<!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:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    template="/templates/wizardTemplate.xhtml">

  <ui:define name="heading">
    <ui:include src="heading.xhtml"/>
  </ui:define> 
  
  <ui:define name="subheading">
    <ui:include src="question.xhtml"/>
  </ui:define>
  
  <ui:define name="work">
    <ui:include src="choices.xhtml"/>
  </ui:define>
   
  <ui:define name="controls">
    <ui:include src="controls.xhtml"/>
  </ui:define> 

</ui:composition>

Os modelos são muito simples. Eles inserem seções de uma página definidas por uma visualização. Nesse caso, o modelo na Listagem 3 insere as seções heading, subheading, work e controls definidas pela exibição na Listagem 4. O encapsulamento de recursos comuns de visualizações em modelos torna mais fácil criar novas visualizações — nesse caso, novos tipos de assistentes.

A Listagem 5 mostra a seção heading do assistente de quiz:

Listagem 5. O heading (quizWizard/heading.xhtml)
<!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:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets">

      <div class="heading">
        #{msgs.quizTitle}
      </div>

</ui:composition>

A Listagem 6 mostra a seção subheading:

Listagem 6. O subheading (quizWizard/question.xhtml)
<!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.or g/1999/xhtml"
     xmlns:f="http://java.sun.com/jsf/core"
     xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets">

  <h:panelGrid columns="1" id="question">
    #{wizard.cursor+1}. #{questions[wizard.cursor].question}?
  </h:panelGrid>
    
</ui:composition>

Visualizar abstrações

A geração de modelos permite encapsular recursos que as visualizações compartilham, permitindo que você enfoque apenas as coisas que mudam entre as visualizações. O modelo de assistente, por exemplo, fornece o título da janela, uma folha de estilo e — por meio de elementos <div>— a estrutura geral de cada visualização. Devido a esse encapsulamento de recursos comuns, é possível implementar com facilidade novas visualizações apenas juntando as partes em uma página.

O modelo do assistente define a estrutura, mas não a aparência de uma visualização. A aparência é, além disso, encapsulada em CSS, proporcionando-lhe outro grau de liberdade com o qual é possível modificar o modelo básico de uma visualização.

O heading na Listagem 5 mostra o título do quiz, neste caso, Science Quiz, e o subheading na Listagem 6 mostra a pergunta. O wizard.cursor mencionado na Listagem 6 é um cursor (ou índice, se preferir) que aponta para a pergunta atual. Esse cursor é baseado em zero, portanto, #{wizard.cursor+1} exibe o número da pergunta, e #{questions[wizard.cursor].question} mostra a pergunta.

Agora que cuidamos das introduções, como geração de modelos e beans de servidor, eu lhe mostrarei o que é realmente interessante: como o Ajax do assistente é implementado e como o assistente usa CDI. Primeiro, o Ajax.


O Ajax

Toda a interação do usuário no assistente de quiz resulta em chamadas Ajax, e somente as seções apropriadas da página são renderizadas quando essas chamadas retornam. Uma coisa que as chamadas Ajax fazem é controlar o estado de ativação dos botões do assistente. A Figura 5 mostra o estado de ativação dos botões do assistente durante a primeira pergunta e a segunda pergunta:

Figura 5. Os botões do assistente de quiz
Os botões do assistente de quiz

Clique para ver a imagem maior

Figura 5. Os botões do assistente de quiz

Os botões do assistente de quiz

O Ajax do assistente está nitidamente encapsulado em dois arquivos de facelet. A Listagem 7 mostra choices.xhtml:

Listagem 7. As opções
<!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:f="http://java.sun.com/jsf/core"
     xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets">
       
  <h:form id="choices">
    <h:panelGrid columns="2">  
        <h:selectOneRadio value="#{questions[wizard.cursor].answer}"
                         layout="pageDirection">
          <f:selectItems value="#{questions[wizard.cursor].choices}"/>
          <f:ajax render=":buttons"/>
        </h:selectOneRadio>
     </h:panelGrid>
  </h:form> 
    
</ui:composition>

Quando o usuário seleciona um botão de opções, JSF faz uma chamada Ajax ao servidor e registra a seleção do botão de opções (a resposta da pergunta) em uma propriedade backing-bean. Quando a chamada retorna, JSF atualiza os botões do assistente.

A Listagem 8 mostra controls.xhtml:

Listagem 8. Os controles
<!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:f="http://java.sun.com/jsf/core"
     xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets">

    <h:form id="buttons">
   
        <h:panelGrid columns="4" styleClass="wizardControls">
        <f:ajax render=":question :choices buttons">

            <h:commandButton id="next" 
                        styleClass="wizardButton"
                             value="#{msgs.nextButtonText}" 
                          disabled="#{not wizard.nextButtonEnabled}"/> 
                    actionListener="#{wizard.nextButtonClicked}"/>
      
            <h:commandButton id="previous"
                        styleClass="wizardButton"
                             value="#{msgs.previousButtonText}" 
                          disabled="#{not wizard.previousButtonEnabled}"
                    actionListener="#{wizard.previousButtonClicked}"/>
        </f:ajax>
                                                              
        <h:commandButton id="finish"
                    styleClass="wizardButton"
                         value="#{msgs.finishButtonText}" 
                      disabled="#{not wizard.finishButtonEnabled}"
                        action="#{wizard.end}"/>
                                                                      
        </h:panelGrid>
        
    </h:form>
</ui:composition>

Quando o usuário clica nos botões Next ou Previous, JSF faz uma chamada Ajax ao servidor e, quando a chamada Ajax retorna, JSF atualiza a pergunta, as opções da pergunta (o botão de opções) e os próprios botões.

O botão Finish não é um botão Ajax porque clicar nele leva para a página done.

Observe as inúmeras referências nas Listagens 7 e 8 ao bean wizard. Esse bean é de fato um controlador para o assistente de quiz. Vou concluir este artigo dando uma olhada nesse bean.


CDI: injeção de dependência e conversações

CDI pode ser descrito como beans gerenciados por JSF anabolizados. Como um componente de Java EE 6, CDI é de muitas formas uma padronização de conceitos cultivados em Spring há bastante tempo, como injeção de dependência e interceptores. De fato, CDI e Spring 3 compartilham muitos recursos similares.

CDI permite dividir as preocupações no que ele se refere como loose coupling e strong typing. Fazendo isso, ele proporciona um escape praticamente de libertação das banalidades da programação diária em Java, como a instanciação de objetos e o controle dos seus tempos de vida.

A partir de uma perspectiva de JSF, um recurso especialmente atraente do CDI é o escopo de conversão. Desenvolvido por Seam, o escopo de conversão é um escopo com um tempo de vida controlado programaticamente, que permite escapar da opção sem saída entre solicitação e sessão.

Todo o uso de CDI pelo assistente está no bean Wizard, mostrado na Listagem 9:

Listagem 9. O bean Wizard
package com.clarity;

import java.io.Serializable;

import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.enterprise.inject.Produces;
import javax.faces.event.ActionEvent;
import javax.inject.Inject;
import javax.inject.Named;

@Named()
@ConversationScoped()
public class Wizard implements Serializable {
  private static final long serialVersionUID = 1L;
  private Questions questions = new Questions();
  private int cursor = 0;
  
  @Inject
  private Conversation conversation;@Produces @Named
  public Question[] getQuestions() {
    return questions.getQuestions();
  }
  
  public void nextButtonClicked(ActionEvent e) {
    incrementCursor();
  }

  public void previousButtonClicked(ActionEvent e) {
    decrementCursor();
  }
    
  public void incrementCursor() { ++cursor; }
  public void decrementCursor() { --cursor; }
  public int  getCursor()       { return cursor; }
  public void resetCursor()     { cursor = 0; }

  public boolean getNextButtonEnabled() {
    return cursor != questions.size() - 1 &&
    (questions.getQuestions())[cursor].isAnswered();
  }
  
  public boolean getPreviousButtonEnabled() {
    return cursor > 0;
  }
  
  public boolean getFinishButtonEnabled() {
    return cursor == questions.size() - 1 &&
    (questions.getQuestions())[cursor].isAnswered();
  }
  
  public String start() {
    conversation.begin();
    return "quizWizard/wizard";
  }
  
  public String end() {
    conversation.end();
    return "/done";
  }
  
  private void setCurrentQuestionUnanswered() {
    Question currentQuestion = (questions.getQuestions())[cursor];
    currentQuestion.setAnswered(false);    
  }
}

Praticamente, todo o código interessante do aplicativo do assistente de quiz reside na Listagem 9. Primeiro, o bean Wizard tem métodos que controlam o estado de ativação dos botões do assistente, como eu mencionei na seção anterior. Ele também tem os métodos chamados por JSF quando o usuário clica nos botões Next ou Previous. Esses métodos avançam para a próxima pergunta ou voltam para a anterior, respectivamente.

Mas, aparentemente, a coisa mais interessante sobre o bean Wizard é o seu uso do CDI. Primeiro, como tenho feito em toda esta série, estou usando a implementação de CDI da anotação @Named (que é na verdade definida por JSR 330, injeção de dependência para Java) no lugar de @ManagedBean. As duas anotações criam um bean com escopo que pode ser acessado pela linguagem de expressão JSF. Mas o recurso de bean gerenciado de CDI é muito mais sofisticado, portanto, se estiver usando um servidor compatível com Java EE 6, escolha @Named em vez de @ManagedBean.

Se observar com mais atenção a Listagem 6 e a Listagem 7, verá que estou acessando um bean denominado questions na linguagem de expressão JSF. Você poderá também se lembrar de que implementei uma classe Questions na Listagem 2. Entretanto, não será possível ver uma anotação @Named na Listagem 2. Em circunstâncias normais, essa falta de anotação produzirá um erro, mas, neste caso, o bean questions vem de outro lugar — ele é produzido pelo método Wizard.getQuestions(). Esse método é anotado com uma anotação @Produces, o que significa que JSF chama esse método para obter o bean Questions quando for feita referência ao bean na linguagem de expressão.

Em seguida, há o uso do escopo de conversação do bean Wizard. O link Start the wizard na página de boas-vindas do aplicativo é vinculado ao método start() do bean Wizard, que inicia uma conversação chamando o método begin() de conversation. Esse método promove a solicitação atual (que é na verdade uma conversação que dura por uma única solicitação) para uma conversação de longa duração que não será finalizada até o seu tempo limite ser atingido ou alguém chamar o método end() de conversation. Como eu especifiquei o escopo de Conversation para Wizard, seu tempo de vida terminará quando a conversação terminar.

Você poderá, claro, fugir do escopo de conversação e implementar seu próprio escopo de pseudoconversação na sessão do usuário. De fato, é exatamente o que muitos desenvolvedores fizeram antes do escopo de conversação para manter o estado dos casos de uso com várias solicitações em seus aplicativos. CDI tira essa tarefa burocrática manual de suas mãos.

Para terminar, observe que estou usando a injeção de CDI para injetar uma conversação no bean gerenciado, portanto, posso iniciar programaticamente o início e o término de uma conversação. A injeção de recurso permite que eu me concentre em fazer coisas com objetos, em vez de me preocupar com detalhes banais de criá-los e controlar seus tempos de vida.


Conclusão

Neste artigo, falei de bastante coisa — assistentes Ajax, modelos, injeção de dependência, escopo de conversação — surpreendentemente com pouco código. Com a ajuda de JSF 2 e CDI, é possível implementar aplicativos da Web robustos e reutilizáveis, com um mínimo de confusão e um máximo de flexibilidade e capacidade de reutilização.

A série JSF 2 fu fará uma pausa agora no terceiro trimestre. Volto em outubro com muito mais novidades para ajudá-lo a aprimorar ainda mais suas habilidades em JSF.


Download

DescriçãoNomeTamanho
Sample code for this articlej-jsf2fu-0710-src.zip13KB

Recursos

Aprender

Obter produtos e tecnologias

  • JSF: Faça o download do JSF 2.0.

Discutir

Comentários

developerWorks: Conecte-se

Los campos obligatorios están marcados con un asterisco (*).


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


A primeira vez que você entrar no developerWorks, um perfil é criado para você. Informações no seu perfil (seu nome, país / região, e nome da empresa) é apresentado ao público e vai acompanhar qualquer conteúdo que você postar, a menos que você opte por esconder o nome da empresa. Você pode atualizar sua conta IBM a qualquer momento.

Todas as informações enviadas são seguras.

Elija su nombre para mostrar



Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Los campos obligatorios están marcados con un asterisco (*).

(Escolha um nome de exibição de 3 - 31 caracteres.)

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


Todas as informações enviadas são seguras.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Tecnologia Java
ArticleID=502382
ArticleTitle=JSF 2 fu: Assistentes JSF
publish-date=09292010