Arquivo

Posts Tagged ‘primefaces’

Gráficos com JSF 2 e Primefaces – Torta

Olá pessoal, tudo bem?

Espero que me perdoem a demora em postar novo material, mas estou com alguns projetos em adamento e ando um pouco sem tempo.

Neste novo post daremos início a uma série onde mostrarei como criar alguns tipos de gráficos com Primefaces. Como pontapé inicial veremos a criação de um gráfico de torta onde mostraremos a probabilidade de título do Camp. Brasileiro.

Utilizaremos em nosso projeto exemplo:

– Netbeans 7.0.1
– Primefaces 3.0M3

Obs.: Com primefaces, não há a necessidade de adicionar nenhuma lib para a criação de gráficos, a não ser, que você deseje interagir com o JFreeChart.

Para começar crie um projeto, no nosso caso ExGraficoTorta. Neste projeto construa uma estrutura de pacotes conforme exibido abaixo:

Criamos uma classe Time, outra TimeDAO e um managedbean GraficoBean. Todas estas classes serão detalhadas mais abaixo:

Veja a classe Time.java


public class Time {

    private long id;
    private String nomeTime;
    private double probabilidade;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getNomeTime() {
        return nomeTime;
    }

    public void setNomeTime(String nomeTime) {
        this.nomeTime = nomeTime;
    }

    public double getProbabilidade() {
        return probabilidade;
    }

    public void setProbabilidade(double probabilidade) {
        this.probabilidade = probabilidade;
    }
}

Utilizaremos este modelo para, através do DAO, buscar os dados que desejamos exibir no gráfico de torta. Vamos agora ver como ficará o managedbean utilizado para gerenciar a página. Abaixo confira o código:

@ManagedBean
public class GraficoBean implements Serializable {

    private PieChartModel modelo;

    public GraficoBean() {
        criarModeloGrafico();
    }

    public PieChartModel getModelo() {
        return modelo;
    }

    public void setModelo(PieChartModel modelo) {
        this.modelo = modelo;
    }

    private void criarModeloGrafico() {
        modelo = new PieChartModel();
        List<time> listaTime = new ArrayList<time>();
 TimeDAO timeDAo = new TimeDAO();
 listaTime = timeDAo.listaTodos();
 for (Time time : listaTime) {
 modelo.set(time.getNomeTime(), time.getProbabilidade());
 }
 }
}

Declaramos um objeto do tipo PieChartModel para espelhar o modelod o gráfico de torta que usaremos na nossa página. Como este é um exemplo simples e prático, decidi simplesmente criar um método para preencher o modelo e chamá-lo no construtor. Provavelmente, em suas apps, você deverá invocar o método através de uma action de um botão, menuitem, etc.

Confira abaixo um pouco sobre os principais atributos da tag pieChart

 Nome

Valor Padão

Tipo

Descrição

id

null

String

Identificador único

rendered

TRUE

Boolean

Indica que o componente deve ou não ser renderizado na tela

binding

null

Object

Uma expression language que faz o mapeamento do componente com um objeto UICOmponente localizado no backingbean.

value

null

Collection

É o modelo do gráfico

diameter

null

Integer

Tamanho do diâmetro da torta.

legendPosition

null

Object

Campo que indica a posição da legenda. Coloque as siglas dos pontos cardeais em inglês. Ex.: w, ne, n, etc.

style

null

String

Define o estilo do painel do gráfico, tamanho, tamanho de fonte, etc.

seriesStyle

null

String

Cores dos items. Coloque as cores em formato RGB sem o #.

Não explicarei todos os atributos, até porque você não os utilizará, mas em caso de dúvida post um comentário. Segue o código da nossa página que exibirá o gráfico:

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:p="http://primefaces.prime.com.tr/ui"
      xmlns:h="http://java.sun.com/jsf/html">
    <h:head>
        <title>Gráficos com JSF 2.0</title>
    </h:head>
    <h:body>
        <p:pieChart value="#{graficoBean.modelo}"
                    legendPosition="w"
                    title="Probabilidade de Título - Brasileirão 2011"
                    style="width:800px;height:600px;"/>
    </h:body>
</html>

Veja na imagem abaixo como ficou:
Gráfico de Torta

É isso ai, bem simples, qualquer dúvida coloca um comentário. Valeu!

JSF 2.0 – PRIMEFACES – P:TREE – CONTROLE DE PERMISSÕES A MENUS

zApós algum tempo sem postar, devido a grande carga de trabalho, consegui um tempo para escrever sobre este maravilhoso componete da biblioteca primefaces. Desde que o vi no showcase sempre tive a idéia de utiliza-lo conforme irei mostrar para vocês, como um controle de permissões com checkboxs. A capacidade de uso deste componente é muito grande e variada devido a flexibilidade e quantidade de recursos agredados a ele.

Antes de iniciar o post gostaria de avisar aos nossos leitores que estão abertas as inscrições para dois cursos na nossa plataforma de ensino a distância. São eles o de FUNDAMENTOS DA LINGUAGEM JAVA e DESENVOLVENDO UMA APLICAÇÃO BÁSICA COM JSF 2.0 E PRIMEFACES. Para mais detalhes, visite a área de cursos em http://www.quebrandoparadigmas.com/cursos/, os preços estão bastante acessiveis, por isso, espero a participação de vocês.

O componete TREE

É um componente usado para exibir dados em formato de árvore. Abaixo os atributos do componente com uma breve descrição:

Nome Valor Padrão Tipo Descrição
id null Tipo Identificador único do componente.
rendered TRUE Boolean Valor boleano que especifica a renderização ou não do componente, quando FALSE o componente não será renderizado.
binding null Object Uma expression language que mapeia o componente para um UIComponente no managed bean.
value null Object Representa uma instância de TreeNode no managed bean.
var null String Nome da variável que será usada para representar cada nó da árvore durante a renderização.
expandAnim null String Animação a ser exibida quando um nó for expandido. Os valores válidos são: FADE_IN ou FADE_OUT.
collapseAnim null String Animação a ser exibida quando um nó for retraido. Os valores válidos são: FADE_IN ou FADE_OUT.
nodeSelectListener null MethodExpr Método do managed bean a ser executado quando um nó for selecionado.
nodeExpandListener null MethodExpr Método do managed bean a ser executado quando um nó for expandido.
nodeCollapseListener null MethodExpr Método do managed bean a ser executado quando um nó for retraído.
cache TRUE Boolean Defini se haverá cache para os nós carregados dinâmicamente. Quando TRUE os nós expandidos serão mantidos na memória.
widgetVar null String Valor da variável para JavaScript.
onNodeClick null String Evendo JavaScript a ser processado quando um nó for clicado.
expanded FALSE Boolean Quando TRUE todos os nós iniciarão expandidos.
update null String Id(s) do(s) componente(s) a ser(em) expandido(s) quando um nó for selecionado.
onselectStart null String Evento JavaScript invocado antes da requisição ajax.
onselectComplete null String Evento JavaScript invocado antes da requisição ajax.
selection null Object Array que referencia todos os nós selecionados.
propagateSelectionUp FALSE Boolean Propaga as seleções para os nós superiores.
propagateSelectionDown FALSE Boolean Propaga as seleções para os nós inferiores.
selectionMode null String Define o modo de seleção.

Fonte: Primefaces User’s Guide 2.2

Para o nosso exemplo utilizaremos:

– Mojarra 2.1
– Primefaces 2.2.1
– Mysql 5.1.53

Neste exemplo irei demonstrar como criar um controle de permissões, com o componente Tree, para gerenciar o acesso de usuários aos menus de uma aplicação. Para quem conseguiu implementar o exemplo de menu dinâmico, pode agregar esta funcionalidade e criar as permissões para cada usuário.

Abaixo o DER com a disposição das tabelas:

Assim, teremos três tabelas, uma para cadastrar os usuários da aplicação, outra para cadastrar os menus e finalmente uma que irá definir os menus que os usuários podem ter acesso.

Desta forma, criaremos os beans e os DAOs, veja imagem abaixo com a organização do projeto.

Como você puderam observar criaremos os três beans, um para cada tabela, abaixo veja o código dos modelos:

Obs.: Suprimimos os getters e setters.

Menu.java

public class Menu {

    private int id;
    private String descricao;
    private String url;
    private String icone;
    private String indice;

    /* Getters e Setters */

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Menu other = (Menu) obj;
        if (this.id != other.id) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 3;
        hash = 67 * hash + this.id;
        return hash;
    }

    @Override
    public String toString() {
        return descricao;
    }
}

Usuario.java

public class Usuario {

    private int id;
    private String login;
    private String senha;
    private Timestamp ultimoAcesso;
    private List<Permissao> listaPermissao = new ArrayList<Permissao>();

   /* Getters e Setters */

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Usuario other = (Usuario) obj;
        if (this.id != other.id) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 31 * hash + this.id;
        return hash;
    }
}

Permissao.java

public class Permissao {

    private int id;
    private Menu menu = new Menu();
    private Usuario usuario = new Usuario();

   /* Getters e Setters */

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Permissao other = (Permissao) obj;
        if (this.id != other.id) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 11 * hash + this.id;
        return hash;
    }
}

No beans é muito importate sobreescrever os métodos equals, hashcode e toString, principalmente na classe Menu, pois iremos fazer comparações entre os objetos criados a partir desta classe.

Com estas classes criadas, vamos criar os DAOs pra acessar os dados na base de dados. Abaixo o código:

MenuDAO.java

public class MenuDAO {

    private Connection con;
    private final String COL_ID = "id";
    private final String COL_DESCRICAO = "descricao";
    private final String COL_URL = "url";
    private final String COL_ICONE = "icone";
    private final String COL_INDICE = "indice";

    public List<Menu> listaTodos() throws SQLException {
        List<Menu> listaMenu = new ArrayList();
        String query = "select * from menus";
        con = ConnectionFactory.getMySQLConnection();
        PreparedStatement ps = con.prepareStatement(query);
        ResultSet rs = ps.executeQuery();
        while (rs.next()) {
            Menu menu = new Menu();
            menu.setId(rs.getInt(COL_ID));
            menu.setDescricao(rs.getString(COL_DESCRICAO));
            menu.setUrl(rs.getString(COL_URL));
            menu.setIcone(rs.getString(COL_ICONE));
            menu.setIndice(rs.getString(COL_INDICE));
            listaMenu.add(menu);
        }
        con.close();
        return listaMenu;
    }
    public Menu buscaPorId(int id) throws SQLException {
        Menu menu = new Menu();
        String query = "select * from menus where id=?";
        con = ConnectionFactory.getMySQLConnection();
        PreparedStatement ps = con.prepareStatement(query);
        ps.setInt(1, id);
        ResultSet rs = ps.executeQuery();
        if (rs.next()) {
            menu.setId(rs.getInt(COL_ID));
            menu.setDescricao(rs.getString(COL_DESCRICAO));
            menu.setUrl(rs.getString(COL_URL));
            menu.setIcone(rs.getString(COL_ICONE));
            menu.setIndice(rs.getString(COL_INDICE));
        }
        con.close();
        return menu;
    }
}

Na classe acima, temos somente dois métodos básicos dos DAOs, listaTodos e buscaPorId.

UsuarioDAO.java

public class UsuarioDAO {

    private Connection con;
    private final String COL_ID = "id";
    private final String COL_LOGIN = "login";
    private final String COL_SENHA = "senha";
    private final String COL_ULTIMOACESSO = "ultimo_acesso";

    public List<Usuario> listaTodos() throws SQLException {
        List<Usuario> listaUsuario = new ArrayList<Usuario>();
        String query = "select * from usuarios";
        con = ConnectionFactory.getMySQLConnection();
        PreparedStatement ps = con.prepareStatement(query);
        ResultSet rs = ps.executeQuery();
        while (rs.next()) {
            Usuario usuario = new Usuario();
            usuario.setId(rs.getInt(COL_ID));
            usuario.setLogin(rs.getString(COL_LOGIN));
            usuario.setSenha(rs.getString(COL_SENHA));
            usuario.setUltimoAcesso(rs.getTimestamp(COL_ULTIMOACESSO));
            listaUsuario.add(usuario);
        }
        con.close();
        return listaUsuario;
    }

    public Usuario buscaPorId(int id) throws SQLException {
        Usuario usuario = new Usuario();
        String query = "select * from usuarios where id=?";
        con = ConnectionFactory.getMySQLConnection();
        PreparedStatement ps = con.prepareStatement(query);
        ps.setInt(1, id);
        ResultSet rs = ps.executeQuery();
        if (rs.next()) {
            usuario.setId(rs.getInt(COL_ID));
            usuario.setLogin(rs.getString(COL_LOGIN));
            usuario.setSenha(rs.getString(COL_SENHA));
            usuario.setUltimoAcesso(rs.getTimestamp(COL_ULTIMOACESSO));
        }
        con.close();
        return usuario;
    }
}

Na classe acima, temos somente dois métodos básicos dos DAOs, listaTodos e buscaPorId.

PermissaoDAO.java

public class PermissaoDAO {

    private Connection con;
    private final String COL_ID = "id";
    private final String COL_USUARIO = "usuarios_id";
    private final String COL_MENU =  "menus_id";

    public List<Permissao> buscaPorUsuario(Usuario usuario) throws SQLException {
        List<Permissao> listaPermissao = new ArrayList<Permissao>();
        MenuDAO menuDAO = new MenuDAO();
        String query = "select * from permissoes where usuarios_id=?";
        con = ConnectionFactory.getMySQLConnection();
        PreparedStatement ps = con.prepareStatement(query);
        ps.setInt(1, usuario.getId());
        ResultSet rs = ps.executeQuery();
        while(rs.next()) {
            Permissao permissao = new Permissao();
            permissao.setId(rs.getInt(COL_ID));
            permissao.setUsuario(usuario);
            permissao.setMenu(menuDAO.buscaPorId(rs.getInt(COL_MENU)));
            listaPermissao.add(permissao);
        }
        con.close();
        return listaPermissao;
    }

    public Permissao buscaPorMenuUsuario(Menu menu, Usuario usuario) throws SQLException {
        Permissao permissao = new Permissao();
        String query = "select * from permissoes where usuarios_id=? and menus_id=?";
        con = ConnectionFactory.getMySQLConnection();
        PreparedStatement ps = con.prepareStatement(query);
        ps.setInt(1, usuario.getId());
        ps.setInt(2, menu.getId());
        ResultSet rs = ps.executeQuery();
        if (rs.next()) {
            permissao.setId(rs.getInt(COL_ID));
            permissao.setMenu(menu);
            permissao.setUsuario(usuario);
        }
        con.close();
        return permissao;
    }

    public void excluiPorUsuario(Usuario usuario) throws SQLException {
        String query = "delete from permissoes where usuarios_id=?";
        con = ConnectionFactory.getMySQLConnection();
        PreparedStatement ps = con.prepareStatement(query);
        ps.setInt(1, usuario.getId());
        ps.execute();
        con.close();
    }

    public void salvar(Permissao permissao) throws SQLException {
        String query = "insert into permissoes(menus_id,usuarios_id) values(?,?)";
        con = ConnectionFactory.getMySQLConnection();
        PreparedStatement ps = con.prepareStatement(query);
        ps.setInt(1, permissao.getMenu().getId());
        ps.setInt(2, permissao.getUsuario().getId());
        ps.execute();
        con.close();
    }
}

Na classe acima temos os métodos buscaPorUsuario, que retorna uma coleção de Permissao, para todos os registros que o usuário for igual ao passado como parâmetro.  Temos tambem, buscaPorMenuUsuario, que retorna uma coleção de Permissao, para aquele registro onde o usuário e o menu são iguais aos passados como parâmetro. Além desses, temos excluirPorUsuario, que exclui todas as permissões do usuário passado como parâmetro e o método salvar, que persiste a permissão passada como parâmetro.

Com estas classes criadas, estamos prontos para partirmos para o desenvolvimento da página. Como toda aplicação JSF criaremos um managed bean para a página que iremos criar e neste colocaremos os atributos que serão acessados na página, além dos métodos que controlarão todas as ações.

A seguir confira como ficou nosso managed bean:

Obs.: Irei suprimir os getters e setters.

PermissaoManagedBean.java
@ManagedBean
@ViewScoped
public class PermissaoManagedBean {

    private TreeNode root;
    private TreeNode[] nosSelecionados;
    private Usuario usuarioSelecionado = new Usuario();
    private List<Usuario> listaUsuario = new ArrayList();
    private List<Permissao> listaPermissao = new ArrayList();
    private List<Menu> listaMenu = new ArrayList();
    private List<Menu> menusPermitidos = new ArrayList();
    private List<Menu> menusUsuario = new ArrayList();
    private UsuarioDAO usuarioDAO = new UsuarioDAO();
    private PermissaoDAO permissaoDAO = new PermissaoDAO();
    private MenuDAO menuDAO = new MenuDAO();

    public PermissaoManagedBean() {
        try {
            listaUsuario = usuarioDAO.listaTodos();
        } catch (SQLException ex) {
            Logger.getLogger(PermissaoManagedBean.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

/* Getters e Setters */
    private boolean isFilho(String[] indicesPai, String[] indicesFilho) {
        boolean isFilho = false;
        int i = 0;
        if (indicesPai.length == indicesFilho.length - 1) {
            for (String string : indicesPai) {
                isFilho = string.equals(indicesFilho[i]);
                if (!isFilho) {
                    break;
                }
                i++;
            }
        }
        return isFilho;
    }

    private void carregarFilhos(List<Menu> menus, Menu menu, TreeNode treeNode) {
        for (Menu m : menus) {
            String[] indicesPai = menu.getIndice().split("\\.");
            String[] indicesFilho = m.getIndice().split("\\.");
            TreeNode tr;
            if ((indicesFilho.length > indicesPai.length)) {
                if (isFilho(indicesPai, indicesFilho)) {
                    if (m.getUrl().equals("")) {
                        tr = new DefaultTreeNode(m, treeNode);
                        carregarFilhos(menus, m, tr);
                    } else {
                        tr = new DefaultTreeNode(m, treeNode);
                        if (isPermitido(m)) {
                            tr.setSelected(true);
                        }
                    }
                }
            }
        }
    }

    private boolean isPermitido(Menu menu) {
        boolean retorno = false;
        for (Menu m : menusPermitidos) {
            if (m.equals(menu)) {
                retorno = true;
                break;
            }
        }
        return retorno;
    }

    public void carregaPermissoesUsuario() {
        permissaoDAO = new PermissaoDAO();
        menuDAO = new MenuDAO();
        root = new DefaultTreeNode("Qp", null);
        menusPermitidos = new ArrayList<Menu>();
        try {
            listaPermissao = permissaoDAO.buscaPorUsuario(usuarioSelecionado);
            listaMenu = menuDAO.listaTodos();

            for (Permissao permissao : listaPermissao) {
                menusPermitidos.add(permissao.getMenu());
            }
            if (usuarioSelecionado.getId() != 0) {
                for (Menu menu : listaMenu) {
                    if ((menu.getUrl().trim().equals("")) && (menu.getIndice().length() == 1)) {
                        TreeNode treeNode = new DefaultTreeNode(menu, root);
                        carregarFilhos(listaMenu, menu, treeNode);
                    }
                }
            }
        } catch (SQLException ex) {
            Logger.getLogger(PermissaoManagedBean.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void salvaPermissoes() {
        if (usuarioSelecionado.getId() == 0) {
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Nenhum usuário SELECIONADO", "Erro"));
        } else {
            try {
                permissaoDAO.excluiPorUsuario(usuarioSelecionado);
                for (TreeNode no : nosSelecionados) {
                    if (no.isLeaf()) {
                        Menu folha = (Menu) no.getData();
                        Permissao permissao = new Permissao();
                        permissao.setMenu(folha);
                        permissao.setUsuario(usuarioSelecionado);

                        permissaoDAO.salvar(permissao);
                        salvaPai(no);
                    }
                }
                carregaPermissoesUsuario();
                FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Permissões Salvas", "Permissões Salvas"));
            } catch (SQLException ex) {
                Logger.getLogger(PermissaoManagedBean.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    public void salvaPai(TreeNode no) {
        TreeNode tr = no.getParent();
        if (!tr.equals(root)) {
            Permissao p;
            try {
                p = permissaoDAO.buscaPorMenuUsuario((Menu) tr.getData(), usuarioSelecionado);
                if (p == null) {
                    Permissao permissao = new Permissao();
                    permissao.setUsuario(usuarioSelecionado);
                    permissao.setMenu((Menu) tr.getData());
                    permissaoDAO.salvar(permissao);
                }
                salvaPai(tr);
            } catch (SQLException ex) {
                Logger.getLogger(PermissaoManagedBean.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
}

E abaixo o código da página, que é controlada pelo backing bean acima:

<?xml version='1.0' encoding='UTF-8' ?>
<!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:p="http://primefaces.prime.com.tr/ui"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html">
    <h:head>
        <title>QuebrandoParadigmas.com</title>
    </h:head>
    <h:body>
        <h:form>
            <p:panel header="Controle de Permissões" style="margin-top: 10px; width: 500px;">
                <h:panelGrid columns="2">
                    <h:selectOneMenu value="#{permissaoManagedBean.usuarioSelecionado.id}">
                        <f:selectItem itemValue="0" itemLabel=""/>
                        <f:selectItems value="#{permissaoManagedBean.listaUsuario}" var="usuario"
                                       itemValue="#{usuario.id}" itemLabel="#{usuario.login}"/>
                        <p:ajax event="change" listener="#{permissaoManagedBean.carregaPermissoesUsuario()}"
                                update="panelPermissoes"/>
                    </h:selectOneMenu>
                    <p:ajaxStatus>
                        <f:facet name="start">
                            <h:graphicImage value="./imagens/ajax-loader.gif" />
                        </f:facet>
                        <f:facet name="complete">
                            <h:outputText value="" />
                        </f:facet>
                    </p:ajaxStatus>
                </h:panelGrid>
            </p:panel>
            <p:panel id="panelPermissoes" style="margin-top: 10px; margin-bottom: 10px; width: 500px;">
                <p:messages/>
                <p:tree value="#{permissaoManagedBean.root}" selectionMode="checkbox" var="no"
                        expanded="true" expandAnim="FADE_IN" collapseAnim="FADE_OUT"
                        selection="#{permissaoManagedBean.nosSelecionados}" propagateSelectionUp="true" propagateSelectionDown="true">
                    <p:treeNode>
                        <h:outputText value="#{no}" style="margin-left: 10px;"/>
                    </p:treeNode>
                </p:tree>
            </p:panel>
            <p:commandButton value="Salvar" action="#{permissaoManagedBean.salvaPermissoes()}" update="panelPermissoes"/>
        </h:form>
    </h:body>
</html>

Temos um selectOneMenu que lista todos os usuários, representados no managed bean por List<Usuario>, que é preenchido no controller.

Como o escopo do backing bean é de visão(@ViewScoped) sempre que dermos um refresh na página os comandos contidos no construtor serão novamente executados e a página retorna ao seu estado padrão.

Dentro do selectOneMenu inserimos um componente do AjaxEngine do primefaces, o p:ajax com o parametro event = change, ou seja, sempre que "mudarmos" o valor do "combo" será executado o método que esta em parametro listener. Ou seja, sempre que o valor for alterado o métodos carregaPermissoesUsuario() será executado e o painel panelPermissoes será atualizado ao final.

O método carregaPermissoesUsuario() preenche o objeto raiz da árvore, root, com todos os menus que existem na tabela Menu e posteriormente verifica quais dos menus são permitidos ao usuário selecionado e, através do método setSelected(true), define na visão quais "folhas" deverão ser marcadas no componente tree. Bom pessoal, espero que consigam integrar com o menu dinâmico, é simples.

Boa sorte e espero ter ajudado.

Abaixo vídeo da aplicação exemplo rodando:

Gostou do Post? Então faça-nos uma doação:

JSF 2.0 – Primefaces 2.2 – FileUpload com ImageCropper

 

FileUpload

O componente FileUpload, como o prórprio nome diz, é responsável pelo envio de imagens da máquina cliente para o lado servidor. Este componente vai além da navegação da tag html <input type=”file”>, trazendo funcionalidades flashjavascript. Podemos filtrar arquivos, fazer múltiplos uploads, processamento parcial da página e uma barra para acompanhamento do progresso do upload. Caso o navegador cliente não suporte flash ou javascrip o fileupload retorna a funcionalidade padrão de <input type=”file”>.

Em um post anterior, já descrevi como utilizar FileUpload, porém, da versão utilizada no post até a atual tivemos algumas modificações na forma de configuração, o que me leva a descrever alguns procedimentos novamente.

Bibliotecas necessárias:

Configuração do web.xml:

<filter>
   <filter-name>PrimeFaces FileUpload Filter</filter-name>
   <filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
</filter>

<filter-mapping>
   <filter-name>PrimeFaces FileUpload Filter</filter-name>
   <servlet-name>Faces Servlet</servlet-name>
</filter-mapping>

Abaixo descrição dos principais atributos do componente:

  • id:  Identificador único do componente
  • rendered: Valor boleano para especificar se o componente deve ou não ser exibido
  • fileUploadListener:  Método a ser executado quando sempre que um arquivo for ser enviado
  • multiple:  Habilita o envio de múltiplos arquivos
  • update: id de um componente a ser atualizado após o término do envio do arquivo
  • auto: Quando habilitado(true) o upload do arquivo começa logo após a seleção
  • label: Rótulo do botão, o padrão é ‘Browse’
  • image: Imagem de fundo do botão
  • cancelImage: Imagem do botão cancelar
  • width: Largura do botão de procura
  • height: Altura do botão de procura
  • allowTypes: Lista de extensões de arquivos aceitas
  • description: Rótulo que descreve quais tipos de arquivo podem ser enviados
  • sizeLimit: Número máximo de bytes aceitos
  • wmode: Propriedade wmode do objeto flash
  • customUI: Quando habilitado(true) os links upload e cancel  não são exibidos
  • widgetVar: Nome do widget para referências em javascript

ImageCropper

O componente ImageCropper  tem como funcionalidade recortar determinadas regiões de uma imagem. Esta funcionalidade criauma nova imagem contendo a região recordada e associando-a a um objeto do tipo CroppedImage instanciado no lado servidor.

Abaixo descrição dos principais atributos do componente:

  • id:  Identificador único do componente
  • rendered: Valor boleano para especificar se o componente deve ou não ser exibido
  • required: Indica se o campo é obrigatório
  • value:  EL para um Objeto do tipo CroppedImage instanciado no managed bean.
  • image:  Caminho para a imagem(context path)
  • initialCoords:  Coordenadas da posição inicial da região de corte

Criação de Aplicação integrando FileUpload e ImageCropper

Para criação desta aplicação iremos criar uma view(index.xhtml), uma pasta imagens onde armazenaremos as imagens utilizadas no sistema e uma pasta upload para colocar as imagens enviadas através do file upload. A estrutura do projeto ficará conforme imagem abaixo:

Para este projeto simples devemos criar um bean gerenciado de escopo de sessão para controlar a nossa view, abaixo confira o código.
Obs.: Desconsideramos os getters e setters.

IndexManagedBean.java

@ManagedBean
@SessionScoped
public class IndexManagedBean {

private StreamedContent imagemEnviada = new DefaultStreamedContent();
private String imagemTemporaria;
private CroppedImage croppedImage;
private boolean exibeBotao = false;

/* getters e setters */

   public void criaArquivo(byte[] bytes, String arquivo) {
      FileOutputStream fos;
      try {
         fos = new FileOutputStream(arquivo);
         fos.write(bytes);
         fos.close();
      } catch (FileNotFoundException ex) {
         Logger.getLogger(IndexManagedBean.class.getName()).log(Level.SEVERE, null, ex);
      } catch (IOException ex) {
         Logger.getLogger(IndexManagedBean.class.getName()).log(Level.SEVERE, null, ex);
      }
   }

   public void enviarImagem(FileUploadEvent event) {
      byte[] img = event.getFile().getContents();
      imagemTemporaria = event.getFile().getFileName();
      FacesContext facesContext = FacesContext.getCurrentInstance();
      ServletContext scontext = (ServletContext) facesContext.getExternalContext().getContext();
      String arquivo = scontext.getRealPath("/upload/" + imagemTemporaria);
      criaArquivo(img, arquivo);
      setExibeBotao(true);
   }

   public void crop() {
      setImagemEnviada(new DefaultStreamedContent(new ByteArrayInputStream(croppedImage.getBytes())));
   }
}

O método enviarImagem(FileUploadEvent event) é utilizado no atributo fileUploadListener para ser executado sempre que uma imagem estiver sendo enviada. É neste método onde poderemos fazer conversões, criação de arquivos, etc.

Observem que no método é passado um parâmetro event com o qual eu consigo retirar todos os dados que preciso, como nome de arquivo, caminho, array de bytes referentes ao arquivo, etc. Iremos criar um arquivo temporário que será utilizado na view com o imageCropper, este arquivo é criado na pasta upload através do método criaArquivo, e também salvar o nome do arquivo criado em uma String, a imagemTemporaria.

Em seguida criamos o método crop() para coletar a imagem recortada e jogar dentro da imagemEnviada que é do tipo StreamedContent, que pode ser trabalhado dinamicamente com o um p:graphicImage. Abaixo confira a utilização de todos os métodos e atributos na view:

<h:form>
   <p:panel header="ImageCropper com FileUpload - QuebrandoParadigmas.com" style="width: 900px; margin: 0 auto; margin-top: 0px">
      <p:fileUpload fileUploadListener="#{indexManagedBean.enviarImagem}" sizeLimit="204800" auto="true"
                            image="/imagens/imgBuscar.png" customUI="true" update="outputPanelUpload"/>
      <p:outputPanel id="outputPanelUpload">
         <h:panelGrid columns="2">
            <h:outputText value="Imagem" rendered="#{indexManagedBean.exibeBotao}"/>
             <h:outputText value="Pre-visualização" rendered="#{indexManagedBean.exibeBotao}"/>
             <p:imageCropper id="imageCropperImagemTemporaria" value="#{indexManagedBean.croppedImage}"
              image="#{pageContext.servletContext.contextPath}/upload/#{indexManagedBean.imagemTemporaria}"/>
              <p:graphicImage value="#{indexManagedBean.imagemEnviada}" cache="false"/>
         </h:panelGrid>
         <p:commandLink action="#{indexManagedBean.crop}" update="outputPanelUpload"
                                   rendered="#{indexManagedBean.exibeBotao}">
            <p:graphicImage style="margin-top: 5px; border: none;" value="/imagens/imgCortar.png"/>
         </p:commandLink>
      </p:outputPanel>
   </p:panel>
</h:form>

Criamos um outputPanel de nome outputPanelUpload que é  atualizado sempre que algum dado no managed bean é alterado, como quando a imagem de upload é enviada e damos um update para exibi-la ou quando cortamos a imagem e atualizamos para exibir a região cortada em uma outra imagem. Gostaria de salientar o código abaixo, pois é nele onde carregamos  a imagem que foi criada no na pasta upload do servidor:
image=”#{pageContext.servletContext.contextPath}/upload/#{indexManagedBean.imagemTemporaria}”

Perceba que pego o caminho do contexto(pasta web) e dentro dele a pasta upload e, em seguida, acrescento com uma EL que representa o nome do arquivo que foi definido no fileUploadListener(enviaImagem).

O resultado você pode conferir no vídeo abaixo:





Twitter: @benignoms

JSF 2.0 + PRIMEFACES + iREPORT

Neste post iremos demonstrar, de forma sucinta, como criar relatórios com iReport e como utiliza-lo em suas aplicações web. O iReport é uma ferramenta para  se desenhar relatórios para o JasperReport, que é a uma biblioteca para geração de relatórios. Escolhemos o iReport, por ser uma ferramenta open-source e de bastante disseminação na comunidade Java, além de ser muito fácil de usar e possuir integração com o JFreeChart, para geração de gráficos, e com o Barbecue, gerador de código de barras.

No nosso exemplo utilizaremos

  • Mojarra 2.0.3
  • Primefaces 2.2.1
  • Mysql JDBC Connector 5.1.14

Alé disso precisamos acrescertar ao projeto, as bibliotecas necessárias para rodar relatórios jasper. São elas:

  • Jasper Reports 3.7.6
  • iText 2.1.7
  • Grovy All 1.7.5
  • Commons beanutils 1.8.2
  • Commons collections 3.2.1
  • Commons Digester 1.7
  • Commons Logging 1.1

Lembre-se que a maioria destes jars você pode encontrar na pasta libs do iReport..

Abaixo você pode ver a estrutura que usaremos para nossa base de dados:

Imagem 1

Como você pode ver, utilizaremos uma tabela cargos(mestre) com uma tabela funcionários(detalhes), onde um cargo pode ser comum de vários funcionários, mas um funcionário só de ter um cargo.

Iniciando com o iRerpot

O iReport é uma ferramenta para criação do arquivo jrxml, que nada mais é do que uma definição do relatório em xml. Esta definição poderia ser feita em um bloco de notas, ou qualquer outro editor de texto, porém seria uma atividade incomparavelmente mais custosa para o desenvolvedor.

Com o iReport, é possível desenhar todo o relatório, incluir imagens, além de manipular sub-relatórios e diferentes fontes de dados.

Bom, no início de qualquer relatório é necessário primeiro definir a fonte de dados, ou seja, de onde iremos captar os dados para construção do relatório. Existem duas formas que gosto de trabalhar, uma é utilizando uma consulta SQL diretamente no banco e utilizando os dados retornados para preencher o relatórios. Outra forma, é através da utilização de JavaBeans enviado para o relatório apenas uma coleção dos dados a serem utilizados.

Ao construirmos um relatório temos diversas bandas aparentes na tela, estas seções são divisões da tela do relatório onde podemos preenche-las com textos e imagens .

No iReport estão visíveis 9 seções, ou bandas. São elas:

1. Title: Título do relatório. Pode ser impresso em uma página separada;

2. Page Header: Cabeçalho de cada página do relatório;

3. Column Header: Seção exibida em cada página que contém uma seção Detail;

4. Detail: Nesta seção são impressos todos os registros fornecidos ao relatório;

5. Column Footer: Exibido em cada página que contém uma seção Detail;

6. Page Footer: Rodapé de cada página;

7. Summary: Seção exibida no fim do relatório. Pode ser impresso em uma página separada;

8. No Data: Seção exibida quando não há registros;

9. Background: Nesta seção é possível inserir uma imagem de fundo que será exibida em cada página do relatório.

Fonte: Gerando relatórios com iReport – Roberto Jundi Furutani da Java Magazina 84.

Imagem 2

Criando os Beans

Na aplicação exemplo que iremos fazer, teremos dois beans. Abaixo você pode ver a codificação de ambos:

Cargo.java

public class Cargo {

private int id;

private String descricao;

public String getDescricao() {

return descricao;

}

public void setDescricao(String descricao) {

this.descricao = descricao;

}

public int getId() {

return id;

}

public void setId(int id) {

this.id = id;

}

}

Funcionario.java


public class Funcionario {

private int id;

private String nome;

private String email;

private Cargo cargo = new Cargo();

public Cargo getCargo() {

return cargo;

}

public void setCargo(Cargo cargo) {

this.cargo = cargo;

}

public String getEmail() {

return email;

}

public void setEmail(String email) {

this.email = email;

}

public int getId() {

return id;

}

public void setId(int id) {

this.id = id;

}

public String getNome() {

return nome;

}

public void setNome(String nome) {

this.nome = nome;

}

}

Para que você possa utilizar os beans no iReport é necessário gerar os arquivos .jar e incluir no classpath. Caso você utilize o netbeans você poderá criar uma nova aplicação desktop, criar as classes e executar a aplicação. Dentro da pasta dist, será gerado um arquivo .jar, com o nome que você de ao projeto da aplicação. Com este arquivo criado,  basta colocar para o classpath do iReport apontar para o local onde você o salvou e pronto. Agora, você já pode configurar seu relatório baseado nos dois modelos que criamos.

Imagem 3

Para isso, vamos criar um novo relatório no iReport e depois clicar com o botão direito do mouse sobre o nome do relatório que fica na aba Report Inspector. Feito isso, clique em Edit Query. Abaixo veja imagens das telas:

Imagem 4

Imagem 5

Você deve escolher a segunda aba, JavaBean DataSource, a primeira é para utilizar-se com uma consulta SQL diretamente na base de dados. Digite o nome da classe, nome completo, incluindo o pacote e depois clique em Read Attributes e depois  selecione os campos e clique em Add Selected Field(s)

Imagem 6

Após adicionar os campos vamos montar nosso relatório. Utilize a paleta com as imagens, static text e text fields para montar seu relatório.

Montamos de acordo com a imagem abaixo:

Imagem 7

Criei uma aplicação JSF simples, somente com um botão para chamar o  relatório.

Imagem 8

Veja abaixo os DAOS:

FuncionarioDAO.java

public class FuncionarioDAO {

private Connection conexao;

public List<Funcionario> listaTodos() {

List<Funcionario> listaFuncionario = new ArrayList<Funcionario>();

String consulta = "select * from tab_funcionarios";

try {

conexao = ConnectionFactory.getMySQLConnection();

PreparedStatement ps = conexao.prepareStatement(consulta);

ResultSet rs = ps.executeQuery();

CargoDAO cargoDAO = new CargoDAO();

while(rs.next()) {

Funcionario funcionario = new Funcionario();

funcionario.setId(rs.getInt("id"));

funcionario.setNome(rs.getString("nome"));

funcionario.setEmail(rs.getString("email"));

funcionario.setCargo(cargoDAO.buscaCargoPorId(rs.getInt("tab_cargos_id")));

listaFuncionario.add(funcionario);

}

} catch (SQLException ex) {

Logger.getLogger(FuncionarioDAO.class.getName()).log(Level.SEVERE, null, ex);

}

return listaFuncionario;

}

}

CargoDAO.java

public class CargoDAO {

private Connection conexao;

public Cargo buscaCargoPorId(int id) {

Cargo cargo = new Cargo();

try {

conexao = ConnectionFactory.getMySQLConnection();

String consulta = "select * from tab_cargos where id=?";

PreparedStatement ps = conexao.prepareStatement(consulta);

ps.setInt(1, id);

ResultSet rs = ps.executeQuery();

if(rs.next()) {

cargo.setId(rs.getInt("id"));

cargo.setDescricao(rs.getString("descricao"));

}

} catch (SQLException ex) {

Logger.getLogger(CargoDAO.class.getName()).log(Level.SEVERE, null, ex);

}

return cargo;

}

}

Para chamar o relatório, colocamos o arquivo compilado(.jasper) na pasta report dentro da pasta web-inf e usamos o método imprimeRelatório() do manager bean:

public void imprimeRelatorio() throws IOException, SQLException {

Connection con = ConnectionFactory.getMySQLConnection();

FuncionarioDAO funcionarioDAO = new FuncionarioDAO();

List<Funcionario> listaFuncionario = new ArrayList<Funcionario>();

listaFuncionario = funcionarioDAO.listaTodos();

JRBeanCollectionDataSource ds = new JRBeanCollectionDataSource(listaFuncionario);

HashMap parameters = new HashMap();

try {

FacesContext facesContext = FacesContext.getCurrentInstance();

facesContext.responseComplete();

ServletContext scontext = (ServletContext) facesContext.getExternalContext().getContext();

JasperPrint jasperPrint = JasperFillManager.fillReport(scontext.getRealPath("/WEB-INF/report/relatorio_funcionarios_por_cargo.jasper"), parameters, ds);

ByteArrayOutputStream baos = new ByteArrayOutputStream();

JRPdfExporter exporter = new JRPdfExporter();

exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);

exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, baos);

exporter.exportReport();

byte[] bytes = baos.toByteArray();

if (bytes != null && bytes.length > 0) {

HttpServletResponse response = (HttpServletResponse) facesContext.getExternalContext().getResponse();

response.setContentType("application/pdf");

response.setHeader("Content-disposition", "inline; filename=\"relatorioPorData.pdf\"");

response.setContentLength(bytes.length);

ServletOutputStream outputStream = response.getOutputStream();

outputStream.write(bytes, 0, bytes.length);

outputStream.flush();

outputStream.close();

}

} catch (Exception e) {

e.printStackTrace();

}

}


Abaixo o resultado do relatório:

É isso, o que ficar de dúvida a gente tenta resolver pelos comentários.

Abraços.

JSF 2.0 – Primefaces – p:picklist

Um outro componente muito interessante de se usar e com várias utilidades em projetos do dia-a-dia é o p:picklist. Com este componente você irá transferir dados entre coleções utilizando uma caracteristica muito interessante o DRAG AND DROP ou ARRASTAR E SOLTAR. Legal, não?

Bom, vamos ver como funciona mais este fantástico componete da Primefaces.

Abaixo uma breve descrição dos principais atributos deste componente:

rendered: Exibir ou não o componente

binding: Uma expression language  que mapeia um UIComponent do lado servidor.

value: Valor do componente. Pode ser uma EL ou um valor literal. Uma coleção do tipo DualListModel.

converter: converter para o componente.

immediate: especifica se o ciclo de validação deve ser ou não processado.

required: Faz do componente um campo requerido no formulário.

var: Nome do objeto de interação

itemLabel: Rótulo do campo.

itemValue: Objeto referente ao valor do item.

Vamos ao nosso exemplo. Optei por fazer um exemplo com interação com uma base de dados, pois fazendo este exemplo você conseguirá fazer o que quiser. Para este exemplo irei utilizar:

– Mojarra 2.0.3
– PrimeFaces-2.2.RC1-SNAPSHOT

Criei uma tabela jogadores com os campos id, nome e estado, conforme a imagem abaixo:

E povoei conforme abaixo:

Obeserve que no campo ESTADO, estou usando valores 1 ou 2. Estes valores representam se o jogador esta 2-LESIONADO ou esta 1-SAUDÁVE. Caso queira, podeá criar uma tabela auxiliar para colocar a descrição, achei desnecessário para o exemplo.

Criei um projeto de nome ExPickList e criei os pacotes de acordo com a imagem abaixo:

Criei o modelo ou bean de acordo com os campos da tabela de jogadores e incluí os métodos getters e setters, veja abaixo:


public class Jogador {

 private int id;
 private String nome;
 private int estado;

 public int getId() {
 return id;
 }

 public void setId(int id) {
 this.id = id;
 }

 public String getNome() {
 return nome;
 }

 public void setNome(String nome) {
 this.nome = nome;
 }

 public int getEstado() {
 return estado;
 }

 public void setEstado(int estado) {
 this.estado = estado;
 }
}

O DAO JogadoresDAO é bem semelhante ao do POST sobre p:autocomplete a única diferença é que eu incluí dois métodos: buscaPorEstado e atualiza.

O buscaPorEstado utiliza um parâmetro inteiro para buscar todos os jogadores de acordo com esse parâmetro e retorna uma coleção do tipo Jogador. Já o atualiza serve para atualizar os valores na base de dados de acordo com o objeto do tipo Jogador passado como parâmetro. Segue abaixo o código do DAO:


public class JogadorDAO {

 private Connection con;
 private String sql;
 private final String COL_ID = "id";
 private final String COL_NOME = "nome";
 private final String COL_ESTADO = "estado";

 public List<Jogador> buscaPorEstado(int estado) {
 List<Jogador> jogadores = new ArrayList<Jogador>();
 sql = "select * from jogadores j where j.estado = ?";
 con = ConnectionFactory.getConnection();
 PreparedStatement ps;
 try {
 ps = con.prepareStatement(sql);
 ps.setInt(1, estado);
 ResultSet rs = ps.executeQuery();
 while (rs.next()) {
 Jogador jogador = new Jogador();
 jogador.setId(rs.getInt(COL_ID));
 jogador.setNome(rs.getString(COL_NOME));
 jogador.setEstado(rs.getInt(COL_ESTADO));
 jogadores.add(jogador);
 }
 con.close();
 } catch (SQLException ex) {
 Logger.getLogger(JogadorDAO.class.getName()).log(Level.SEVERE, null, ex);
 }
 return jogadores;

 }

 public Jogador buscaPorNome(String nome) {
 Jogador jogador = new Jogador();
 sql = "select * from jogadores j where j.nome = ?";
 con = ConnectionFactory.getConnection();
 PreparedStatement ps;
 try {
 ps = con.prepareStatement(sql);
 ps.setString(1, nome);
 ResultSet rs = ps.executeQuery();
 if (rs.next()) {
 jogador.setId(rs.getInt(COL_ID));
 jogador.setNome(rs.getString(COL_NOME));
 jogador.setEstado(rs.getInt(COL_ESTADO));
 }
 con.close();
 } catch (SQLException ex) {
 Logger.getLogger(JogadorDAO.class.getName()).log(Level.SEVERE, null, ex);
 }
 return jogador;

 }

 public List<Jogador> listaTodos() {
 List<Jogador> jogadores = new ArrayList<Jogador>();
 try {
 con = ConnectionFactory.getConnection();
 sql = "select * from jogadores j";
 PreparedStatement ps = con.prepareStatement(sql);
 ResultSet rs = ps.executeQuery();
 while (rs.next()) {
 Jogador j = new Jogador();
 j.setId(rs.getInt(COL_ID));
 j.setNome(rs.getString(COL_NOME));
 j.setEstado(rs.getInt(COL_ESTADO));
 jogadores.add(j);
 }
 con.close();
 } catch (SQLException ex) {
 Logger.getLogger(JogadorDAO.class.getName()).log(Level.SEVERE, null, ex);
 }
 return jogadores;
 }
 public void atualiza(Jogador jogador) {
 sql = "update jogadores set nome=?, estado=? where id=?";
 con = ConnectionFactory.getConnection();
 try {
 PreparedStatement ps = con.prepareStatement(sql);
 ps.setString(1, jogador.getNome());
 ps.setInt(2, jogador.getEstado());
 ps.setInt(3, jogador.getId());
 ps.execute();
 } catch (SQLException ex) {
 Logger.getLogger(JogadorDAO.class.getName()).log(Level.SEVERE, null, ex);
 }
 }

Por último, mas não menos importante vem o nosso CONTROLLER.

@ManagedBean
@SessionScoped
public class JogadorController {

 private JogadorDAO dao = new JogadorDAO();
 private List<Jogador> saudaveis = new ArrayList<Jogador>();
 private List<Jogador> lesionados = new ArrayList<Jogador>();
 private DualListModel<Jogador> jogadores;

 public DualListModel<Jogador> getJogadores() {
 return jogadores;
 }

 public void setJogadores(DualListModel<Jogador> jogadores) {
 this.jogadores = jogadores;
 }

 public List<Jogador> getLesionados() {
 return lesionados;
 }

 public void setLesionados(List<Jogador> lesionados) {
 this.lesionados = lesionados;
 }

 public List<Jogador> getSaudaveis() {
 return saudaveis;
 }

 public void setSaudaveis(List<Jogador> saudaveis) {
 this.saudaveis = saudaveis;
 }

 public void salva() {
 saudaveis = jogadores.getSource();
 lesionados = jogadores.getTarget();
 for (Jogador jogador : saudaveis) {
 jogador.setEstado(1);
 dao.atualiza(jogador);
 }
 for (Jogador jogador : lesionados) {
 jogador.setEstado(2);
 dao.atualiza(jogador);
 }
 Utils.showFacesMessage("Jogadores SAUDAVEIS e LESIONADOS atualizados", 2);
 }

 public JogadorController() {
 saudaveis = dao.buscaPorEstado(1);
 lesionados = dao.buscaPorEstado(2);
 jogadores = new DualListModel<Jogador>(saudaveis, lesionados);
 }
}

No nosso controller quero destacar alguns pontos. Primeiramente temos duas coleções ambas do do tipo List<Jogador> uma para lesionados e outra para saudaveis. Logo em seguida, temos uma coleção do tipo org.primefaces.model.DualListModel que utiliza-se de duas coleções e será o responsável pela interação entre as outras coleções que criamos. Além desses atributos supracitados inserimos o nosso dao que usaremos para preencher as coleções.

Inserimos todos os  métodos getters e setters e no construtor chamamos o dao  duas vezes para povoar a coleção saudaveis e lesionados com os jogadores de acordo com o seu estado. Depois passamos as duas coleções como parâmetro do construtor do DualListModel jogadores. Pronto! Nosso PickList esta pronto para sofrer interações do usuário.

Na nossa view é onde iremos trabalhar com o nosso p:picklist, veja abaixo o código da index.xhtml:


<h:body>
 <p:panel header="Jogadores do Corinthians" style="width:500px">
 <p:messages id="mensagens"/>
 <h:form>
 <p:pickList id="jogadores" value="#{jogadorController.jogadores}" var="jogador" iconOnly="true" itemLabel="#{jogador.nome}" itemValue="#{jogador}"
 converter="jogadorConverter">
 <f:facet name="sourceCaption">Saudáveis</f:facet>
 <f:facet name="targetCaption">Lesionados</f:facet>
 </p:pickList>
 <p:commandButton value="Submit" action="#{jogadorController.salva}" update="jogadores mensagens" image="ui-icon-transfer-e-w"/>
 <p:ajaxStatus>
 <f:facet name="start">
 <h:outputText value="Salvando..."/>
 </f:facet>
 <f:facet name="complete">
 <h:outputText value=""/>
 </f:facet>
 </p:ajaxStatus>
 </h:form>
 </p:panel>
 </h:body>

No picklist o atributo value deverá conter a nossa coleção DualListModel #{jogadorController.jogadores} e utilizaremos do f:facet para definir o sourceCaption, que referencia ao título da lista Origem(saudaveis) e targetCaption que representa o titulo da lista Destino(lesionados). Abaixo do picklist tem um commandbutton onde chamo o método salva do managed bean que atualizará os valores na base de dados.

Pronto pessoal! Bon appetit, vejam como ficou nosso lindo picklist:

É isso ai pessoal, espero ter ajudado. Abraços a todos e até o próximo post!

JSF 2.0 – Primefaces – p:autoComplete

Esta semana estive testanto alguns componentes do Primefaces, e achei alguns bastante interessantes. Irei fazer uma série de posts mostrando alguns destes componentes. Dentre os que mais gostei está o autocomplete que, como o nome diz, exibe sugestões de complemento para o texto que esta sendo digitado.

Abaixo os principais atributos do p:autocomplete:
rendered – especifica a renderização ou não do componente.
binding – mapeia um UIComponente no lado servidor.
value – Objeto referente.
converter – id de um converter
immediate –  especifica se a fase de validação será ou não processada.
required – define se o campo é referido no formulário.
validator – Especifica um método ou um validator, para validar os dados do campo.
var – nome que irá interagir quando utilizar sugestões baseadas no POJO.
itemLabel – Label do item.
itemValue – Valor do item.
completeMethod – Método chamado para produzir as sugestões.
maxResults – Número máximo de sugestões.

Vamos iniciar o exemplo de uso do componente autocomplete. No exemplo irei mostrar como criar as sugestões a partir de um banco de dados, com este exemplo vocês conseguirão utilizar o componente como quiserem. Let´s rock!

Para este exemplo irei utilizar:

– Mojarra 2.0.3
– PrimeFaces-2.2.RC1-SNAPSHOT

Criei uma tabela:

Povoei esta tabela:

A partir dai, criei um projeto ExAutoComplete com a seguinte estrutura:

No projeto criei o controller da página, a fábrica de conexões, nosso DAO e o modelo(bean), além de ter criado o JogadorConverter, que irá nos ajudar a encontrar o objeto para cada nome sugerido. Caso queira saber mais sobre converter, leia o meu último post. Com estas classes ja podemos iniciar nosso desenvolvimento.

Jogador.java


public class Jogador {

private int id;

private String nome;

public int getId() {

return id;

}

public void setId(int id) {

this.id = id;

}

public String getNome() {

return nome;

}

public void setNome(String nome) {

this.nome = nome;

}

}

Acima, um bean simples com dois atributos e seus métodos getters e setter.

JogadorDAO.java

public class JogadorDAO {

 private Connection con;
 private String sql;
 private final String COL_ID = "id";
 private final String COL_NOME = "nome";

 public Jogador buscaPorNome(String nome) {
 Jogador jogador = new Jogador();
 sql = "select * from jogadores j where j.nome = ?";
 con = ConnectionFactory.getConnection();
 PreparedStatement ps;
 try {
 ps = con.prepareStatement(sql);
 ps.setString(1, nome);
 ResultSet rs = ps.executeQuery();
 if(rs.next()) {
 jogador.setId(rs.getInt(COL_ID));
 jogador.setNome(rs.getString(COL_NOME));
 }
 } catch (SQLException ex) {
 Logger.getLogger(JogadorDAO.class.getName()).log(Level.SEVERE, null, ex);
 }
 return jogador;

 }

 public List<Jogador> listaTodos() {
 List<Jogador> pessoas = new ArrayList<Jogador>();
 try {
 con = ConnectionFactory.getConnection();
 sql = "select * from jogadores j";
 PreparedStatement ps = con.prepareStatement(sql);
 ResultSet rs = ps.executeQuery();
 while(rs.next()) {
 Jogador p = new Jogador();
 p.setId(rs.getInt(COL_ID));
 p.setNome(rs.getString(COL_NOME));
 pessoas.add(p);
 }
 } catch (SQLException ex) {
 Logger.getLogger(JogadorDAO.class.getName()).log(Level.SEVERE, null, ex);
 }
 return pessoas;
 }
}

No nosso DAO temos apenas dois métodos, o listaTodos() e o buscaPorNome(String nome). O nome dos métodos ja diz tudo, não? Um serve para buscar todos os registros da tabela jogadores e preencher uma lista de objectos Jogador. Já o segundo, procura na tabela jogadores a linha que contiver o nome correspondente ao parâmetro nome.

JogadorController.java

@ManagedBean
@RequestScoped
public class JogadorController {

 private Jogador jogadorSelecionado;
 private JogadorDAO jogadorDAO = new JogadorDAO();
 private List<Jogador> jogadores = new ArrayList<Jogador>();

 public Jogador getJogadorSelecionado() {
 return jogadorSelecionado;
 }

 public void setJogadorSelecionado(Jogador jogadorSelecionado) {
 this.jogadorSelecionado = jogadorSelecionado;
 }

 public List<Jogador> getJogadores() {
 return jogadores;
 }

 public void setJogadores(List<Jogador> jogadores) {
 this.jogadores = jogadores;
 }

 public List<Jogador> completaNome(String query) {
 this.jogadores = jogadorDAO.listaTodos();
 List<Jogador> sugestoes = new ArrayList<Jogador>();
 for (Jogador j : this.jogadores) {
 if (j.getNome().startsWith(query)) {
 sugestoes.add(j);
 }
 }
 return sugestoes;
 }
}

No nosso controller teremos três atributos. Um será do tipo JogadorDAO, outro Jogador e por último uma lista List<Jogador>. O JogadorDAO serve para interagirmos com a base de dados, o jogadorSelecionado serve para quando selecionarmos um dos nomes sugeridos no componente autocomplete ele procure o objeto correspondente, já a lista representa a lista de sugestões. Temos também os métodos getters e setters e um método completaNome(String query) que carrega os dados da lista jogadores e depois procura na lista os objetos que contem o atributo nome começando com os valores do parâmetro query.

index.xhtml


<html xmlns="http://www.w3.org/1999/xhtml"
 xmlns:p="http://primefaces.prime.com.tr/ui"
 xmlns:h="http://java.sun.com/jsf/html"
 xmlns:f="http://java.sun.com/jsf/core"  >
 <h:head>
 <title>Exemplo Autocomplete  - PrimeFaces</title>
 <link href="#{facesContext.externalContext.requestContextPath}/css/blitzer/skin.css" rel="stylesheet" type="text/css" />
 </h:head>
 <h:body>
 <p:panel header="Busca de Jogadores" style="width:300px">
 <h:form>
 <h:panelGrid columns="2">
 <p:autoComplete value="#{jogadorController.jogadorSelecionado}" completeMethod="#{jogadorController.completaNome}" var="jogador" itemLabel="#{jogador.nome}"
 itemValue="#{jogador}" converter="jogadorConverter"/>
 <p:commandButton value="Submit" update="jogador mensagens" image="ui-icon-transfer-e-w"/>
 <h:outputText id="jogador" value="Selecionado: #{jogadorController.jogadorSelecionado.id} - #{jogadorController.jogadorSelecionado.nome}" />
 </h:panelGrid>
 </h:form>
 </p:panel>
 </h:body>
</html>

Acima a nossa view, um panel, um panel grid para organizar os componente ,o componente autocomplete coloquei no atributo value o jogadorSelecionado do controller, o completeMethod é o completaNome, no var chamei de jogador, em itemLabel é o que será exibido, no nosso caso o nome e itemValue o objeto que representa e por ultimo o converter.

Observe que no campo autocomplete eu uso um converter, abaixo o código da classe JogadorConverter.java.


@FacesConverter(value="jogadorConverter")
public class JogadorConverter implements Converter {

 @Override
 public Object getAsObject(FacesContext fc, UIComponent uic, String string) {
 JogadorDAO jogadorDAO = new JogadorDAO();
 Jogador jogador = jogadorDAO.buscaPorNome(string);
 return jogador;
 }

 @Override
 public String getAsString(FacesContext fc, UIComponent uic, Object o) {
 Jogador jogador = new Jogador();
 jogador = (Jogador) o;
 return jogador.getNome();
 }

}

Implementando os dois método, um para converter de String para o objeto do tipo Jogador e outro para fazer o inverso.

O resultado é o seguinte:


É isso, espero ter ajudado. Grande abraço e até o próximo POST.

abraços!

Converters – JSF 2.0

Atendendo a pedidos vou comentar um pouco sobre o uso de converters no JSF 2.0. Para aqueles que não sabem Converters são classes que implementam a interface Converter e servem para converter dados da view(String) para um Objeto e vice-versa.  Todos os tipos básicos JSF converterá automaticamente. Mas, se você quiser converter um objeto do tipo Date, JSF provê o converter <f:convertDateTime>. Para utilizar esta tag, basta inseri-la dentro do componente que quer fazer a conversão, como no exemplo abaixo:

<h:outputText value="#{meuBean.data}">
<f:convertDateTime type="date" dateStyle="medium"/>
</h:outputText>

O convertDateTime suporta alguns atributos para uma melhor configuração, como type e dateStyle, dentre outros. Abaixo dou uma breve explicação sobre estes atributos.

dateStyle – Somente é válido se o atributo type estiver definido. Especifica o estilo da formatação da data. Os valores válidos são: short, medium  (default), long and full.

timeStyle – Somente é válido se o atributo type estiver definido. Especifica o estilo da formatação da hora. Os valores válidos são: short, medium  (default), long and full.

timeZone – Especifica uma zona de tempo. Caso não seja setado GMT será utilizado.

locale – Informa o local de exibição da data.

pattern – Especificação da formatação da data. Use esse atributo ou o type.

type – Informa o tipo de data. Os tipos validos são: date, time ou both

Caso você deseje fazer conversões de números, JSF te oferece o convertNumber. Abaixo veja um exemplo do uso deste converter:

</pre>
<h:outputText value="#{meuBean.data}">
<f:convertNumber type="number" maxIntegerDigits="3"/>
</h:outputText>

Attributos da tag:

currencyCode – Especifica o caractere que aparecerá a cada três digitos. Expressor de milhares, milhões, etc.

currencySymbol – O simbolo a ser exibido antes do valor monetário. Ex.: Para R$ você usa ?R$?.

integerOnly – Alguém tem dúvida? Somente inteiros 😀

minFractionDigits – Mínimo número de dígitos fracionados a serem exibidos.

maxFractionDigits – Máximo de dígitos fracionados a serem exibidos.

minIntegerDigits e maxIntegerDigits – Mínimo e máximo de dígitos inteiros.

pattern – É a máscara

type – Tipo do campo. Padrão é numeric, mas existem tambem currency e percent.

Caso nenhum destes dois converters resolva seu problema, veremos agora como criar o nosso converter customizado.

O problema é o seguinte:

No meu formulário vou precisar de um campo para armazernar o peso de uma pessoa. Até ai tudo bem, mas eu gostaria que no inputText o campo aparecesse com o sufixo kg(quilograma) Ex.: 82kg(uma String) e que quando fosse salvo no banco de dados, fosse salvo somente o 82 que é um numero inteiro. Então como fazer isso?

Primeiramente iremos criar a nossa classe que servirá como converter:


//Aqui eu digo que esse cara é um FACES CONVERTER, Antes eu tinha de mapear no facesc-config.xml
@FacesConverter(value="pesoConverter")
public class PesoConverter implements Converter {
//Aqui faremos a conversão de String(82kg) para Inteiro(82)
public Object getAsObject(FacesContext context, UIComponent component, String value) {
int retorno = 0;
 if (!(value.equals(""))) {
 String peso = value;
 String somenteNumero = peso.replace("kg", "");
 retorno = Integer.parseInt(somenteNumero);
 }
 return retorno;
}
//Aqui faremos o inverso. Conversão de Inteiro(82) para String(82kg)
 public String getAsString(FacesContext context, UIComponent component, Object value) {
String peso = value.toString();
peso = peso + "kg";
return peso;
 }
}

Para usa o converter agora é muito simples. basta inserir dentro do campo que você desejar, no nosso caso um inputText.

<h:inputText value="#{meuBean.peso}" converter="pesoConverter" />

E é isso, espero que tenham gostado de mais essa dica, aguardo sugestões para novos posts.

abraços

Menu dinâmico – JSF 2.0 + Primefaces

Bom dia,

Depois de algum tempo sem postar, volto com tudo pra falar sobre outro tema que muitas pessoas tem dificuldade de encontrar material completo na internet. Para completar, vamos começar a utilizar JSF 2.0 com Primefaces.

Nosso projeto consistirá em uma tabela que representará menus e submenus e através dela montaremos o menu da nossa aplicação dinâmicamente conforme o exemplo abaixo:

Menu dinâmico

Menu dinâmico

Segue abaixo a estrutura da tabela e os campos:

tab_menu

Tabela que contem todos os menus e sub-menus

tabela menu povoada

tabela menu povoada

Crie um esquema de banco de dados no banco de dados que preferir e apartir dele crie uma tabela chamada tab_menu. No nosso exemplo a tabela contem cinco campos: id, descrição, viewId, icone e tab_menus_id. O campo id representa o id do menu, o campo descrição é como se fosse o label, é o nome que será exibido no menu, o viewId representa a view que será exibida quando clicarmos no menu, a página ou a expression language, ou uma navigation rule depende de como você irá chamar a próxima view. O campo ícone, é a imagem que aparecerá junto ao menu e deverá estar na pasta imagens dentro da pasta web. Já o campo tab_menu_id condiz a um auto-relacionamento da tabela, que indicará a profundidade do menu.

Após a criação da tabela, veja como ficará a estrutura de pacotes do nosso projeto:

pacotes

pacotes e páginas

Daremos ênfase as classes que construirão o menu. Primeiro iremos criar a classe Menu.java dentro do pacote beans que será o modelo do nosso menu. Segue abaixo o código da classe:


package info.esolucao.sac.beans;

import java.util.List;

/**
 *
 * @author BENIGNO
 */
public class Menu {

 private int id;
 private String descricao;
 private String viewId;
 private String icone;
 private Menu menu;
 private List<Menu> listaMenu;

 public int getId() {
return id;
 }

 public void setId(int id) {
this.id = id;
 }

 public List<Menu> getListaMenu() {
return listaMenu;
 }

 public void setListaMenu(List<Menu> listaMenu) {
this.listaMenu = listaMenu;
 }

 public String getDescricao() {
return descricao;
 }

 public void setDescricao(String descricao) {
this.descricao = descricao;
}

 public String getIcone() {
 return icone;
 }

 public void setIcone(String icone) {
 this.icone = icone;
 }

 public Menu getMenu() {
 return menu;
 }

 public void setMenu(Menu menu) {
 this.menu = menu;
 }

 public String getViewId() {
 return viewId;
 }

 public void setViewId(String viewId) {
 this.viewId = viewId;
 }
}

Todos os campos da tab_menu representados no bean. Agora veremos a classe MenuDAO.java que representa outro padrão de projetos, o padrão DAO(Data Access Object) onde separamos a regra de negócio do acesso ao banco de dados.


package info.esolucao.sac.dao;

import info.esolucao.sac.beans.Menu;
import info.esolucao.sac.factory.ConnectionFactory;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author BENIGNO
 */
public class MenuDAO {

 Connection con;
 String sql;

 public boolean verificaSubMenu(Menu menu) {
 sql = "select count(*) as total from tab_menus where tab_menus_id=?";
 con = ConnectionFactory.getConnection();
 int t = 0;
 try {
 PreparedStatement pstm;
 pstm = con.prepareStatement(sql);
 pstm.setInt(1, menu.getId());
 ResultSet rs = pstm.executeQuery();
 if (rs.next()) {
 t = rs.getInt("total");
 }
 } catch (SQLException ex) {
 Logger.getLogger(MenuDAO.class.getName()).log(Level.SEVERE, null, ex);
 }
 return (t > 0);
 }

 public List<Menu> buscaPorMenu(Menu menu) {
 List<Menu> listaMenu = new ArrayList<Menu>();
 sql = "select * from tab_menus where tab_menus_id=?";
 con = ConnectionFactory.getConnection();
 try {
 PreparedStatement pstm = con.prepareStatement(sql);
 pstm.setInt(1, menu.getId());
 ResultSet rs = pstm.executeQuery();
 while (rs.next()) {
 Menu m = new Menu();
 m.setId(rs.getInt("id"));
 m.setDescricao(rs.getString("descricao"));
 m.setIcone(rs.getString("icone"));
 m.setViewId(rs.getString("viewId"));
 Menu subMenu = new Menu();
 subMenu = buscaPorId(rs.getInt("tab_menus_id"));
 m.setMenu(subMenu);
 listaMenu.add(m);
 }
 con.close();
 } catch (SQLException ex) {
 Logger.getLogger(MenuDAO.class.getName()).log(Level.SEVERE, null, ex);
 }
 return listaMenu;
 }

 public Menu buscaPorId(int id) {
 sql = "select * from tab_menus where id=?";
 con = ConnectionFactory.getConnection();
 Menu menu = new Menu();
 try {
 PreparedStatement pstm = con.prepareStatement(sql);
 pstm.setInt(1, id);
 ResultSet rs = pstm.executeQuery();
 if (rs.next()) {
 menu.setId(rs.getInt("id"));
 menu.setDescricao(rs.getString("descricao"));
 menu.setIcone(rs.getString("icone"));
 menu.setViewId(rs.getString("viewId"));
 Menu subMenu = new Menu();
 subMenu = buscaPorId(rs.getInt("tab_menus_id"));
 menu.setMenu(subMenu);
 }
 con.close();
 } catch (SQLException ex) {
 Logger.getLogger(MenuDAO.class.getName()).log(Level.SEVERE, null, ex);
 }
 return menu;
 }

 public List<Menu> listaTodos() {
 List<Menu> listaMenu = new ArrayList<Menu>();
 sql = "select * from tab_menus";
 con = ConnectionFactory.getConnection();
 try {
 PreparedStatement pstm = con.prepareStatement(sql);
 ResultSet rs = pstm.executeQuery();
 while (rs.next()) {
 Menu menu = new Menu();
 menu.setId(rs.getInt("id"));
 menu.setDescricao(rs.getString("descricao"));
 menu.setIcone(rs.getString("icone"));
 menu.setViewId(rs.getString("viewId"));
 Menu subMenu = new Menu();
 subMenu = buscaPorId(rs.getInt("tab_menus_id"));
 menu.setMenu(subMenu);
 listaMenu.add(menu);
 }
 con.close();
 } catch (SQLException ex) {
 Logger.getLogger(MenuDAO.class.getName()).log(Level.SEVERE, null, ex);
 }
 return listaMenu;
 }
}

Criei quatro métodos de acesso a dados do banco de dados, o primeiro public boolean verificaSubMenu(Menu menu), verifica se o menu tem filhos(submenus ou itens do menu) retornando verdadeiro ou falso. O segundo List<Menu> buscaPorMenu(Menu menu) busca todos os filhos do menu passado como parâmetro e retorna uma coleção do tipo Menu. O terceiro Menu buscaPorId(int id) retorna o Menu correspondente ao id passado como parâmetro. Por fim, o quarto método List<Menu> listaTodos() retorna todos os Menus cadastrados no banco de dados. Todos estes métodos nós utilizaremos na nossa classe de controle, no nosso bean gerenciado, que chamaremos de indexController.java.

Abaixo o código da classe indexController.java


package info.esolucao.sac.controllers;

import info.esolucao.sac.beans.Menu;
import info.esolucao.sac.dao.MenuDAO;
import java.util.List;
import javax.enterprise.context.RequestScoped;
import javax.faces.bean.ManagedBean;
import org.primefaces.component.menuitem.MenuItem;
import org.primefaces.component.submenu.Submenu;
import org.primefaces.model.DefaultMenuModel;
import org.primefaces.model.MenuModel;

/**
 *
 * @author BENIGNO
 */
@ManagedBean
@RequestScoped
public class indexController {

 private MenuModel menuModel;
 private MenuDAO menuDAO = new MenuDAO();

 public void geraMenu() {
 menuModel = new DefaultMenuModel();
 List<Menu> listaMenu = menuDAO.listaTodos(); // Substituir o listaTodos() pelos menus permitidos
 for (Menu menu : listaMenu) {
 if (menu.getMenu().getId() == 0) {
 Submenu submenu = new Submenu();
 submenu.setLabel(menu.getDescricao());
 for (Menu m : menuDAO.buscaPorMenu(menu)) {
 if (!menuDAO.verificaSubMenu(m)) {
 MenuItem mi = new MenuItem();
 mi.setValue(m.getDescricao());
 mi.setIcon("imagens/" + m.getIcone());
 submenu.getChildren().add(mi);
 } else {
 Submenu sm = new Submenu();
 sm.setLabel(m.getDescricao());
 sm = geraSubmenu(m);
 submenu.getChildren().add(sm);
 }
 }
 menuModel.addSubmenu(submenu);
 }
 }
 }

 public Submenu geraSubmenu(Menu menu) {
 Submenu submenu = new Submenu();
 submenu.setLabel(menu.getDescricao());
 for (Menu m : menuDAO.buscaPorMenu(menu)) {
 if (!menuDAO.verificaSubMenu(m)) {
 MenuItem mi = new MenuItem();
 mi.setValue(m.getDescricao());
 mi.setStyle("width:100px");
 submenu.getChildren().add(mi);
 } else {
 submenu.getChildren().add(geraSubmenu(m));
 }
 }
 return submenu;
 }

 public MenuModel getMenuModel() {
 return menuModel;

 }

 public indexController() {
 geraMenu();

 }
}

Como estamos trabalhando com JSF 2.0, definimos que uma classe é um bean gerenciado através da anotação @ManagedBean e  dizemos o escopo do bean é de request através da anotação @RequestScoped. O que antes nós faziamos em um arquivo xml separado, agora é feito através de anotações, de forma elegante e sem precisar criar linhas e mais linhas de xml.

No nosso bean gerenciado possuímos dois atributos e quatro métodos. O atributo menuModel, do tipo org.primefaces.model.MenuModel que fará binding com o menu na view, representando o menu que será exibido. O segundo atributo é o menuDAO do tipo MenuDAO, que será usados empre que precisarmos verificar alguma informação no banco de dados. Além dos dois atributos, temos os quatro métodos, dos quais, um é o construtor do indexController.java onde iremos chamar o método principal geraMenu(), para gerar o menu assim que a view for chamada e o outro é um get do menuModel que envia o atributo para a view quando referenciado na mesma.

Os outros dois métodos, são onde está o “pulo do gato”, são os principais métodos da criação dos menus dinâmicos. São eles o método  geraMenu que vai gerar a base do menu, pegando os menus que não possuem PAI e colocando eles na base do menu e o geraSubmenu, um método recursivo que gera toda a árvode de submenus para um menu passado como parâmetro.

Agora, vamos ver como ficará  a nossa view, a nossa página xhtml:


<html xmlns="http://www.w3.org/1999/xhtml"
 xmlns:p="http://primefaces.prime.com.tr/ui"
 xmlns:h="http://java.sun.com/jsf/html">
 <h:head>
<link href="./css/skin.css" rel="stylesheet" type="text/css" />
<link href="./css/default.css" rel="stylesheet" type="text/css" />
<title>SAC</title>
</h:head>
<h:body>
<center>
<p:panel header="Sistema de Avaliação de Competências" style="text-align: left;width: 850px; vertical-align: middle;">
<h:panelGrid columns="2">
<h:column>
<h:form>
<p:menu model="#{indexController.menuModel}"/>
</h:form>
</h:column>
<h:column>
<h:form>
<p:panel style="width: 600px; vertical-align: top;">
</p:panel>
 </h:form>
 </h:column>
 </h:panelGrid>
 </p:panel>
 </center>
 </h:body>
</html>

Ficou muito simples, não? Todo o trabalho ficou no indexController.java através do método geraMenu() e na nossa camada de visão apenas exibimos o que foi gerado. Atentem para o detalhe que estou usando um skin(skin.css)  para que a página fique com uma aparência melhor. Para aprender como usar skins e outras funcionalidades do primefaces, visitem o blog do meu amigo Wagner Borges: [url]http://quebrandoparadigmas.wordpress.com/2010/06/28/utilizando-skin-no-primefaces/[/url]

Bom, essa é a forma que gosto de trabalhar, se é a melhor ou não… fica a critério de vocês julgar.  Espero ter ajudado, qualquer dúvida é só mandar um comentário. Valeu!

Criando Gráficos Com Primefaces

Meu tempo está realmente mais curto trabalhos, consultoria e agora o curso de java da FAETE. Mas não vou deixar de escrever. E para continuar o assunto PrimeFaces eu vou apresentar o suporte a gráfico deste framework.

Exsitem duas formas de se desenhar gráficos em nossa aplicação web com o primefaces: Ou utilizamos seu suporte nativo que utiliza Flash para desenhar os gráficos ou usamos a integração do framework com o JFreeChart. A segunda opção é minha preferida por usar uma biblioteca já consagrada. Vou demostrar as duas formas.

Criando um novo Projeto

Para iniciar nossos exemplos vamos criar um novo projeto no netbeans 6.8 e vamos utilizar a especificação JEE6 com glassfish v3. Em caso de dúvida de como criar um projeto JSF 2.0 veja os post anteriores. Não esqueçam de adicionar nas bibliotecas do projeto o arquivo primefaces-2.0.1.jar, isso para que possamos utilzar as tag libs do primefaces em nossas páginas.

Graficos Utilizando o suporte Nativo.

O Primefaces possui alguns componente para criar diversos tipos de gráficos de forma bem simples e intuítiva, os tipos de gráficos são:

  • Pie Chart – Usado para desenhar gráficos do tipo pizza.

  • Line Chart – Usando para desenhar gráficos em Linha.


  • Column Chart – Usado para desenhar gráficos em coluna. Este mesmo gráfico existe a opção de ser desenhado na horizontal (Bar Chart).

  • Stacked (Column ou Bar) Chart – Usado para desenhar gráfico (de coluna) empilhado.

Para nosso primeio exemplo vamos criar um gráfico do tipo pizza. Para tanto devemos pensar o que nosso gráfico vai demostrar, que tipo de dado estatístico ele vai exibir. Aproveitando o ano eleitoral, vamos criar um gráfico que demostre a intenção de votos para alguns dos candidatos à presidencia da república. Antes de tudo vamos criar um nova classe que vai possuir apenas dois atributos: canditado e totalVotos. Nossa classe segue abaixo, eu a chamei de ConcorrenciaEleitoral e está no meu pacote modelo.


package modelo;

/**
 * criando em 23/05/2010
 * @author wagner
 */
public class ConcorrenciaEleitoral {
 private String candidato;
 private int totalVotos;

 public ConcorrenciaEleitoral() {
 }

 public ConcorrenciaEleitoral(String candidato, int totalVotos) {
 this.candidato = candidato;
 this.totalVotos = totalVotos;
 }

 public String getCandidato() {
 return candidato;
 }

 public void setCandidato(String candidato) {
 this.candidato = candidato;
 }

 public int getTotalVotos() {
 return totalVotos;
 }

 public void setTotalVotos(int totalVotos) {
 this.totalVotos = totalVotos;
 }
}

Agora já temos nossa classe capaz de armazenar as informações que precisamos. O próximo passo é criar nosso Managed Bean e adicionarmos um atributo que seja uma coleção de objetos da entidade ConcorrenciaEleitoral. Nosso Managed Bean vai ter aparecia do código abaixo, eu a chamei de ConcorrenciaEleitoralController e está no pacote controller:


package controller;

import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import modelo.ConcorrenciaEleitoral;

/**
 * criando em 23/05/2010
 * @author wagner
 */
@ManagedBean(name="concorrenciaEleitoral")
public class ConcorrenciaEleitoralController {
 private List<ConcorrenciaEleitoral> concorrencia = new ArrayList();

 public ConcorrenciaEleitoralController() {
 carregaDadosVotacao();
 }

 public List<ConcorrenciaEleitoral> getConcorrencia() {
 return concorrencia;
 }

 public void setConcorrencia(List<ConcorrenciaEleitoral> concorrencia) {
 this.concorrencia = concorrencia;
 }

 public void carregaDadosVotacao() {
 concorrencia.add(new ConcorrenciaEleitoral("José Serra", 650));
 concorrencia.add(new ConcorrenciaEleitoral("Dilma Rousseff", 450));
 concorrencia.add(new ConcorrenciaEleitoral("Marina Silva", 200));
 concorrencia.add(new ConcorrenciaEleitoral("Outros", 150));
 }
}

Olhando para nosso controlador não existe nenhuma novidade. Como já foi dito em post anteriores, no JSF 2.0 nós declaramos nossos Managed Beans através de anotações, ou seja, não precisamos mais fazer nenhuma configuração em arquivos XML (faces-config.xml). O nome do objeto que será criado será concorrenciaEleitoral, conforme esta nesta linha @ManagedBean(name=”concorrenciaEleitoral”). Essa declaração do nome ela é facultativo, quando não explicitamos o nome do objeto que será criado o nome dado é o mesmo nome da classe com a primeira letra em minusculo. Logo abaixo crie um atributo do tipo List que irá armazenar objetos do tipo ConcorrenciaEleitoral contendo as intenções de voto para cada canditato. Logo abaixo um método chamado carregaDadosVotacao foi criado para preencher a Lista com dados fictícios, esse método é chamado no construtor da classe para carregar a lista no momento da criação do objeto.

Agora devemos escrever nossa página que vai exibir nosso gráfico com essas informação. A tag lib, do primefaces, responsavel por desenhar um gráfico em pizza é a p:pieChart, e essa tah possui alguns atributos que merecem comentários:

  • value – É o atributo que esperaça a lista com os dados (a lista que será interada).
  • var – A variável que representa cada elemento da lista. (No nosso caso a variável irá representar cada objeto da nossa lista)
  • categoryField – Nesse atributo devemos informar qual o atributo de nossa classe de modelo representa a categoria quantificada, em nosso caso é o atributo canditado da nossa classe ConcorrenciaEleitoral
  • dataField – Nesse atributo informamos o atributo que possui o valor de uma determinada categoria, no nosso caso é o atributo totalVotos da classe ConcorrenciaEleitoral.

obs: para esse exemplo esses atributos que merecem destaques, mas existem atributos interessante que serão visto em um post seguinte.

A página index.xhml, depois de adicionada a tag lib p:pieChart com os atributos descritos acima, segue abaixo:



<?xml version='1.0' encoding='UTF-8' ?>

<!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:p="http://primefaces.prime.com.tr/ui">

<h:head>

<title>Gráficos com PrimeFaces</title>

</h:head>

<h:body>

<p:pieChart value="#{concorrenciaEleitoral.concorrencia}" var="concorrencia"

categoryField="#{concorrencia.candidato}" dataField="#{concorrencia.totalVotos}"/>

</h:body>

</html>

O resultado pode ser visto abaixo:

No próximo post vamos utilizar o mesmo projeto e as mesmas informações para também criar um gráfico de pizza, só que dessa vez vamos utilizar a integração com o JFreeChart.

um abraço e até o próximo.

Introdução ao JSF 2.0 com PrimeFaces parte II

Hoje eu vou mostrar mais um componente do primefaces e vou também falar um pouco sobre a nova forma de declarar Managed Beans no JSF 2.0. O componente que vou mostrar é o <p:collector />, esse componente é um facilitador para formulario do tipo  mestre-detalhe visto que ele inseri e remove objetos de uma lista a ele associado. O componente comumente está associado á um componente <h:commandButton> e um <h:dataTable />.

Criando nossas classes de Modelo e Managed Bean.

Seguindo o exemplo que foi dado no último post, a nossa estrutura de projeto deve está conforme a imagem exibida abaixo:

Estrutura do projeto

Por questão de organização e padronização nós vamos adicionar dois novos pacotes em nosso pacotes de código-fonte chamados de org.seed.exemploprime.managedbeans e org.seed.exemploprime.modelo. Para criar os pacotes basta clicar com o botão direito sobre a pasta Pacotes de código-fonte –> Novo –> Pacote Java. Dentro do pacote org.seed.exemploprime.modelo vamos adicionar uma classe java chamada de Aluno, a classe Aluno representa uma entidade de nosso sistema e é comumente chamada pela comunidade como um DTO (Data Transfer Object) e segue um padrão chamado de JavaBeans. A nossa classe é exibida abaixo:

package org.seed.exemploprime.modelo;

/**
 *criado em 27/04/2010
 * @author wagnerborges
 */
public class Aluno {
 private String matricula;
 private String nomeCompleto;
 private String login;
 private String senha;

 public String getLogin() {
 return login;
 }

 public void setLogin(String login) {
 this.login = login;
 }

 public String getMatricula() {
 return matricula;
 }

 public void setMatricula(String matricula) {
 this.matricula = matricula;
 }

 public String getNomeCompleto() {
 return nomeCompleto;
 }

 public void setNomeCompleto(String nomeCompleto) {
 this.nomeCompleto = nomeCompleto;
 }

 public String getSenha() {
 return senha;
 }

 public void setSenha(String senha) {
 this.senha = senha;
 }
}

Agora vamos adicionar no pacote org.seed.exemploprime.managedbeans uma classe chamada de AlunoManagedBean, essa classe vai interagir com nossa página capturando os eventos e dados fornecidos pelos usuários. Essa classe também é chamada de Backing Bean. A classe vai ficar como o código abaixo:


package org.seed.exemploprime.managedbeans;

import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import org.seed.exemploprime.modelo.Aluno;

/**
 *criado em 27/04/2010
 * @author wagnerborges
 */

@ManagedBean
@SessionScoped

public class AlunoManagedBean {
 private Aluno aluno = new Aluno();
 private List<Aluno> listaAlunos = new ArrayList();

 public Aluno getAluno() {
 return aluno;
 }

 public void setAluno(Aluno aluno) {
 this.aluno = aluno;
 }

 public List<Aluno> getListaAlunos() {
 return listaAlunos;
 }

 public void setListaAlunos(List<Aluno> listaAlunos) {
 this.listaAlunos = listaAlunos;
 }

public void create(){
 aluno = new Aluno();
 }


}

A classe acima merece alguns comentários. Como foi dito acima ela representa um managed bean, isso significa dizer que eu posso vincular (binding) seus atributos ou métodos com componentes de minhas páginas JSF. É essa caracteristica que torna o JSF uma framework orientado a componentes e a eventos. O que caractetiza nossa classe como sendo um bean gerenciado é a anotação @ManagedBean sobre a definição da classe. Essa é nova forma de se declarar  Managed Bean na nova especificação JSF, antes isso era feito em pelo menos 5 linhas em um arquivo xml chamdo de faces-config.xml que é o arquivo de configuração do Java Server Faces. Uma outra anotação que podemos perceber logo abaixo é a anotação @SessionScoped, essa anotação informa que o escopo de nosso bean gerenciado é de sessão, ou seja, enquanto durar minha sessão eu vou ter um objeto da classe AlunoManagedBean na sessão da minha aplicação. Análogo ao escopo de sessão existe o escopo de request referenciado pela anotação @RequestScoped onde um novo objeto é criado a cada requisição realizada pelo usuario. Ainda existem outros tipos de escopos: @ConversationScoped que cria um escopo de conversação entre duas páginas onde os objetos permanecem “vivos”  entre a pagina que originou o request até a página alvo. @ApplicationScoped que cria um escopo cujos os objetos são vistos por toda aplicação enquanto a aplicação estiver em execução.

Nossa classe AlunoManagedBean possui dois atributos: aluno da classe Aluno cujos atributos vamos vincular com os campos do nosso formulario e um atributo listaAlunos que é do tipo ArrayList que é onde vamos armazenar nossos objetos criado. A lista também será usada para exibir uma tabela com os objetos já cadastrados. Além dos dois atributos a classe possui um método chamado de create que será chamdo sempre que um novo objeto for inserido na lista, isso para que todos objetos sejam diferentes e não apontem para o mesmo endereço de memória.

Feito isso, a nova estrutura de nosso projeto deve está conforme imagem abaixo:

Nova Estrutura

O que vamos fazer agora é vincular nossa página index.xhtml com os atributos do nosso Bean Managed, mas qual é o nome do nosso Bean Managed? é o mesmo nome da classe? Antes do JSF2 deveriamos informa qual o nome do objeto que seria criado e referenciado nas páginas, mas agora quando colocamos a anotação @ManagedBean temos a opção de informa um nome ou não. Se desejarmos informar um nome fazemos assim: @ManagedBean(name=”alunoBean”), mas se não desejamos explicitar um nome para o nosso bean gerenciado um nome é criado tomando como base o nome da classe com a primeira letra em minusculo, então no nosso caso o objeto que será criado e que vamos referenciar em nossas páginas vai ser alunoManagedBean. Abaixo o código da nossa página index.html depois de alterado. Os comentários sobre os componentes vem logo em seguida.


<?xml version='1.0' encoding='UTF-8' ?>

<!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:p="http://primefaces.prime.com.tr/ui"

xmlns:f="http://java.sun.com/jsf/core">

<h:head>

<title>Facelet Title</title>

</h:head>

<h:body>

<h:panelGrid>

<p:messages />

<h:form>

<p:panel closable="true" footer="Cadastro" header="Cadastro de Alunos" style="width: 350PX">

<h:panelGrid columns="2">

<h:outputLabel value="Matricula:"/>

<h:inputText id="matricula" required="true" value="#{alunoManagedBean.aluno.matricula}"

requiredMessage="Campo [Matricula] obrigatório"/>

<h:outputLabel value="Nome Completo:"/>

<h:inputText id="nome" required="true" value="#{alunoManagedBean.aluno.nomeCompleto}"

requiredMessage="Campo [Nome Completo] obrigatório"/>

<h:outputLabel value="Nome p/ Login:"/>

<h:inputText id="login" required="true" value="#{alunoManagedBean.aluno.login}"

requiredMessage="Campo [Nome p/ login] obrigatório"/>

<h:outputLabel value="Senha:"/>

<p:password minLength="6" value="#{alunoManagedBean.aluno.senha}"

promptLabel="Digite uma senha segura"

goodLabel="Boa"

weakLabel="Razoável"

strongLabel="Excelente" />

<h:commandButton value="Cadastrar" action="#{alunoManagedBean.create}">

<p:collector value="#{alunoManagedBean.aluno}" addTo="#{alunoManagedBean.listaAlunos}"/>

</h:commandButton>

</h:panelGrid>

</p:panel>

</h:form>

<br/><br/>

<h:form>

<p:dataTable value="#{alunoManagedBean.listaAlunos}" var="aluno">

<p:column>

<f:facet name="header">

<h:outputText value="Matricula" />

</f:facet>

<h:outputText value="#{aluno.matricula}" />

</p:column>

<p:column>

<f:facet name="header">

<h:outputText value="Nome" />

</f:facet>

<h:outputText value="#{aluno.nomeCompleto}" />

</p:column>

<p:column>

<f:facet name="header">

<h:outputText value="Login" />

</f:facet>

<h:outputText value="#{aluno.login}" />

</p:column>

<p:column>

<f:facet name="header">

<h:outputText value="Remover" />

</f:facet>

<h:commandLink value="remover">

<p:collector value="#{aluno}" removeFrom="#{alunoManagedBean.listaAlunos}"/>

</h:commandLink>

</p:column>

</p:dataTable>

</h:form>

</h:panelGrid>

</h:body>

</html>

Vamos aos comentários

Primeiramente, fazemos a vinculação dos campos com os atributos:

<pre><h:inputText id="matricula" required="true" value="#{alunoManagedBean.aluno.matricula}" requiredMessage="Campo [Matricula] obrigatório"/></pre>

alunoManagedBean é o nome do objeto que foi criado da nossa classe AlunoManagedBean, aluno é um atributo da classe Aluno e nomeCompleto um atributo do objeto aluno.

O trecho abaixo mostra onde fazemos uso do componente <p:collector /> associado com um componente <h:commandButton />, o componente <h:commanButton/> possui um atributo chamado de action onde informamos qual o método que deverá ser executado quando o mesmo for pressionado. Nesse caso, a action associada a esse botão é o método create do nosso ManagedBean. Em seguida nosso componente <p:collector/> é adicionado com dois atributos, no atributo value é informado qual o objeto do ManagedBean se deseja armazenar na lista e no atributo addTo é informado em qual lista o objeto será amazeado.

<pre><h:commandButton value="Cadastrar" action="#{alunoManagedBean.create}">

<p:collector value="#{alunoManagedBean.aluno}" addTo="#{alunoManagedBean.listaAlunos}"/>

</h:commandButton></pre>

Em seguida criamos uma tabela informando no atributo value qual a lista que será exibida e um atributo var para informa o nome do objeto que está sendo interado pela lista.

<pre><p:dataTable value="#{alunoManagedBean.listaAlunos}" var="aluno"></pre>

Na tabela também adicionamos um link para remover objetos da lista utilizando o componente <p:collector> informando qual o objeto se deseja remover através do atributo value e de qual lista esse objeto será removido através do atributo removeFrom.

<pre><h:commandLink value="remover">

<p:collector value="#{aluno}" removeFrom="#{alunoManagedBean.listaAlunos}"/>

</h:commandLink></pre>

A imagem abaixo exibe nossa página index.xhtml em execução:

Resultado Final do Exemplo

Bom pessoal é isso aí. Espero que gostem e que seja útil.

abraços e até a próxima.