Arquivo

Archive for the ‘PrimeFaces’ Category

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: