dez
16
2009

iniciando com vraptor 3

Artigo retirado do blog: http://wbotelhos.wordpress.com

Olá pessoal,

Pra quem esta acompanhando a área de Java não é novidade alguma que o VRaptor esta explodindo de sucesso e boas referências. Hoje trabalho em três projetos consideravelmente grandes na Giran utilizando-o, e posso dizer que estou super satisfeito e admirado.

Conhecendo a framework

O VRaptor é um framework MVC que trabalha com os métodos de seus controllers de forma exposta e de maneira RESTFul, ou seja, conseguimos acessar um método público, por exemplo, através da URI: /usuario/cadastrar de forma fácil e intuitiva. A seguir há uma lista resumida de algumas características:

- Injeção de Dependência;
- Cast automático;
- Conversores;
- Interceptadores;
- Integração com Spring, Hibernate e JPA;
- Facilidade de Testes de Unidade;
- Validações;
- Redirecionamentos;
- URI parametrizada;
- Entre outras mais...

E o melhor de tudo, é open source, brasileira e tem uma lista de discussão com pessoas dispostas a ajudar além de poder acompanhar o desenvolvimento da framework.

Objetivo

Criar um CRUD de Usuário utilizando a última versão do VRaptor 3 simulando a persistência no banco.

Configurando o projeto:

Depois de fazer o download do (blank project for Eclipse WTP) e descompactar o arquivo vraptor-blank-project-3.x.x.zip na sua workspace, iremos renomear os arquivos classpath-example e project-example para .classpath e .project respectivamente.

Se o projeto for aberto, será criado ambos os arquivos iniciados com ponto (ocultos), então terá de deletá-los e fazer o procedimento citado. No Unbuntu basta apertar (Ctrl + H) para ver os arquivos ocultos.

Baixei o blank project mais recente e reparei que já estão ambos os arquivos configurados e podem ser utilizados, porém as libs ficarão quebradas, pois estão configuradas com o caminho do ${USER} do lucascs. Então é só clicar com o botão no projeto -> ir em properties -> Java Build Path e na aba Libraries remover as libs com um 'x' vermelho indicando referência quebrada.

Agora precisaremos configurar o web.xml para enxergar o caminho do nosso pacote principal. No meu caso com.wordpress.wbotelhos, logo todos as outras pastas: Model, Controller, Dao, Repository etc.. estarão abaixo deste pacote e é ele que devemos mapear:


<span> </span>br.com.caelum.vraptor.packages <span> </span>com.wordpress.wbotelhos

Criando o controller

Criaremos o pacote com.wordpress.wbotelhos.controller e dentro um IndexController. (o blank project já contém o mesmo)

@Resource
public class IndexController {

@Path("/")
public void index() {
}

}

Todos os nossos controllers terão o nome NomePastaController e serão anotados com @Resource para expor seus recursos e tornar os métodos públicos acessíveis atavés da URI. No exemplo acima o caminho "/" irá executar o método index, tendo como regra o redirecionamento para uma página de mesmo nome do método, contido dentro de uma pasta de mesmo nome do controller WEB-INF/jsp/index/index.jsp. Todas as nossas páginas ficarão dentro de WEB-INF/jsp/pasta, onde pasta é o nome da entidade na qual queremos trabalhar.

@Path

O VRaptor é uma framework Action Based, logo os métodos são acessados via ações da URI, e estas devem ser únicas.
A anotação Path indica a URI a ser acessada para que possamos executar um método. Por convenção o utilizado é o seguinte: @Path("nomeEntidade/nomeMetodo"):

@Path("/usuario/listarTodos")
public void listar() {
// O método não tem que ter o mesmo nome.
}

Methods

O acesso a um método é feito através das operações HTTP mais comuns como o GET, POST, PUT e DELETE que normalmente são combinadas a um CRUD.

Podemos fazer um esqueminha do tipo:
GET - Listar dados e acessar links;
POST - Salvar uma entidade;
PUT - Atualizar uma entidade; e
DELETE - Excluir uma entidade.

Mesmo que um método tenha o mesmo Path ele pode se diferenciar através do método executado:

@Post
@Path("/usuario")
public void salvar() {
}

@Put
@Path("/usuario")
public void editar() {
}

Por padrão o acesso de um método é composto por nomeController/nomeMetodo via @Get, não sendo necessário neste caso anotar, porém recomendo sempre explicitar, evitando confudir o método de acesso assim como o caminho.

Criando a página inicial

Agora criaremos uma página chamada index.jsp dentro de uma pasta chamada index contendo um menu para a navegação:

...
< %@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
...
<a href="<c:url value='/usuario/novo'></a>">Novo usuário
...

Utilize sempre a tag URL da biblioteca core para que as URLs sejam montadas corretamente.

Pronto! Podemos testar nossa aplicação. Adicione o projeto ao servidor e verá que o nome estará vraptor-blank-project. Esse é o nome default e é através dele que iremos acessár a aplicação: http://localhost:8080/vraptor-blank-project/. Mas queremos usar outro nome, então irei mostrar como trocar, pois renomear a pasta do projeto apenas não irá resolver.

Trocando o nome de deploy e o context-root da aplicação:

- Visualize os arquivos ocultos e dentro da pasta do projeto conterá uma outra chamada .settings;
- Abra o arquivo org.eclipse.wst.common.component em um editor de texto;
- Altere a tag "deploy-name" para alterar o nome visualmente ao escolher a aplicação para deploy;
- Altere a propriedade "context-root" para alterar o contexto de acesso da aplicação;
- Faça o deploy e verá as alterações, podendo escolher o nome que achar melhor.

Criando a página de cadastro do usuario (novo.jsp)

Criaremos 1 Controller + 1 Dao + 1 Pasta contendo as páginas.

...

<form action="<c:url value='/usuario'/>" method="post">
Nome: <input name="usuario.nome" type="text" value="${usuario.nome}" />

Senha: <input name="usuario.senha" type="text" value="${usuario.senha}" />

E-mail: <input name="usuario.email" type="text" value="${usuario.email}" />

<input type="submit" value="Salvar" />
...

A action do formulário acessa /usuario via POST.
Através do parâmetro name, setamos os valores nos atributos do objeto usuario.
Através do parâmetro value, recuperamos o objeto usuario e utilizamos seus atributos para popular os campos.

Criando o modelo do usuário

private Integer id;
private String nome;
private String senha;
private String email;

// Getters e Setters.

Lembre-se que atributo name="usuario.nome" acessa de fato o objeto Usuario e tanto o nome quanto os atributos do objeto devem existir.

Criando o controller do usuário

De acordo com a ação do nosso formulário, criaremos um método acessado pela URI /usuario via POST.

@Post
@Path("/usuario")
public void salvar() {
}

Ainda falta o objeto no qual seto os valores dos campos do formulário. Diferente do useBean do JSP os valores são setados em um objeto presente no próprio controller, falicitando assim o uso do mesmo. Este objeto assim como qualquer que formos trabalhar devem estar presentes no construtor do método invocado, podendo ser mais do que um:

@Post
@Path("/usuario")
public void salvar(Usuario usuario) {
}

Com o objeto alimentado a partir do formulário podemos persistí-lo.

Trabalhando com redirecionamento:

Ao tentarmos salvar um usuário teremos um erro 404, pois seremos redirecionados para uma página com o mesmo nome do método: WEB-INF/jsp/usuario/salvar.jsp, mas como queremos manter o nome do método, porém sermos redirecionados para a página listagem.jsp teremos de fazer o redirecionamento ao final do método.

Temos dois tipos de redirecionamentos:

Results.logic()

Redirecionamento para um método qualquer dos controllers. Devemos passar a classe do controller que iremos utilizar:

result.use(Results.logic()).redirectTo(UsuarioController.class).listagem();

UsuarioController.class pode ser substituido por getClass() indicado a própria classe, ou qualquer outro Controller.class.

Results.page()

Redirecionamento para uma página. Indicamos o caminho da página na qual queremos ser redirecionados (redirect) ou encaminhados (forward):

result.use(Results.page()).forward("WEB-INF/jsp/listagem.jsp");

Para maiores informações sobre a diferença dos dois tipos leia este artigo do Rafael Ponte. (:

Então teríamos nosso controller assim:

@Resource
public class UsuarioController {

private Result result;

@Get
@Path("/usuario/novo")
public void novo() {
}

@Post
@Path("/usuario")
public void salvar(Usuario usuario) {
result.use(Results.page()).forward("WEB-INF/jsp/usuario/listagem.jsp");
}
}

Colocamos o caminho das páginas a partir da pasta WEB-INF.

Injeção de dependência

Certamente se formos utilizar o método salvar seria lançado um NullPointerException, pois o objeto result não esta instanciado. Uma grande facilidade que temos é a injeção de dependência na qual injetamos o objeto através do contrutor da classe e a framework trata de controlar o que é necessário para intanciá-lo.

public UsuarioController(Result result) {
this.result = result;
}

Então agora já temos nosso result instanciado. Da mesma forma se quiséssemos trabalhar com outros controllers, por exemplo, apenas injetaríamos os mesmos.

Por boas práticas recomenda-se criar interfaces com as assinaturas de suas classes e na injeção passá-las em vez das classes concretas, falicitando deste modo os testes de unidades, além de ter uma interface externa de acesso para sua aplicação.

Criando o Dao

Precisamos da camada de persistência e esta camada deve ser anotada como @Component. Componentes são instâncias de classes utilizadas pela sua aplicação para executar tarefas ou armazenar estados em diferentes formas. O Dao é um exemplo clássico.

Para o nosso exemplo iremos colocar a classe como escopo de sessão para que possamos manter o estado dos nossos dados. Os escopos existentes são:

RequestScoped: estará disponível apenas durante a requisição;
ApplicationScoped: será apenas um por aplicação;
SessionScoped: será o mesmo durante uma http session; e
PrototypeScoped: instanciado sempre que requisitado.

@SessionScoped
@Component
public class UsuarioDao {

private List usuarioList = new ArrayList();
private Integer id = 1;

public void salvar(Usuario usuario) {
usuarioList.add(usuario);
usuario.setId(id++);
}

}

Listando os dados: (listagem.jsp)

Para podermos listar nossas informações salvas, devemos passar estes dados através do request que o VRator encapsula assim como o response, tornando esta tarefa mais fácil. O Result será utilizado para incluir os dados da seguinte forma:

result.include("usuarioList", usuarioList);

Para recuperarmos a lista do request podemos utilizar EL da seguinte forma: ${usuarioList}.

...
<table border="0">
<thead>
<tr>
<th>Nome</th>
<th>Senha</th>
<th>E-mail</th>
</tr>
</thead>
<tbody>
<tr>
<td>${item.nome}</td>
<td>${item.senha}</td>
<td>${item.email}</td>
</tr>
</tbody></table>
...

No caso acima nós que incluímos a lista no request, porém por padrão o retorno já é colocado no request. O nome do retorno é formado pelo tipo da lista caso tenha mais o nome "List": public List listar(); seria capturado como ${usuarioList} e se for apenas um objeto basta capturar o nome começando em minísculo: public Usuario consultar(); seria capturado como ${usuario}.

Vamos adicionar o método que retorna a lista no Dao:

public List loadAll() {
return usuarioList;
}

E também no Controller:

@Get
@Path("/usuario")
public List listagem() {
return usuarioDao.loadAll();
}

No método acima estou usando o default e deixando ele colocar o usuarioList no resquest assim como fazer o redirecionamento para listagem.jsp.

Criando a lógica para editar

Vamos adicionar uma coluna na tabela da listagem de dados para conter um link para a edição:

...

<form action="<c:url value='/usuario'/>" method="post">
<input name="_method" type="hidden" value="PUT" />
<input name="usuario.id" type="hidden" value="${item.id}" />
<input type="submit" value="Editar" />
...

Como nosso método editar é acessado via PUT teremos de fazer o formulário utilizá-lo, já que só há o suporte como GET e POST hoje em dia. Para isso criamos um campo hidden (que não aparece na tela) sobrescrevendo o atributo _method com o valor PUT, atributo no qual indica qual método que o formulário executará. O atributo id do objeto usuario também esta escondido servindo apenas para indicar qual usuário queremos editar.

No nosso controller teremos o seguinte método:

@Put
@Path("/usuario")
public void editar(Usuario usuario) {
Usuario entity = usuarioDao.loadById(usuario);
result.use(Results.logic()).redirectTo(getClass()).novo(entity);
}

Repare que após recuperarmos o usuário que queremos editar fazemos uma chamada ao método novo(), pois é ele que redireciona para nosso formulário, porém preciso levar meu usuário consultado para a tela, logo passo o mesmo para o método que foi refatorado para incluir o usuário no request:

@Get
@Path("/usuario/novo")
public void novo(Usuario usuario) {
result.include("usuario", usuario);
}

No nosso Dao também iremos adicionar o método que consulta o usuário pelo ID:

public Usuario loadById(Usuario usuario) {
Usuario usuarioDelete = null;

for (Usuario item : usuarioList) {
if (item.getId() == usuario.getId()) {
usuarioDelete = item;
break;
}
}

removerItem(usuarioDelete); // *
return usuarioDelete;
}

* removerItem(usuarioDelete) foi utilizado aqui apenas por não usármos um banco de dado real e o editar ser na verdade um remover e logo em seguida um salvar.

Procuro o usuário com o ID passado e o guardo, logo em seguida removo ele da lista:

private void removerItem(Usuario usuarioDelete) {
if (usuarioList.remove(usuarioDelete)) {
id--;
}
}

Se desistirmos de salvar o usuário lá no formulário o mesmo já terá sido removido, mas o exemplo é simbólico.

Criando a lógica de exclusão

O método para deletar segui o mesmo raciocínio do editar, só não tendo que retornar os dados para a tela através do request.
Vamos adicionar uma coluna na tabela da listagem de dados para conter um link para a remoção:


<form action="<c:url value="/usuario"/>" method="post">
<input name="_method" type="hidden" value="DELETE/><br />         <input type=" />
<input type="submit" value="Excluir" />

Vamos criar um método anotado com @Delete no controller:

@Delete
@Path("/usuario")
public void remover(Usuario usuario) {
usuarioDao.remover(usuario);
result.use(Results.logic()).redirectTo(getClass()).listagem();
}

E então repassaremos para o nosso Dao remover o objeto:

public void remover(Usuario usuario) {
Usuario usuarioDelete = null;

for (Usuario item : usuarioList) {
if (item.getId() == usuario.getId()) {
usuarioDelete = item;
break;
}
}

removerItem(usuarioDelete);
}

No método acima busco pelo ID, ao achar guardo o objeto e o removo da lista. Em uma situação real removeríamos o objeto do banco de dados de acordo com o ID passado.

Conclusão

De forma fácil conseguimos criar um CRUD sem nos preocupar com requisições, conversões de dados e redirecionamentos. Podemos fazer isso e muito mais com o VRaptor. E se esta preocupado com a parte visual é só da uma olhada no jQuery UI.

Para quem quiser se aprofundar mais no VRaptor, acompanhe a lista de discussão, de uma olhada na documentação oficial disponível em português ou continue acompanhando os artigos aqui no Blog.

Link do projeto:

http://github.com/washingtonbotelho/iniciando-com-vraptor-3

0
dez
16
2009

tags de selecao com jsf

Artigo retirado do blog: http://wbotelhos.wordpress.com

Olá galera! (:

Após rascunhar vários temas, resolvir falar um pouco sobre as tags de seleção do JSF.

Para aqueles que não sabem, temos sete tags de seleção:
<h:selectBooleanCheckbox/>;
<h:selectManyCheckbox/>;
<h:selectOneRadio/>;
<h:selectOneListbox/>;
<h:selectManyListbox/>;
<h:selectOneMenu/>; e
<h:selectManyMenu/>
.

Todas as tags de seleção começam com o nome select e se dividem em 4 (quatro) tipos: CheckBox, Radio, List e Menu. Cada um destes menos o Radio possuem duas formas, uma de seleção única (One) e outra de seleção múltipla (Many).

A tag <h:selectBooleanCheckbox/> é a tag mais simples, no qual apresenta uma única opção de escolha que poderá ser vinculada a um atributo booleano, veja um exemplo:

selectBooleanCheckbox

<h :o utputText value="Ativo?:"/>
<h :selectBooleanCheckbox value="#{bean.ativo}"/>

Temos uma opção, onde se pode marcar como verdadeira ou falsa, no caso, se uma pessoa esta ativa ou não. O valor estará vinculado ao atributo "ativo" contido no backing bean chamado "bean". Teremos um atributo booleano e os métodos get e set para recuperar e atribuir os valores da seleção:

public class Bean {

private boolean ativo;

public boolean isAtivo() {
return ativo;
}

public void setAtivo(boolean ativo) {
this.ativo = ativo;
}
}

Esta tag tem apenas um item de seleção, porém as outras possuem mais de um, nos quais devem ser especificados. Uma maneira direta de especificá-los é utilizar a tag <f:selectItem/>. Você poderá usar os dois atributos básico desta tag que é o valor e o nome do item:

<f :selectItem itemValue="M" itemLabel="Masculino"/>

O valor 'M' é passado como parâmetro de requisição quando o formulário é submetido.

Vejamos um conjunto de botões de rádio utilizando a tag <h:selectOneRadio/> em conjunto com a tag <f:selectItem/>:

selectOneRadio

&lt;h :o utputText value="Sexo:"/&gt;
&lt;h :selectOneRadio value="#{bean.sexo}" layout="pageDirection"&gt;
<f :selectItem itemValue="M" itemLabel="Masculino"/>
&lt;f :selectItem itemValue="F" itemLabel="Feminino"/&gt;
&lt;/h&gt;

Um importante atributo do selectOneRadio e do selectManyCheckbox além de border para especificar uma borda, enabledClass e disabledClass para aplicar um estilo quando o componente estiver habilitado e desabilitado respectivamente, é o layout, que especifica como será dipostos os menus: horizontal ou vertical. Por padrão o componente é lineDirection (horizontal), mas podemos colocá-lo como pageDirection (vertical).

Podemos vincular um único selectItem a um atributo SelectItem do backing bean:

<f :selectItem value="#{bean.femininoItem}"/>
public class Bean {

private SelectItem femininoItem ;

public Bean() {
femininoItem = new SelectItem("F", "Feminino");
}

public SelectItem getFemininoItem() {
return femininoItem;
}

public void setFemininoItem(SelectItem femininoItem) {
this.femininoItem = femininoItem;
}
}

Veja que Sexo possue duas opções, logo utilizei a tag de Item duas vezes, porém esta opção seria um tanto inviável para menus com muitos itens de seleção ou dinâmicos, nos quais os valores não são fixos. A maneira para contornarmos esta restrição é utilizar a tag composta <h:selectItems/>.

Esta tag deverá estar vinculada a um backing bean com um atributo que seja um único SelectItem, Collecion, Array ou um Map com duas entradas representando os rótulos e os valores de SelectItem, além de um atributo no qual você colocará o(s) valor(es) selecionado(s).

Vejamos um conjunto de caixas de seleção, nas quais posso selecionar uma ou mais opções:

selectManyCheckbox

<h :o utputText value="Matérias:"/>
<h :selectManyCheckbox value="#{bean.materias}">
<f :selectItems value="#{bean.materiasItems}"/>
</h>

Cada entrada do mapa será convertida para uma instância de SelectItem. A chave será o rótulo e o valor de entrada será o valor do item. Como no mapa não explicitamos o SelectItem, não conseguimos utilizar outros atributos desta tag como a descrição por exemplo.

Ao utilizarmos um mapa devemos ter em mente que:
- O LinkedHashMap colocará os itens na ordem de inserção;
- O TreeMap será ordenado em ordem alfabética; e
- HashMap será ordenado de forma aleatória.

Backing bean utilizando um mapa:

public class Bean {

private String[] materias;
private Map<string , Object> materiasItems;

public Bean() { // "public" se faz necessário.
materiasItems = new LinkedHashMap</string><string , Object>();
materiasItems.put("Português", "pt");
materiasItems.put("Inglês", "en");
}

public Map</string><string , Object> getMateriasItems() {
return materiasItems;
}

public void setMateriasItems(Map</string><string , Object> materiasItems) {
this.materiasItems = materiasItems;
}
}

O primeiro parâmetro do Mapa representará o rótulo do SelectItem e o segundo o valor.
Para você lembrar o que poderá ser especificado para selectItem basta lembrar de SCAM:
- SelectItem;
- Collection;
- Array; e
- Map.

Repare que estou inicializando o mapa no construtor padrão do backing bean, mas na maioria das vezes buscaremos de um banco de dados.

Agora que estamos familiarizados com o modo de inserir os itens e os possiveis elementos para adicioná-lo, vejamos os restantes das tags de caixa de listagem e menu:

selectOneListbox

<h :o utputText value="Ano:"/>
<h :selectOneListbox value="#{bean.ano}" size="7">
<f :selectItems value="#{bean.anosItems}"/>
</h>

Um atributo interessante é o size, ele indicará quantos itens serão visíveis na caixa de seleção. Caso você especifique um valor menor do que o total de itens, será adicionado um scroller, caso não especifique o atributo a caixa de seleção se ajustará à quantidade de itens, que no caso é o comportalmente padrão.

Backing bean utilizando uma coleção:

public class Bean {

private int ano;
private Collection<selectitem> anosItems;

public Bean() {
anosItems = new ArrayList</selectitem><selectitem>();
for (int i = 1990; i < = 2000; i++) {
anosItems.add(new SelectItem(i));
}
}

public Collection<selectItem> getAnosItems() {
return anosItems;
}

public void setAnosItems(Collection</selectitem><selectitem> anosItems) {
this.anosItems = anosItems;
}
}

selectManyListbox

<h :o utputText value="Dias:"/>
<h :h:selectManyListbox value="#{bean.diasSemana}" style="height: 110px;">
<f :selectItems value="#{bean.diasSemanaItems}"/>
</h>

Quando esta tag é renderizada para HTML, a única diferença dela para a tag OneList é o atributo muiltiple para indicar a possibilidade de múltiplas escolhas.

* Para selecionar mais de um item basta clicar segurar e selecioná-los, porém para seleções não consecutivas se faz necessário segurar a tecla Ctrl.

Backing bean utilizando um array:

public class Bean {

private String[] diasSemana;
private SelectItem[] diasSemanaItems = {
new SelectItem("Domingo"),
new SelectItem("Segunda"),
new SelectItem("Terça"),
new SelectItem("Quarta"),
new SelectItem("Quinta"),
new SelectItem("Sexta"),
new SelectItem("Sábado")
};

public String[] getDiasSemana() {
return diasSemana;
}

public void setDiasSemana(String[] diasSemana) {
this.diasSemana = diasSemana;
}
}

selectOneMenu

<h :o utputText value="Aprovado:"/>
<h :selectOneMenu value="#{bean.aprovado}">
<f :selectItems value="#{bean.aprovadoItems}"/>
</h>

Os dois tipos de menus também têm uma diferença muito simples: o OneMenu simplesmente adiciona o atributo size="1" para indicar que só aparecerá um item, com isso o navegador em vez de criar um scoller cria um botao dropdown pelo fato da tag ser Menu.

Backing bean utilizando um array:

public class Bean {

private String aprovado;
private SelectItem[] aprovadoItems = {
new SelectItem("Sim"),
new SelectItem("Não")
};

public String getAprovado() {
return aprovado;
}

public void setAprovado(String aprovado) {
this.aprovado = aprovado;
}
}

selectManyMenu

<h :o utputText value="Requisitos:"/>
<h :selectManyMenu value="#{bean.requisitos}">
<f :selectItems value="#{bean.requisitosItems}"/>
</h>

O menu de múltiplas escolha tem um pequeno problema: se é um Menu, ele terá o size="1", se é Many terá o atributo multiple. Mas repare só, eu posso selecionar várias opções, mas só enxergarei um item por vez na tela. Sim, realmente assim será, pois os navegadores não criam um menu dropdown no qual se pode selecionar mais de uma opção, até mesmo porque no clique o dropdown é desativado e setado a escolha do usuário. Em vez disso o navegador coloca um scroller minúsculo no qual se deve selecionar um item e passar para o próximo não tendo uma visualização de todas as opções. Outros navegadores nem mesmo colocam o scroller o que nos obrigam a navegarmos pelos itens através do teclado.

Backing bean utilizando um array:

public class Bean {

private String[] requisitos;
private SelectItem[] requisitosItems = {
new SelectItem("Bacharel"),
new SelectItem("Pós Graduação"),
new SelectItem("Mestrado"),
new SelectItem("Doutorado")
};

public String[] getRequisitos() {
return requisitos;
}

public void setRequisitos(String[] requisitos) {
this.requisitos = requisitos;
}
}

Para todas as tags vista menos a selectBooleanCheckbox podemos fazer agrupamentos de itens.

SelectItemGroup

Agora trabalharemos com grupos de SelectItem em vez do array:

private SelectItemGroup meuGrupo = new SelectItemGroup("Nome", "Descrição", true, selectItems);

Temos como atributo o nome do grupo, a descrição, se está ativo ou não e o array de SelectItem.

Vejamos um exemplo utilizando selectManyListbox:

<h :o utputText value="Currículo:"/>
<h :selectManyListbox value="#{bean.curriculo}">
<f :selectItems value="#{bean.curriculoItems}"/>
</h>

Teremos um array de SelectItem e um de resultado da mesma forma que fizemos antes, porém em vez do array de SelectItem receber instâncias de SelectItem, receberá vários SelectItemGroup que por sua vez possue as instâncias de SelectItem. Isto é possível porque SelectItemGroup estende SelectItem.

import javax.faces.model.SelectItem;
import javax.faces.model.SelectItemGroup;

public class Bean {

private SelectItem[] javaItems = {
new SelectItem("Java SE"),
new SelectItem("Java EE"),
new SelectItem("JSP")
};
private SelectItem[] conhecimentosItems = {
new SelectItem("JSF"),
new SelectItem("Hibernate"),
new SelectItem("EJB"),
new SelectItem("Facelets")
};
//
private SelectItemGroup javaGroup = new SelectItemGroup("Java", "Linguagens Java", true, javaItems);
private SelectItemGroup requisitosGroup = new SelectItemGroup("Requisitos", "Conhecimentos", true, conhecimentosItems);
//
private String[] curriculo;
private SelectItem[] curriculoItems = {javaGroup, requisitosGroup};

public SelectItem[] getConhecimentosItems() {
return conhecimentosItems;
}

public void setConhecimentosItems(SelectItem[] conhecimentosItems) {
this.conhecimentosItems = conhecimentosItems;
}

public SelectItem[] getJavaItems() {
return javaItems;
}

public void setJavaItems(SelectItem[] javaItems) {
this.javaItems = javaItems;
}

public String[] getCurriculo() {
return curriculo;
}

public void setCurriculo(String[] curriculo) {
this.curriculo = curriculo;
}

public SelectItem[] getCurriculoItems() {
return curriculoItems;
}

public void setCurriculoItems(SelectItem[] curriculoItems) {
this.curriculoItems = curriculoItems;
}
}

Agora já sabemos manipular todas as tags de seleção do JSF, falta saber como apresentar os resultados. Os resultados mantidos em um vetor por poderem ser mais que um valor, não podem ser impressos diretamente igual um valor vindo de selectOneBooleanCheckbox e armazenado em uma int por exemplo:

<h :o utputText value="Ativo?:"/>
<h :selectBooleanCheckbox value="#{bean.ativo}"/>

Teremos então de pegar cada valor do vetor, montar uma string e ai sim retorná-la. Podemos fazer um método que concatena todos os valores do vetor e retorna uma String montada:

private String concatenar(Object[] vet) {
if (vet == null) {
return "";
}

StringBuilder builder = new StringBuilder();

for (Object ite : vet) {
if (builder.length() > 0) {
builder.append(", ");
}
builder.append(ite.toString());
}

return builder.toString();
}

Também precisaremos de um método get para retornar a String concatenada:

public String getDiasSemanaDisplay() {
return concatenar(diasSemana);
}

Então para todos os atributos que possuem mais que um valor teremos de ter um método get alternativo para apresentação dos mesmos. Mas não omita o get que retorna o vetor, pois ele é necessário para renderização do valor selecionado no componente.

Conclusão:

Em um formulário utilizamos estas tags várias vezes sendo estas essenciais para qualquer tipo de aplicação.
Todas elas suportam formatação de estilo com CSS, mas o foco o artigo é apresentá-las de forma simples e didática. É claro que estas tags possuem vários recursos interessantes, mas deixaremos para um próximo artigo.

Espero que tenham gostado deste meu primeiro post apesar de ter ficado um pouco extenso por ter abordado todas as tags de seleção. Espero que este artigo sirva como um ponta pé para o aprendizado de vocês.

Projeto completo: Download

Até a próxima! (:

Créditos: http://wbotelhos.wordpress.com/2009/07/24/tags-de-selecao-com-jsf/

0
dez
16
2009

validando formularios jsf com javascript

Artigo retirado do blog: http://wbotelhos.wordpress.com

Olá pessoal! =)

Bem, hoje vou mostrar como validar um formulário JSF com Javascript. A princípio é simples, porém existe um detalhe e este detalhe no final se torna um conceito necessário para todos aqueles desenvolvedores JSF, chamado de Naming Container.

Para que possamos validar um campo, este deve conter um identificador ID para servir de "âncora" para nosso script.

Vale lembrar que o ID é uma identificação única, logo se tivermos dois componentes com o mesmo ID o JSF acusará um erro, e lançará uma exceção: "Duplicate component id". Já no HTML não ocorre o erro. Falaremos mais sobre id, class e name em outra oportunidade.

1. Criaremos um fomulário com os campos usuario, senha e confirmação de senha;
2. Identicaremos os componentes;
3. Criaremos um script que validará o formulário.

Formulário:

// < < Atenção!
...

...

Montamos o formulário com os três campos e suas respectivas identificações e um botão que chama uma função javascript de nome validar passando o formulário corrente como parâmetro. Agora devemos declarar o script na página:


<script src="script.js" type="text/javascript"></script>

E então poderemos criar nosso script utilizando os ids como referência e assim capturando os valores dos campos, mas é ai que acabamos vacilando. Se tentarmos capturar o valor do campo "usuario" do modo descrito abaixo, não dará certo, pois o JSF trabalha com o conceito de hierarquia dos componente, ou seja, o Naming Container:

function validar(form) {
var usuario = form["usuario"].value;
...
}

Veja que estamos buscando o id de nome "usuario", porém nosso código gerou algo como:


<form id="j_id_jsp_1070816059_1"> <input id="j_id_jsp_1070816059_1:usuario" name="j_id_jsp_1070816059_1:usuario" />
</form>

Veja que foi concatenado ao nosso ID "usuario" um ID especial j_id_jsp_1070816059_1. Mas de onde veio este ID? Veio do componente mais externo, que por ser um naming container, repassou sua ID para seus componentes internos e é por isso que nosso script não iria funcionar já que a ID final ficou: "j_id_jsp_1070816059_1:usuario". O JSF gera um ID não muito legível, assim como um name automaticamente caso nós não o especifiquemos. Logo devemos especificá-lo para conseguirmos manipulá-lo.


...

Desta forma como já sabemos que os IDs serão concatenados do componente mais "externo" até o nosso componente mais "interno" e já especificamos um ID para o form, teríamos acesso ao campo da seguiente forma:

function validar(form) {
var usuario = form["form:usuario"].value;
...
}

Alguns poderiam pensar ser possível fazer o acesso ao valor do campo da seguinte forma:

var usuario = documents.forms.form.usuario.value;

Porém como vimos temos o sinal de dois pontos ':' entre as IDs, o que nos impossibilita tal ação. Porém temos formas mais elegantes de acesso aos dados, utilizando o getElementById() e evitando passar o formulário como parâmetro:

var usuario = document.getElementById('form:usuario').value;

Você pode estar se questionando o porquê de sempre termos de indicar o ID do componente mais externo, sendo que se tivéssemos mais outros componentes naming containers teríamos de fazer várias concatenações de IDs. Mas o JSF já deu um jeitinho bem legal de resolver isso com apenas um atributo chamado prependId. Basta inserirmos ele na tag <h:form> e a seu ID não será herdada pelos componentes internos:


...

Neste caso indicamos que o prependId será falso, ou seja, o prepend que da idéia de anterior (componente anterior, externo, pai) não passará seu ID adiante. Por padrão este atributo é true. Vale lembrar que mesmo o ID não sendo passado para os componentes internos, o formulário continua com um ID, seja ele gerado automaticamente ou por você próprio ficando assim:


<form id="j_id_jsp_1070816059_1"> <input id="usuario" name="usuario" />
</form>

Desta forma já podemos acessar os valores de forma fácil e moderna, não precisando de passar o formulário como parâmetro e acessando os valores dos campos diretamente:

Formulário:


...

...

Javascript:

function validar() {
var usuario = document.getElementById('usuario');
var senha = document.getElementById('senha');
var confirmar = document.getElementById('confirmar');

if (usuario.value == '' || senha.value == '' || confirmar.value == '') {
alert('Por favor, preencha todos os campos!');
return false;
} else if (senha.value != confirmar.value) {
alert('Ops! A senha não confere.');
confirmar.focus();
return false;
}

alert("Ok! Seu formulário esta válido! (:");
return true;
}

Neste script primeiramente capturo os dados a partir de seus IDs, agora solitários, e com isso pego os valores dos campos e comparo se algum deles esta vazio, apresentando uma mensagem para o usuário e retornando false caso seja verdade ou se a senha não for igual a senha de confirmação, no qual, dou um foco no campo e também alerto o usuário. Caso contrário apenas aviso o usuário que o formulário esta ok e retorno true para o método onSubmit do formulário que diante disso submete o mesmo.

Conclusão:
O Javascript dominou a web e é usado em todas aplicações hoje em dia e com JSF não é diferente, aqui ele também esta presente e não só podemos como devemos usufruir deste recurso. O JSF tem seus próprios validadores nos quais passam pelo ciclo de vida do JSF fazendo uma requisição ao servidor, porém a grande jogada do javascript é exatamente não fazer requisições ao servidor economizando recursos, mas sim ser executado do lado do cliente.

Mas cuidado, como o javascript roda do lado do cliente ele pode ser facilmente desabilitado ou bloqueado, então o ideal seria uma validação tanto client side como server side.

Link do Projeto (Git):
http://github.com/washingtonbotelho/validando-formulario-jsf-com-javascript

Fonte: http://wbotelhos.wordpress.com/2009/08/03/validando-formularios-jsf-com-javascript/

0
dez
06
2009

Resolvendo “Unable to umount, device is busy”

Ao tentar desmontar um volume retorna o erro "Unable to umount, device is busy", uma soluçao para isto é que você pode esta dentro do diretório em que pretende desmontar, ou algum outro usuário. Tente um "ps aux|grep NOME_DO_VOLUME" veja se existe algum processo rodando caso sim, de um "kill -9 N_PROCESSO".

Ou ainda execulte

umount -l /PASTA

até galera...!

1
nov
24
2009

Aparência de Mac no seu GNOME, Usando o Mac4lin

Essa é um artigo requentado, não faz muito tempo, pouco antes do lançamento do incrivel, fenomenal, magnifico sistema operacional da Apple, Mac OS X Leopard, eu demonstrei como é possivel deixar o GNOME com cara de Mac, alias até melhor em alguns aspectos.Novamente vou repetir o artigo, dessa vez com a versão 0.4 do pacote Mac4Lin.
No final do artigo voce encontrará dois videos demonstrando o Look and Feel desse Tema. O vídeo demonstrativo pega pesado usando o WINE (com msoffice2003) e o vmware (virtualizando o windows xp), também demonstra o comportamento desse tema com acesso ao menu do GNOME, acesso ao cairo-dock, troca de tarefas, meta-desktop (cubo) e as firulas do compiz.
0
nov
11
2009

Google lança linguagem de programação “Go”

A Google, não para de inventar, agora foi uma linguagem de Programação (LP). O que vem por ai??? Existe a promessa de um Sistema Operacional (SO), e toda a tecnologia de nuvem, será uma grande inovação da Informatica, e a promessa de um futuro melhor para os internaltas...

Google acaba de anunciar o lançamento de uma nova linguagem de programação de código aberto chamado Go. A empresa diz que o Go é experimental, e que combina os benefícios de desempenho e de segurança associados à utilização de uma linguagem compilada como C + + com a velocidade de uma linguagem dinâmica como Python.

Site do Go escreveu:

Go attempts to combine the development speed of working in a dynamic language like Python with the performance and safety of a compiled language like C or C++.

Fonte: techcrunch.com

0
nov
09
2009

Usando o VirtualBox por linha de comando Criando uma máquina virtual

Para utilizar o VirtualBox por linha de comando usaremos o comando VBoxManage.

Para exemplos de comandos com o VBoxManage use o comando:

$ VBoxManage --help

Ou então visite esta página do manual do VirtualBox:

(mais...)

2
nov
09
2009

Migrar para o Linux pode representar boa economia para sua empresa

Se o preço do Windows e de outros aplicativos empurram as contas de sua empresa para o vermelho, considere usar open source.

O Windows Vista foi lançado sob tímidos aplausos, seguidos por vendas fracas. Até o dia 30 de junho passado, empresas com pouca verba que não quisessem gastar com upgrade de hardware compatível com o Vista ainda podiam adquirir o confiável Windows XP.

(mais...)

0
nov
09
2009

Cinco razões que fazem o Ubuntu 9.10 melhor que o Windows 7

Nova versão do Linux (e praticamente qualquer outra distribuição) faz tudo que se precisa no PC, por menos dinheiro e problemas.

Mesmo reconhecendo que a Microsoft fez um bom trabalho com o Windows 7, que o novo sistema operacional está mais leve e é mais seguro que as versões anteriores já lançadas pela empresa, o que faz, então, um grande número de usuários continuar preferindo usar o Linux (sem contar os novos adeptos) e defender a plataforma open source com unhas e dentes?

(mais...)

1
out
23
2009

Instalando programas 32bits em CentOS 64bits

Acesse o terminal como root, execute o comando:

# yum install glibc.i686

Após isso basta execultar sua aplicação.. =)

Simples mais difícil de se localizar esta informação na web, estou a 2hors...

0