【问题标题】:Implement <o:graphicImage> instead of icon in <p:menuitem> of <p:megaMenu>在 <p:megaMenu> 的 <p:menuitem> 中实现 <o:graphicImage> 而不是 icon
【发布时间】:2015-03-10 22:43:55
【问题描述】:

好的,标题有点混乱,但我不知道如何用一句话来解决我的问题。

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

我尝试了很多方法,但(不用说)我很遗憾地失败了 :-(。我没有任何编写全栈 Primefaces 自定义组件的经验,所以我尝试使用一些基本的 MegaMenu 组件自定义渲染器。例如,我尝试使用来自 o:graphicImage 组件(encodeBegin 和 encodeEnd)的代码并在我的 CustomMegaMenuRenderer(它扩展了 MegaMenuRenderer)中的重写方法 encodeMenuItemContent 中实现它。我使用小技巧来传递 EL 表达式(如 #{imageStreamer.getImage(23) },其中 23 是实际图像 ID)将此字符串作为模型中 MenuItem 组件的“图标”字段的值传递。然后,在覆盖的 encodeMenuItemContent 中,我检查它是否实际上是 el(而不是图标名称),我执行以下操作:

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) 无法像在通常装箱的 o:graphicImage 组件中那样返回字符串内容。

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

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

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

  1. 是否可以实例化每个primefaces/omnifaces 自定义渲染器中的组件并使其正常工作 正常工作(所以它按预期呈现)?我猜这个 将是让我的渲染器按需要工作的最简单方法...
  2. 我应该继续使用这种“自定义渲染器”方法还是 在这种情况下没用?
  3. 我是否必须在其中创建自定义 MenuModel、MenuItem 或 MegaMenu 类 为了创建上面解释的这个功能?
  4. 最后,理论上最简单的方法是什么? 以及实现这一目标的“最佳”方式是什么(因此它与 primefaces 组件设计,实际上“应该”如何完成)?

另外提一下(但我猜它超出了范围),我在 Tomcat 8 上使用 JSF MOJARRA 2.2.9、Primefaces 5.1、Omnifaces 2.0 和 Weld。

提前致谢。

【问题讨论】:

    标签: jsf-2 primefaces omnifaces megamenu graphicimage


    【解决方案1】:

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

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

    这确实行不通。当渲染器获得它时,它会立即被评估。这也不是&lt;o:graphicImage&gt; 的工作方式。它将评估推迟到浏览器实际需要请求图像的那一刻。

    最好的办法是传递图像标识符:

    <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 以及它究竟是如何失败的,以便可以查明确切的原因)

    【讨论】:

    • 感谢 BalusC,您真的很有帮助。看来我的代码中唯一的问题是模型代码中的这一行:item.setIcon("#{imageSteramer.getImage(" + c.getIcon().getId() + ")}"); 其中 item 是 DefaultMenuItem 对象。我应该只是传递图像 ID,然后在我的渲染器中伪造表达式,就像您在答案中指出的那样。失败消息是 FATAL: Target Unreachable, identifier 'imageSteramer' resolve to null 但我无法正确理解它。所以,我想你又是对的,我真的很接近...... :)。再次感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多