quarta-feira, 17 de fevereiro de 2010

Menu dinâmico com Rich Faces

Olá, pessoal!
Nesse tutorial vou mostrar uma solução que encontrei para criar um menu dinâmico infinito multinível.

Primeiramente vamos criar a classe Menu:

public class Menu {

 private Long id;
 private String nome; //Rótulo do menu. 
 private String navegacao; //Nome da navegação cadastrada no faces-config.xml
 private Menu menuSuperior; //Elemento pai do menu caso haja.
 private TipoMenu tipoMenu;
 
 public Menu getMenuSuperior() {
  return menuSuperior;
 } 
 public TipoMenu getTipoMenu() {
  if (tipoMenu == null){
   tipoMenu = TipoMenu.ITEM;
  }
  return tipoMenu;
 }
 public String getNome() {
  return nome;
 }
 public String getNavegacao() {
  return navegacao;
 }
 public void setNome(String nome) {
  this.nome = nome;
 }
 public void setNavegacao(String navegacao) {
  this.navegacao = navegacao;
 }
 public void setMenuSuperior(Menu menuSuperior) {
  this.menuSuperior = menuSuperior;
 }
 public void setTipoMenu(TipoMenu tipoMenu) {
  this.tipoMenu = tipoMenu;
 }
 public Long getId() {
  return id;
 }
 public void setId(Long id) {
  this.id = id;
 }
}


A classe TipoMenu é um enumerador:

public enum TipoMenu {
 DROP_DOWN,
 GROUP,
 ITEM; 
}


Realizando o controle:

public class MenuControle {
 
 private HtmlToolBar htmlToolBar;
 private int countId = 1;
  
 @SuppressWarnings("unchecked")
 public HtmlToolBar getHtmlToolBar(){
  if (htmlToolBar == null){
   try{
    ArrayList<Menu> itens = (ArrayList<Menu>) getMenuDAO().listar(Menu.class); //UTILIZAR SEU MÉTODO DE LISTAGEM.

    FacesContext context = FacesContext.getCurrentInstance();  
    htmlToolBar = (HtmlToolBar) context.getApplication().createComponent(HtmlToolBar.COMPONENT_TYPE);
    htmlToolBar.setId("myToolBar" + countId++);

    //BOTÃO SAIR
    HtmlToolBarGroup htmlToolBarGroup = (HtmlToolBarGroup) context.getApplication().createComponent(HtmlToolBarGroup.COMPONENT_TYPE);
    htmlToolBarGroup.setLocation("right");
    htmlToolBarGroup.setId("myToolBarGroup" + countId++);
    
    HtmlMenuItem menu = (HtmlMenuItem) context.getApplication().createComponent(HtmlMenuItem.COMPONENT_TYPE);   
    menu.setValue("Sair");
    menu.setSubmitMode("ajax");
    MethodExpression action = context.getApplication().getExpressionFactory().createMethodExpression(context.getELContext(), "#{menuControle.logout}", String.class, new Class[]{});
    menu.setActionExpression(action);
    
    htmlToolBarGroup.getChildren().add(menu);
    htmlToolBar.getChildren().add(htmlToolBarGroup);
    
    if (itens == null || itens.isEmpty()){
     return htmlToolBar;
    }
    
    Map<Long, Map<Long, Menu>> menuTotal = new HashMap<Long, Map<Long, Menu>>();
      
    for (Menu item : itens) {   
     Long idPai = item.getMenuSuperior() == null ? 0L : item.getMenuSuperior().getId();   
     
     if (!menuTotal.containsKey(idPai)){
      menuTotal.put(idPai, new HashMap<Long, Menu>());
     }
     menuTotal.get(idPai).put(item.getId(), item);   
    }
    
    montaMenu(context, htmlToolBar, menuTotal, 0L);
        
   }catch (Exception e) {
    e.printStackTrace();
   }
  }
  return htmlToolBar;
 }
 
 public static void montaMenu(FacesContext context, UIComponent pai, Map<Long, Map<Long, Menu>> menuTotal, Long idPai){
        
        Iterator<Long> it = menuTotal.get(idPai).keySet().iterator();
  while (it.hasNext()) {
   Long key = it.next();
   Menu item = menuTotal.get(idPai).get(key);
   UIComponent novoPai = null;
   
   switch (item.getTipoMenu()) {
   case DROP_DOWN:
    HtmlDropDownMenu menuAdm = (HtmlDropDownMenu) context.getApplication().createComponent(HtmlDropDownMenu.COMPONENT_TYPE);
    menuAdm.setValue(item.getNome());
    pai.getChildren().add(menuAdm);
    novoPai = menuAdm;
    break;
   
   case GROUP:
    HtmlMenuGroup group = (HtmlMenuGroup) context.getApplication().createComponent(HtmlMenuGroup.COMPONENT_TYPE);
    group.setValue(item.getNome());
    pai.getChildren().add(group);
    novoPai = group;
    break;
    
   case ITEM:
    HtmlMenuItem menu = (HtmlMenuItem) context.getApplication().createComponent(HtmlMenuItem.COMPONENT_TYPE);   
    menu.setValue(item.getNome());    
    menu.setSubmitMode("ajax");
    MethodExpression action = context.getApplication().getExpressionFactory().createMethodExpression(context.getELContext(), item.getNavegacao(), null, new Class<?>[0]);
    menu.setActionExpression(action);
    pai.getChildren().add(menu);
    break;    
   }
   if (menuTotal.containsKey(key)){
    montaMenu(context, novoPai, menuTotal, key);
   }         
  }        
 }
 public String logout(){
  //TODO SEU MÉTODO DE SAÍDA.
  return "login";
 }
 public void setHtmlToolBar(HtmlToolBar htmlToolBar) {
  this.htmlToolBar = htmlToolBar;
 }
}


Agora basta inserir o menu no jsp:

<rich:toolBar binding="#{menuControle.htmlToolBar}"></rich:toolBar>

Não se esqueça de cadastrar a navegação no faces-config.xml.
Valew, galera!
Abraços!!!

7 comentários:

  1. Anderson, excelente dica. :P

    Eu quebrei muito a cabeça tentando deixar essa montagem do menu totalmente dinâmica e com essa sua dica ficou show de bola.

    Parabéns!

    ResponderExcluir
  2. Boa noite Anderson,

    Gostei muito da estrutura que vc montou para o menu dinamico mas estou com um problema e será que pode me ajudar?
    Fiz conforme o post e para fazer um teste adicionei um list de menu manualmente:

    Menu menu1 = new Menu();

    menu1.setId(1L);
    menu1.setNome("TESTE");
    menu1.setTipoMenu(TipoMenu.DROP_DOWN);


    o erro apresentado é:



    04/08/2010 00:37:35 com.sun.facelets.FaceletViewHandler handleRenderException
    SEVERE: Error Rendering View[/index.xhtml]
    javax.faces.FacesException: Parent menu for menu group (id=j_id5:j_id11) has not been found.


    Obrigado

    ResponderExcluir
  3. Opa...
    Tudo bem, Dudu!?
    Acabei de atualizar o código. Realmente havia um erro, os id's têm que ser definidos previamente.

    Qualquer coisa, estamos a disposição.
    Abraços!!!

    ResponderExcluir
  4. boa tarde anderson vc nao teria nenhum tutorial ensinando a criar menu dinamico com panelmenu + panelmenugroup

    cara ja to a mais de 15 dias tentando criar um menu destes so que, nao consigo fazer a parte de navegacao.
    meu email duzackzack@hotmail.com

    ResponderExcluir
    Respostas
    1. Eduardo,
      Ainda não utilizei o rich:panelMenu, mas acredito que substituindo o HtmlMenu nesse tutorial, deve funcionar. O difícil do menu dinâmico é a lógica de sua criação. Tente substituir, se der resultado positivo nos informe.
      Abraços!

      Excluir
  5. Este comentário foi removido pelo autor.

    ResponderExcluir
  6. Nessa linha de código está dando erro:
    (Logo após o hello world)
    binding="#{menuControle.htmlToolBar}"

    Erro-> #{...} Not allowed in a template text body.

    Isso acontece com todos os menus que eu já tentei utilizar :(

    Tentei entrar em contato contigo, Anderson, mas não achei nenhum e-mail aqui no site de contato...

    Valeu

    ResponderExcluir