如何在 p:dataTable 中使用 p:graphicImage 和 StreamedContent? [复制]

Posted

技术标签:

【中文标题】如何在 p:dataTable 中使用 p:graphicImage 和 StreamedContent? [复制]【英文标题】:How to use p:graphicImage with StreamedContent within p:dataTable? [duplicate] 【发布时间】: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;


【问题讨论】:

【参考方案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 的类型、消息和第一行通常是足够的信息。 完成了,好建议,知道像您这样的人使 *** 成为一个很棒的 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     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 中,它们就会被正确流式传输。

感谢和问候, 泽山

【讨论】:

以上是关于如何在 p:dataTable 中使用 p:graphicImage 和 StreamedContent? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如何在 PrimeFaces 3.0 的 p:dataTable 中设置 p:column 的宽度?

如何在 <p:dataTable> 中一次展开一行?

将样式应用于 p:datatable 中的 Header

如何从 p:dataTable 本身对 p:dataTable 进行 ajax 更新?

如何更改默认 p:dataTable emptyMessage 消息

如何以编程/动态方式将组件添加到 p:dataTable facet