[RESOLVIDO] Menu Dinâmico em JSF

Bom Dia Galera,

To com uma dúvida e gostaria da ajuda de vocês.

Preciso criar um menu dinâmico, estou usando Primefaces.

FIz um ManagedBean para criar o Menu e um xhtml para exibir, ficou mais ou menos assim:

ManagedBean:

@ManagedBean(name = "controleMenuMB")
@SessionScoped
public class ControleMenuManagedBean implements ActionListener {

	private MenuModel menuModel;
	protected static UIViewRoot uiViewRoot = new UIViewRoot();

	@EJB
	private ModuloBusinessRemote moduloBusiness;

	@EJB
	private PaginaBusinessRemote paginaBusiness;

	@PostConstruct
	public void init() {
		this.geraListaModulos();
	}

	public MenuModel geraListaModulos() {
		this.menuModel = new DefaultMenuModel();
		Submenu submenu;
		MenuItem item;

		try {

			for (Modulo modulo : this.moduloBusiness.listar()) {

				submenu = new Submenu();

				submenu.setLabel(modulo.getNome());

				for (Pagina pagina : this.paginaBusiness.listar()) {

					if (pagina.getModulo().getId().equals(modulo.getId())) {
						item = new MenuItem();

						item.setValue(pagina.getNome());
						item.setUrl(pagina.getUrl());
						item.setAjax(false);
						item.setId(uiViewRoot.createUniqueId());
						item.addActionListener(this);

						submenu.getChildren().add(item);
					}
				}

				this.menuModel.addSubmenu(submenu);

			}

		} catch (Exception e) {
			e.printStackTrace();
		}
		return this.menuModel;
	}

	@Override
	public void processAction(ActionEvent event) throws AbortProcessingException {
		System.out.println("Entro no processAction");
	}

	public MenuModel getMenuModel() {
		return menuModel;
	}
}

Xhtml:

<p:menubar model="#{controleMenuMB.menuModel}">

Mas não consigo identificar uma forma de fazer a seguinte ação: Quando algum link for clicado, chamar o método processAction da interface ActionListener.

Alguém pode ajudar?

Nunca fiz dessa forma, sempre adiciono uma action ao item;

item.setActionExpression(MethodExpression);

Vc tem que criar sua própria implementação do MethodExpression, instanciando ele e adicionando uma ação ao Method, tem umas coisas no google sobre isso.

Boa tarde,

Tente algo do tipo:

item.addActionListener(createMethodActionListener("#{menuController.alterarPerfilAction}", Void.TYPE, new Class[] { ActionEvent.class }));

Att

Opa Galera, brigadão pela ajuda,

Então, fiz assim:


import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.el.ExpressionFactory;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ActionEvent;
import javax.faces.event.ActionListener;
import javax.faces.event.MethodExpressionActionListener;

import org.primefaces.component.menuitem.MenuItem;
import org.primefaces.component.submenu.Submenu;
import org.primefaces.model.DefaultMenuModel;
import org.primefaces.model.MenuModel;

import br.com.ePrescon.business.modulo.ModuloBusinessRemote;
import br.com.ePrescon.business.pagina.PaginaBusinessRemote;
import br.com.ePrescon.crud.Modulo;
import br.com.ePrescon.crud.Pagina;

@ManagedBean(name = "controleMenuMB")
@ViewScoped
public class ControleMenuManagedBean implements ActionListener {

	private MenuModel menuModel;

	@EJB
	private ModuloBusinessRemote moduloBusiness;

	@EJB
	private PaginaBusinessRemote paginaBusiness;

	@PostConstruct
	public void init() {
		this.geraListaModulos();
	}

	public MenuModel geraListaModulos() {
		this.menuModel = new DefaultMenuModel();
		Submenu submenu;
		MenuItem item;

		try {

			for (Modulo modulo : this.moduloBusiness.listar()) {

				submenu = new Submenu();

				submenu.setLabel(modulo.getNome());

				for (Pagina pagina : this.paginaBusiness.listar()) {

					if (pagina.getModulo().getId().equals(modulo.getId())) {
						item = new MenuItem();

						item.setId(new UIViewRoot().createUniqueId());
						item.setValue(pagina.getNome());
						item.setUrl("#");
						item.setAjax(false);

						ExpressionFactory factory = FacesContext.getCurrentInstance().getApplication().getExpressionFactory();
						MethodExpressionActionListener methodExpression = new MethodExpressionActionListener(factory.createMethodExpression(FacesContext.getCurrentInstance().getELContext(),
						        "#{controleMenuMB.processAction}", Void.TYPE, new Class[] { ActionEvent.class }));

						item.addActionListener(methodExpression);

						submenu.getChildren().add(item);
					}
				}

				this.menuModel.addSubmenu(submenu);

			}

		} catch (Exception e) {
			e.printStackTrace();
		}
		return this.menuModel;
	}

	@Override
	public void processAction(ActionEvent event) throws AbortProcessingException {
		System.out.println("Entro no processAction");
	}

	public MenuModel getMenuModel() {
		return menuModel;
	}
}

Mas ainda não funciona, acho que ele nem entra no processAction.
Continuo extendendo a interface ActionListener

Vou te mandar o código e tenta achar algo diferente, mas aqui isso funciona =/


public void selectorSistemaAction(ActionEvent event) {
		try{
			...
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

public MenuItem obterSeletorSistema() {
		MenuItem item = new MenuItem();
		item.setValue("Inicio");
		item.addActionListener(createMethodActionListener(
				"#{menuController.selectorSistemaAction()}", Void.TYPE,
				new Class[] { ActionEvent.class }));
		item.setAjax(false);
		item.setIcon("ui-icon ui-icon-home");

		return item;
	}

Espero que ajude.

Esse método createMethodActionListener, ele é algum método de alguma interface?

Devia ser esse código que estava faltando, tenta ai.


private MethodExpressionActionListener createMethodActionListener(
			String valueExpression, Class<?> valueType,
			Class<?>[] expectedParamTypes) {
		MethodExpressionActionListener actionListener = null;
		try {
			actionListener = new MethodExpressionActionListener(
					createMethodExpression(valueExpression, valueType,
							expectedParamTypes));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return actionListener;
	}

Abraços

Opa,

Voltando aqui pra posta a solução que achei.

Para gerar o menu dinâmico usando o menubar JSF, fiz da seguinte forma:

No xhtml:

&lt;h:form&gt;
    &lt;p:menubar model="#{controleMenuMB.menuModel}"/&gt;
&lt;/h:form&gt;

No ControleMenuManagedBean:

@ViewScoped
public class ControleMenuManagedBean {
	private String url;
	private MenuModel menuModel;

	@EJB
	private ModuloBusinessRemote moduloBusiness;

	@EJB
	private PaginaBusinessRemote paginaBusiness;

	@PostConstruct
	public void init() {
		this.geraListaModulos();
	}

	public MenuModel geraListaModulos() {
		this.menuModel = new DefaultMenuModel();
		Submenu submenu;
		MenuItem item;

		try {

			for (Modulo modulo : this.moduloBusiness.listar()) {

				submenu = new Submenu();

				submenu.setLabel(modulo.getNome());

				for (Pagina pagina : this.paginaBusiness.listar()) {

					if (pagina.getModulo().getId().equals(modulo.getId())) {
						item = new MenuItem();

						item.setValue(pagina.getNome());
						item.setAjax(false);
						item.setActionExpression(this.createExpression(&quot;#{controleMenuMB.getItemMenuSelecionado}&quot;, String.class, null));
						item.addActionListener(this.createPropertyActionListener(&quot;#{controleMenuMB.url}&quot;, pagina.getUrl()));

						submenu.getChildren().add(item);
					}
				}

				this.menuModel.addSubmenu(submenu);
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
		return this.menuModel;
	}

	public void getItemMenuSelecionado() {
		System.out.println(&quot;Entro no getMenu&quot;);

		FacesContext facesContext = FacesContext.getCurrentInstance();

		String url = this.getUrl();

		System.out.println(&quot;URL: &quot; + url);
	}

	private MethodExpression createExpression(final String expression, final Class&lt;?&gt; returnType, final Class&lt;?&gt;[] parameters) {

		FacesContext facesContext = FacesContext.getCurrentInstance();
		Application application = facesContext.getApplication();
		ExpressionFactory expressionFactory = application.getExpressionFactory();
		ELContext elContext = facesContext.getELContext();

		return expressionFactory.createMethodExpression(elContext, expression, returnType, parameters);
	}

	private ValueExpression createValueExpression(final String expression, final Class&lt;?&gt; expectedType) {
		final ExpressionFactory expressionFactory;
		final ELContext elContext;
		FacesContext facesContext = FacesContext.getCurrentInstance();

		expressionFactory = facesContext.getApplication().getExpressionFactory();
		elContext = facesContext.getELContext();

		return expressionFactory.createValueExpression(elContext, expression, expectedType);
	}

	public MenuModel getMenuModel() {
		return menuModel;
	}

	private SetPropertyActionListenerImpl createPropertyActionListener(final String expression, final Object value) {
		final ExpressionFactory expressionFactory;
		FacesContext facesContext = FacesContext.getCurrentInstance();

		expressionFactory = facesContext.getApplication().getExpressionFactory();

		return new SetPropertyActionListenerImpl(createValueExpression(expression, value.getClass()), expressionFactory.createValueExpression(value, value.getClass()));
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

Basicamente, eu fiz da seguinte forma:

Criei um private MenuModel menuModel; e criei seus getters e setters.

Criei um método init anotado com @PostConstruct e nesse método, chamo o método geraListaModulos()

Nesse método eu percorro uma lista com os módulos e adiciono a um submenu.
Depois percorro uma lista de paginas e jogo a um menuItem, mas só pego as páginas que pertecem a esse módulo.
Depois jogo esse menuItem no subMenu.

O que eu estava errando, é que quando coloco item.setUrl(), ele gerava um erro.
Então, basicamente, tem que tirar esse setUrl e criar propertyActionListener passando a variavel url como parâmetro.
Além do propertyActionListener, também crio um action chamado getItemMenuSelecionado().

Nesse getItemMenuSelecionado() eu pego a url que foi passada na propertyActionListener e ai manipulo do jeito que preciso.

O banco de dados é simples, seria:

Módulo { ID, NOME}
Página {ID, NOME, URL, MODULO_ID}

Valeu pela ajuda pessoal.
Abraços.