在<p:megamenu> </p:megamenu> </p:menuitem> </o:graphicimage>的<p:menuitem>中实现<o:graphicimage>而不是icon

时间:2015-01-13 03:08:53

标签: jsf-2 primefaces omnifaces megamenu graphicimage

好吧,标题有点令人困惑,但我无法弄清楚如何用单句来解决我的问题。

所以这是交易: 我需要以某种方式实现Primefaces中的graphicImage组件(甚至更好,Omnifaces,因为我从数据库加载图像,我已经在应用程序中使用o:graphicImage)在MenuItem组件中,以便在MegaMenu组件中显示它,该组件是使用创建的DefaultMenuModel以编程方式创建的在支持豆。另外(如上所述),图像是从数据库加载的,所以我想通过css加载这些图像(图标)的解决方案不适用,因为图像是动态的。

我尝试了很多方法但是(不用说)我很遗憾地失败了:-(。我没有任何编写完整堆栈Primefaces自定义组件的经验,因此我尝试使用MegaMenu组件的一些基本自定义渲染器。例如,我试图使用来自o:graphicImage组件(encodeBegin和encodeEnd)的代码,并在我的CustomMegaMenuRenderer(它扩展MegaMenuRenderer)中实现它在重写方法encodeMenuItemContent。我使用小hack传递EL表达式(如#{imageStreamer.getImage(23) },其中23是实际图像id)将此字符串作为模型中MenuItem组件的'icon'字段的值传递。然后,在重写的encodeMenuItemContent中,我检查它是否实际上是el(而不是图标名称)我做这样的事情:< / p>

writer.startElement("img", null);
writer.writeURIAttribute("src", getSrc(context, expresion), "value");
writeAttributes(writer, this, GraphicImage.ATTRIBUTE_NAMES);
writer.endElement("img");

其中getSrc(context,expression)的实现方式如下:

private String getSrc(FacesContext context, String expression) throws IOException {
    Resource resource;
    ExpressionFactory ef = context.getApplication().getExpressionFactory();
    ValueExpression dynExpression = ef.createValueExpression(context.getELContext(), expression, Object.class);
    resource = GraphicResource.create(context, dynExpression, null);
    return context.getExternalContext().encodeResourceURL(resource.getRequestPath());
}

但不幸的是,getSrc(context,expression)无法返回字符串内容,就像它在正常crated o:graphicImage组件中一样。

我还尝试了一些其他的方法,比如在我的渲染中以编程方式实例化graphicImage组件(来自Primefaces或Omnifaces),然后在对象上调用encodeAll方法但是也失败了......

GraphicImage gi = (GraphicImage) application.createComponent(GraphicImage.COMPONENT_TYPE);
gi.getAttributes().put("value", expression);
gi.encodeAll(context);

所以我得出结论,我错过了一些非常重要的东西。我试图在SO和谷歌上找到类似的东西,但无法成功。所以,这里是我真正的问题(假设我的方法很糟糕):

  1. 事件是否可以实例化每个主要/全方位 自定义渲染器中的组件,使其工作原样 通常工作(所以它按照预期呈现)?我猜这个 是让渲染器按需运行的最简单方法......
  2. 我应该继续使用这种“自定义渲染器”方法吗? 在这种情况下无用吗?
  3. 我是否必须自定义MenuModel,MenuItem或MegaMenu类 为了创建上面解释的这个功能?
  4. 最后,理论上最简单的方法是实现这一目标 什么是实现这一目标的“最佳”方式(因此它与之相符 primefaces组件设计,实际上这应该“完成”了吗?
  5. 另外要提一下(但我猜它超出了范围),我在Tomcat 8上使用JSF MOJARRA 2.2.9,Primefaces 5.1,Omnifaces 2.0和Weld。

    提前致谢。

1 个答案:

答案 0 :(得分:0)

据我了解,你试图使用类似的东西:

<p:menuitem ... icon="#{imageStreamer.getImage(23)}" />

这确实行不通。当渲染器获得它时,将立即对其进行评估。这也不是<o:graphicImage>的工作原理。它将评估推迟到浏览器实际需要请求图像的那一刻。

您最好的选择是传递图像标识符:

<p:menuitem ... icon="23" />

(可安全地表达为icon="#{bean.iconId}"

然后你可以按如下方式渲染它:

@Override
protected void encodeMenuItemContent(FacesContext context, AbstractMenu menu, MenuItem menuitem) throws IOException {
    ResponseWriter writer = context.getResponseWriter();
    String imageId = menuitem.getIcon();
    Object value = menuitem.getValue();

    if (imageId != null) {
        ValueExpression expression = Components.createValueExpression("#{imageStreamer.getImage(" + imageId + ")}", Object.class);
        GraphicResource resource = GraphicResource.create(context, expression, null);
        String src = context.getExternalContext().encodeResourceURL(resource.getRequestPath());
        writer.startElement("img", null);
        writer.writeURIAttribute("src", src, null);
        writer.endElement("img");
    }

    // ...
}

(你非常接近,唯一不幸的是你没有展示你是如何创建的expression以及它究竟是如何失败的,因此确切的原因可以被精确定位)