如何在 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】:<p:graphicImage>
将调用 getter 方法两次。第一次是将<img>
元素呈现为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[] 的形式保存。我上传了带有<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<Integer, byte[]>
。 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视图中,<p:graphicImage alt="image" value="#three.getImage(data)" cache="false" >
调用方法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 进行 ajax 更新?