Sunday 31 May 2009

JSF 2.0 Criando componentes e usando listeners

Ola Pessoal,
hoje vou deixar o exemplo completo. Vou tentar colocar isso meio que formatado aqui, mas esse site nao e bom para isso e muito menos para a colocacao de codigos.
O arquivo web.xml ira ser o mesmo do post anterior.
Estrutura do projeto
project -+
+ src--+
| +-+ myjsf2.beans
| +-+ myjsf2.business
|
+ WebContent -+
| +-+ META-INF
| +-+ resources
| +-+ WEB-INF--+
| | + lib
| |-+ view files .xhtml

Agora vamos a classe MyLoginBean.java

package myjsf2.beans;
/*
* MyLoginBean is one bean using annotations and some new features from JSF 2.0
* There are no more the faces-config.xml, everything is made by annotations and
* pages are called via action from XHTML page.
* Tipos de anotacoes para o antigo back bean
* @ManagedBean - Registra a instancia da classe como um managed bean e coloca isso no escopo especificado
* @ManagedProperty - Seta a propriedade do managed bean. A anotacao precisa ser colocada antes da declaracao
* das variaveis membros da classe.
* @ApplicationScoped -
* @SessionScoped -
* @RequestScoped -
* @ViewScoped - Todas estas e como a tag que fala qual o escopo de cada...
* @NoneScoped - Sem escopo
* @CustomScoped - Armazena o managed bean em um custon escopo.
*
*/
import java.io.Serializable;
import java.util.ArrayList;
import javax.context.SessionScoped;
import javax.faces.bean.ManagedBean;
import javax.faces.component.UISelectItems;
import myjsf2.business.CheckLogin;

@ManagedBean(name = "myLogin")
@SessionScoped
public class MyLoginBean implements Serializable {
private static final long serialVersionUID = 1L;
private String login;
private String password;
private ArrayList names = CheckLogin.allNames();
private String name;
private UISelectItems nameItem;

// ---- gets and sets from login
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}

// ---- gets and sets from password
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}

// ---- gets and sets from name
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}


// ---- get all names from name
public ArrayList getNames() {
return names;
}
public void setNames(ArrayList names) {
this.names = names;
}


// ---- get and sets for UISelectItems
public UISelectItems getNameItem() {
return nameItem;
}
public void setNameItem(UISelectItems nameItem) {
this.nameItem = nameItem;
}


// ---- Cancel datas from inputTexts
public String cancel() {
login = "";
password = "";
name = "";
return "home";
}

// ---- Check if the login is valid or not
public String check() {
if (CheckLogin.checking(login, password)) {
return "final";
}
return "home";
}
}

Voces poderao perceber aqui que nao mudou muita coisa do JSF 1.2, mas voce poderia colocar o bean ou o objeto em vez do ArrayList que coloquei aqui. O ArrayList foi usado pois nao criei uma conexao a algum banco de dados, ussei um array em vez disso. E isso ja e uma boa diferenca. Temos tambem um componente UI que nessa e uma UISelectItems. Que sera usada para se 'pegar' o valor da view, que e um facelet e nao mais JSP, para portar diretamente para a variavel de instancia name, via gets e sets.
Agora vamos a classe que em um projeto poderia ser o DAO ou um EJB fazendo um lookup ou ainda mesmo uma chamada a um servico. Ela so esta aqui para que tenhamos alguns dados e algum check de login, na primeira parte, pois a segunda que sera o componente nao e testada. Eu fiz isso para que voce tenha uma boa ideia, com varias coisas juntas e depois seria so separar o que voce precisa.
A classe CheckLogin.java
package myjsf2.business;
import java.util.ArrayList;

public class CheckLogin {
public static boolean checking(String user, String password) {
if ((user.endsWith("admin")) && (password.equals("admin"))) {
return true;
}
return false;
}

public static ArrayList allNames() {
ArrayList names = new ArrayList();
names.add("Klaus");
names.add("admin");
names.add("Number1");
names.add("Number2");
names.add("Number3");
return names;
}
}

Como voces podem ver o primeiro metodo ira fazer um teste para direcionar para uma pagina se 'logado' e o segundo e um array que poderia ser um list, bean ou qualquer outro objeto.
A classe LoginActionListener.java
package myjsf2.business;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.component.UIComponent;
import javax.faces.component.ValueHolder;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ActionEvent;
import javax.faces.event.ActionListener;

@ManagedBean(name="loginActionListener")
@SessionScoped
public class LoginActionListener implements ActionListener {
@Override
public void processAction(ActionEvent event) throws AbortProcessingException {
FacesContext context = FacesContext.getCurrentInstance();
UIComponent source = event.getComponent();
ValueHolder usernamemy, passwordmy;
usernamemy = (ValueHolder) source.findComponent("usernameid");
passwordmy = (ValueHolder) source.findComponent("passwordid");
String message = "Login event happned userid : " + usernamemy.getValue() +
" password:" + passwordmy.getValue();
System.out.println(message);
context.getExternalContext().getRequestMap().put("loginActionMessage", message);
}
}

Essa classe ira pegar os dados do componente e disponibiliza-lo no contexto do JSF. Voce esta vendo uma classe nova aqui que e a ValueHolder, ela e que 'pega' o valor usando o id da tag e passa ele, nesse caso, para uma String, o que tambem poderia ser para um Integer ou qualquer outro tipo que voce queira, inlcusive primirivos. O resto sao comandos que ja existem e sao utilizados na versao 1.2 .
Agora voces devem estar se perguntando, para que ser a pasta resource dentro da WebContent, ela e onde voce ira guardar os recursos que serao usados no projeto, podem ser os arquivos CSS, JavaScript, componentes e ou imagens, no nosso caso aqui ira ser um componente.
Ele esta dentro de resources -> mycomponents
O componente loginPanel.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:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:composite="http://java.sun.com/jsf/composite" >
< h:head >
< meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" / >
< title >This will not be present in rendered output< / title >
< / h:head>

< h:body >
< composite:interface >
< composite:valueHolder name="usernameid" / >
< composite:valueHolder name="passwordid" / >
< / composite:interface >

< composite:implementatio >
< br / >
< b >This is the composite component.< / b >
< br / >
< table >
< tr >
< td >Username: < h:inputText id="usernameid" / > < / td >
< / tr >
< tr >
< td >Password: < h:inputSecret id="passwordid" / >< / td >
< / tr >
< tr >
< td >< h:commandButton value="Login" id="loginEvent" actionListener="#{loginActionListener.processAction}" / >< / td >
< / tr >
< / table >
< / composite:implementation >

< / h:body >
< / html >

Este aquivo ira ser o componente que voce ira adicionar dentro da view principal que no nosso caso aqui e a home.xhtml e que voce poderea usar ele em varias outras views
Agora voce ira ver o arquivo home.xml
< !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:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:mc="http://java.sun.com/jsf/composite/mycomponents" >

< h:head >
< meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" / >
< title>J S F 2 . 0 - Tests< / title >
< style type="text/css" >
.grayBox { padding: 8px; margin: 10px 0; border: 1px solid #CCC; background-color: #f9f9f9; }
< / style>
< / h:head>

< h:body >
< ui:debug hotkey="p" rendered="true" / >

< h:form id="home" >
< h:outputScript name="jsf.js" library="javax.faces" target="head" / >
< h:outputStylesheet name="stylesheet.css" / >

< b >
< h:outputText id="zerotext" value="JSF 2.0 Login" / >
< / b >
< br / >
< br / >


< h:outputText id="onetext" value="Login :" / >
< h:inputText id="oneinput" value="#{myLogin.login}" / >
< br / >

< h:outputText id="twotext" value="Password :" / >
< h:inputText id="twoinput" value="#{myLogin.password}" / >
< br / >
< br / >

< h:selectOneMenu id="oneselect" value="#{myLogin.login}" onchange="submit();" >
< f:selectItems id="oneselectItems" value="#{myLogin.names}" binding="#{myLogin.nameItem}" / >
< / h:selectOneMenu >

< br / >
< h:outputText id="threetext" value="#{myLogin.name}" / >
< br / >

< h:commandButton id="validate" value="Login" action="#{myLogin.check()}" / >
< h:commandButton id="cancel" value="Cancel" action="#{myLogin.cancel()}" / >

< br / >

< !-- From here is the part that contain the component example -- >
< div id="compositeComponent" class="grayBox" style="border: lpx solid #090;" >

< mc:loginPanel >
< f:actionListener for="loginEvent" type="myjsf2.business.LoginActionListener" / >
< / mc:loginPanel >

< / div >

< h:commandButton value="reload" / >
< h:outputText value="#{loginActionMessage}" / >

< !-- End of my component -- >

< / h:form >

< / h:body >
< / html >

Voce pode notar que ate o comentario < !-- From here is the part that contain the component example -- >, a view e a mesma do exemplo anterior com somente um SelectOneMenu a mais.
Que foi colocado aqui para que voce veja o funcionamento dos componentes JSF 2.0 usando facelets.
Os arquivos index.xhtml e fina.xhtml sao exatamente os mesmos do ultimo exemplo postado.
Como voces podem ver nao ha muito o que explicar, pois e muito simples o uso dos listeners, criacao de componentes e inclusao deles em outra pagina, uma coisa que nao era facil
com a versao anterior. Tambem deve ter percebido a ausencia do faces-config.xml, agora e tudo feito via anotacoes e o direcionamento para paginas esta dentro da view.
Espero que com isso voces tenham uma boa ideia do que vem vindo por ae com o Java2 SE 7 e o EE 6.
O que posso adiantar tambem para voces e que o uso de microcontainer do EJB3.1 e muito poderoso e pratico, com ele tambem nao existe mais a necessiade de se criar interfaces
locais e remotas, e tudo feito via anotacoes. O validator usado e o do Hibernate que por sinal e muito poderoso e facil de usar. Ainda no EE temos o web beans que fara a tarefa
de trabalhar com EJB muito mais facil e devera tambem ser o core da proxima versao do Seam. Que hoje e um dos frameworks mais utlizados, tendo ja suplantado os sistemas com Struts.
Bom com isso encerro a visao do JSF 2.0 . Eu tinha falado que iria postar um exemplo usando AJAX, mas como a padronizacao ainda nao esta 100% e podendo mudar muito ainda, fora que
RichFaces e IceFaces ainda nao sao 100% compativeis com facelets e o novo JSF engine. Achei melhor deixar isso para depois
Qualquer duvida que voces tiverem podem me escrever, o email esta no post anterior.
Se voce tiver alguma duvida a mais tem um blog da sun que possue varios exemplos de JSF 2.0 que por sinal e muito bom e o Jim Driscoll's Blog .
Boa sorte.

3 comments:

Unknown said...

Boa meu velho, proximo projeto JSf que pegar vou usar o 2.0... value abraço!

Unknown said...

Vlw Ribas, qq duvida e so perguntar, se quizer posso enviar o mini-projeto em eclipse para vc.
Abs

Unknown said...

opa, poode mandar sim! manda para ribas.barros@gmail.com