【问题标题】:How to use p:graphicImage with StreamedContent within p:dataTable? [duplicate]如何在 p:dataTable 中使用 p:graphicImage 和 StreamedContent? [复制]
【发布时间】:2012-01-08 10:49:00
【问题描述】:

我想使用 PrimeFaces 数据表从数据库中动态加载图像。基于this PF forum topic的代码如下所示:

<p:dataTable id="tablaInventario" var="inv" value="#{registrarPedidoController.inventarioList}" paginator="true" rows="10"
    selection="#{registrarPedidoController.inventarioSelected}" selectionMode="single"                                     
    update="tablaInventario tablaDetalle total totalDesc" dblClickSelect="false" paginatorPosition="bottom">
    <p:column sortBy="producto.codigo" filterBy="producto.codigo">
        <f:facet name="header">#{msg.codigo}</f:facet>
        #{inv.producto.codProducto}
    </p:column>                            
    <p:column>
        <f:facet name="header">Foto</f:facet>
        <p:graphicImage id="photo" value="#{registrarPedidoController.streamedImageById}" cache="FALSE">
            <f:param name="inv" value="#{inv.id}" />
        </p:graphicImage>                                
    </p:column>
</p:dataTable>

public StreamedContent getStreamedImageById() {
    DefaultStreamedContent image = null;
    String get = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("inv");
    System.out.println("[Param]: " + get); // This prints null.
    Long id = new Long(get);
    List<Inventario> listInventarios = controladorRegistrarPedido.listInventarios();

    for (Inventario i : listInventarios) {
        if (i.getId().compareTo(id) == 0) {
            byte[] foto = i.getProducto().getFoto();
            image = new DefaultStreamedContent(new ByteArrayInputStream(foto), "image/png");
        }
    }

    return image;
}

但是我无法让它工作。我的参数正在将“null”传递给我的支持 bean。这是如何引起的,我该如何解决?

我正在使用 Netbeans 6.9.1、JSF 2.0 和 Primefaces 2.2.RC2。

我继续使用 BalusC 第一个解决方案,它运行良好,但图像没有在 UI 中呈现。 Glassfish 抛出异常:

WARNING: StandardWrapperValve[Faces Servlet]: PWC1406: Servlet.service() for servlet Faces Servlet threw exception
java.lang.NullPointerException
        at com.sun.faces.mgbean.BeanManager$ScopeManager$ViewScopeHandler.isInScope(BeanManager.java:552)

看来,感谢 BalusC,我可以开始工作了。我已经使用 RequestScoped、SessionScoped 或 ApplicationScoped 来管理 getStreamedImageId。但是,在 UI 中始终设置默认图像(对于 null 情况),而不是按预期设置与每一行对应的图像。新代码是:

public StreamedContent streamedById(Long id) {
    DefaultStreamedContent image = null;

    System.out.println("[ID inventario]: " + id);

    List<Inventario> listInventarios = controladorRegistrarPedido.listInventarios();
    for (Inventario i : listInventarios) {
        if (i.getId().equals(id)) {
            byte[] foto = i.getProducto().getFoto();
            if (foto != null) {
                System.out.println("   [Foto]: " + foto);
                image = new DefaultStreamedContent(new ByteArrayInputStream(foto), "image/png");
                break;
            }
        }


    }
    if (image == null) {
        System.out.println("       [Image null]");
        byte[] foto = listInventarios.get(0).getProducto().getFoto();
        image = new DefaultStreamedContent(new ByteArrayInputStream(foto), "image/png");
    }

    System.out.println("   [Foto Streamed]: " + image);

    return image;

}

【问题讨论】:

    标签: image jsf jsf-2 datatable primefaces


    【解决方案1】:

    &lt;p:graphicImage&gt; 将调用 getter 方法两次。第一次是将&lt;img&gt; 元素呈现为HTML,因此需要src 属性中的URL。如果您只返回new DefaultStreamedContent(),那么它将在src 属性中自动生成正确的URL。第二次是浏览器真正请求图片的时候,此时你应该返回实际的图片。

    所以,getter 方法基本上应该是这样的:

    public StreamedContent getStreamedImageById() {
        FacesContext context = FacesContext.getCurrentInstance();
    
        if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
            // So, we're rendering the view. Return a stub StreamedContent so that it will generate right URL.
            return new DefaultStreamedContent();
        }
        else {
            // So, browser is requesting the image. Get ID value from actual request param.
            String id = context.getExternalContext().getRequestParameterMap().get("id");
            Image image = service.find(Long.valueOf(id));
            return new DefaultStreamedContent(new ByteArrayInputStream(image.getBytes()));
        }
    }
    

    【讨论】:

    • BalusC 质量上乘的优秀答案。我采用了第一个解决方案,它正在使用 long 参数,并且我从数据库中获取图像,但是没有在 UI 中呈现,我检查了 Glassfish 日志并且存在一些异常,知道吗? (我添加到我的帖子中。)
    • 我会先分享例外情况,因为它们本身通常已经是完整的答案。 stacktrace 的类型、消息和第一行通常是足够的信息。
    • 完成了,好建议,知道像您这样的人使 stackoverflow 成为一个很棒的 wiki 社区是件好事吗?继续加油!
    • p:graphicImage 内容提供服务的 bean 需要是请求或会话范围的(如果它是无状态的,甚至是应用程序范围)。不支持视图范围。您需要将视图范围 bean 中的方法拆分为适当范围内的单独 bean。这还有一个额外的好处,那就是它可以更好地在其他地方重复使用。
    • 是的!这是一个很好的观点,我想我几乎准备好了。现在没有抛出异常,但是没有呈现图像(但是,如果我在 UI 中的 registrarPedidoController.getStreamedImageById(1) 中硬编码 1 ,它可以工作(当然会带来相同的图像)。我看到我的日志并且有一个奇怪的情况,有一点它正在寻找等于 0 的 id(当我的数据库中没有它时);我应该管理这种情况还是空图像?我应该在 getStreamedImageById 方法中为这些情况返回什么?
    【解决方案2】:

    在 PrimeFaces 3.2 中,该错误仍然存​​在。我解决了

    <p:graphicImage value="#{company.charting}">
        <f:param id="a" name="a" value="#{cc.attrs.a}" />
        <f:param id="b" name="b" value="#{cc.attrs.b}" />
    </p:graphicImage>
    

    ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
    String a= externalContext.getRequestParameterMap().get("a");
    String b= externalContext.getRequestParameterMap().get("b");
    

    但即使这样,bean 也会被调用 2 次。但是在第二个调用变量中 a + b 被填充了 ;-)

    该死的虫子

    【讨论】:

    • 感谢这很有用。在一个请求中,参数为空,而在另一个请求中,它被填充,因此只有一个属性就足够了。只需要在开始时检查参数不为空。
    【解决方案3】:

    如果我们通过休眠将图像保存在数据库中,则它们会以 byte[] 的形式保存。我上传了带有&lt;p:fileUpload...标签的图像,然后我使用休眠将图像与其他数据值一起保存。

    在第二页上,我正在使用

    显示整个表格数据(当然还有图像)
    <p:dataTable  var="data" value="#{three.all}" ....
    

    和动态图像使用

    <p:graphicImage   alt="image"  value="#{three.getImage(data)}" cache="false"  >
                    <f:param id="image_id" name="image_id" value="#{data.number}" />
    </p:graphicImage></p:dataTable>
    

    这里的“三”是Backing Bean的名称。在方法getAll() 中,我通过休眠从表中检索数据,并且在相同的方法中,我创建了一个HashMap&lt;Integer, byte[]&gt;。 HashMap 是 bean 的实例变量,而 Bean 是 SessionScoped。我将images(采用byte[] 形式)与一个整数image_id 放在一起。

    代码:

        for (int i=0; i<utlst.size(); i++ ){
                 images.put(utlst.get(i).getNumber(), utlst.get(i).getImage());}
    //utlst is the object retrieved from database. number is user-id.
    

    在getImage.xhtml视图中,&lt;p:graphicImage alt="image" value="#{three.getImage(data)}" cache="false" &gt;调用方法getImage(data /*I am passing current object of the list which is being iterated by*/ )

    getImage 代码:

    public StreamedContent getImage(Util ut) throws IOException {
           //Util is the pojo
    
              String image_id = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("image_id");
              System.out.println("image_id: " + image_id);
    
              if (image_id == null) {
    
                    defaultImage=new DefaultStreamedContent(FacesContext.getCurrentInstance().getExternalContext().getResourceAsStream("/Capture.PNG"), "image/png");
    
                return defaultImage; 
            }
    
    
             image= new DefaultStreamedContent(new ByteArrayInputStream(images.get(Integer.valueOf(image_id))), "image/png");
    
            return image;
        }
    

    只需将带有 id 的动态图像保存在会话中的 A HashMap 中,它们就会被正确流式传输。

    感谢和问候, 泽山

    【讨论】:

      猜你喜欢
      • 2012-03-08
      • 1970-01-01
      • 2013-08-15
      • 2017-02-03
      相关资源
      最近更新 更多