min*_*tnt 48 database jsf image primefaces jsf-2
我想显示的保存在数据库中的图像字节StreamedContent中<p:graphicImage>,如下所示:
<p:graphicImage value="#{item.imageF}" width="50" id="grpImage" height="80"/>
Run Code Online (Sandbox Code Playgroud)
private StreamedContent content; // getter and setter
public StreamedContent getImageF() {
if (student.getImage() != null) {
InputStream is = new ByteArrayInputStream(student.getImage());
System.out.println("Byte :"+student.getImage());
content = new DefaultStreamedContent(is, "", student.getStuID());
System.out.println("ddd ------------------------------- " + content);
return content;
}
return content;
}
Run Code Online (Sandbox Code Playgroud)
这将返回一个空白图像.这是怎么造成的,我该如何解决?
标准输出打印以下内容:
INFO: Byte :[B@a2fb48
INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent@b0887b
INFO: Byte :[B@a2fb48
INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent@1d06a92
INFO: Byte :[B@d52f0b
INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent@39a60
INFO: Byte :[B@d52f0b
INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent@8c3daa
INFO: Byte :[B@124728a
INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent@1dbe05b
INFO: Byte :[B@124728a
INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent@66a266
INFO: Byte :[B@a2fb48
INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent@1293976
INFO: Byte :[B@a2fb48
INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent@17b7399
INFO: Byte :[B@d52f0b
INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent@1e245a5
INFO: Byte :[B@d52f0b
INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent@4a7153
INFO: Byte :[B@124728a
INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent@1561bfd
INFO: Byte :[B@124728a
INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent@47a8c2
Run Code Online (Sandbox Code Playgroud)
Bal*_*usC 92
将<p:graphicImage>需要一个特殊的getter方法.它将在每个生成的映像中调用两次,每个映像都在完全不同的HTTP请求中.
第一个请求JSF页面的HTML结果的HTTP请求将首次调用getter,以便<img>在src属性中生成具有正确唯一且自动生成的URL 的HTML 元素,该URL 包含有关哪个bean和只要webbrowser即将请求图像,就应该调用getter.请注意getter确实在这一刻并不需要返回到图像显示的内容.它不会以任何方式使用,因为HTML不是如何工作的(图像不是在HTML输出中"内联",而是单独请求它们).
一旦webbrowser将HTTP结果作为HTTP响应检索,它将解析HTML源,以便将结果可视化地呈现给最终用户.一旦webbrowser <img>在解析HTML源代码时遇到一个元素,它就会在其src属性中指定的URL上发送一个全新的HTTP请求,以便下载该图像的内容并将其嵌入到可视化表示中.这将第二次调用getter方法,反过来应该返回实际的图像内容.
在您的特定情况下, PrimeFaces显然要么无法识别和调用getter以便检索实际的图像内容,要么getter没有返回预期的图像内容.#{item}变量名称的使用和日志中的大量调用表明您在a <ui:repeat>或a 中使用它<h:dataTable>.很可能,支持bean是请求作用域,并且在请求图像期间未正确保留datamodel,并且JSF将无法在正确的迭代轮次期间调用getter.视图范围的bean也不起作用,因为当浏览器实际请求图像时,JSF视图状态无处可用.
要解决这个问题,最好的办法就是重写getter方法,这样就可以在每个请求的基础上调用它,在这种情况下,你可以将唯一的图像标识符作为一个<f:param>而不是依赖于某些可能会"退出"的支持bean属性.在后续HTTP请求期间"同步".为此没有任何状态使用单独的应用程序范围的托管bean是完全有意义的.此外,a InputStream只能读取一次,而不能多次读取.
换句话说:永远不要声明StreamedContent任何InputStream甚至UploadedFile是bean属性; @ApplicationScoped当webbrowser实际请求图像内容时,只在无状态bean 的getter中创建它全新的.
例如
<p:dataTable value="#{bean.students}" var="student">
<p:column>
<p:graphicImage value="#{studentImages.image}">
<f:param name="studentId" value="#{student.id}" />
</p:graphicImage>
</p:column>
</p:dataTable>
Run Code Online (Sandbox Code Playgroud)
凡StudentImages支持bean可以是这样的:
@Named // Or @ManagedBean
@ApplicationScoped
public class StudentImages {
@EJB
private StudentService service;
public StreamedContent getImage() throws IOException {
FacesContext context = FacesContext.getCurrentInstance();
if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
// So, we're rendering the HTML. Return a stub StreamedContent so that it will generate right URL.
return new DefaultStreamedContent();
}
else {
// So, browser is requesting the image. Return a real StreamedContent with the image bytes.
String studentId = context.getExternalContext().getRequestParameterMap().get("studentId");
Student student = studentService.find(Long.valueOf(studentId));
return new DefaultStreamedContent(new ByteArrayInputStream(student.getImage()));
}
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,这是一个非常特殊的情况,其中以getter方法执行业务逻辑是完全合法的,考虑<p:graphicImage>到封面下的工作.在getter中调用业务逻辑通常是不受欢迎的,另请参阅为什么JSF多次调用getter.不要将此特殊情况作为其他标准(非特殊)情况的借口.另请注意,您不能使用传递方法参数的EL 2.2功能,#{studentImages.image(student.id)}因为此参数不会在图像URL中结束.因此,你真的需要传递它们<f:param>.
如果您碰巧使用OmniFaces 2.0或更新版本,那么考虑使用它<o:graphicImage>可以更直观地使用它,使用应用程序范围的getter方法直接委托给服务方法并支持EL 2.2方法参数.
因此:
<p:dataTable value="#{bean.students}" var="student">
<p:column>
<o:graphicImage value="#{studentImages.getImage(student.id)}" />
</p:column>
</p:dataTable>
Run Code Online (Sandbox Code Playgroud)
同
@Named // Or @ManagedBean
@ApplicationScoped
public class StudentImages {
@EJB
private StudentService service;
public byte[] getImage(Long studentId) {
return studentService.find(studentId).getImage();
}
}
Run Code Online (Sandbox Code Playgroud)
另请参阅有关该主题的博客.
这里有几种可能性(如果不是,请发布整个课程)。
1) 你没有正确初始化图像 2) 你的流是空的,所以你什么也没得到
我假设 student.getImage() 具有 byte[] 的签名,因此首先确保该数据实际上是完整的并代表图像。其次——你没有指定一个应该是“image/jpg”或任何你正在使用的内容类型。
这是一些用于检查的样板代码,我为此使用了 Primefaces 2。
/** 'test' package with 'test/test.png' on the path */
@RequestScoped
@ManagedBean(name="imageBean")
public class ImageBean
{
private DefaultStreamedContent content;
public StreamedContent getContent()
{
if(content == null)
{
/* use your database call here */
BufferedInputStream in = new BufferedInputStream(ImageBean.class.getClassLoader().getResourceAsStream("test/test.png"));
ByteArrayOutputStream out = new ByteArrayOutputStream();
int val = -1;
/* this is a simple test method to double check values from the stream */
try
{
while((val = in.read()) != -1)
out.write(val);
}
catch(IOException e)
{
e.printStackTrace();
}
byte[] bytes = out.toByteArray();
System.out.println("Bytes -> " + bytes.length);
content = new DefaultStreamedContent(new ByteArrayInputStream(bytes), "image/png", "test.png");
}
return content;
}
}
Run Code Online (Sandbox Code Playgroud)
和一些标记...
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.prime.com.tr/ui"
>
<h:head>
</h:head>
<h:body>
<p:graphicImage value="#{imageBean.content}" />
</h:body>
</html>
Run Code Online (Sandbox Code Playgroud)
如果该代码有效,那么您已正确设置。尽管它是流的垃圾代码(不要在生产中使用它),但它应该给你一个解决问题的点。我的猜测是,您的 JPA 或其他数据库框架中可能发生了一些事情,其中 byte[] 为空或格式错误。或者,您可能只是有内容类型问题。
最后,我将从 bean 中克隆数据,以便 student.getImage() 只会被复制到一个新数组中然后使用。这样,如果您有一些未知的事情发生(移动对象或更改 byte[] 的其他事情),您就不会弄乱您的流。
做类似的事情:
byte[] data = new byte[student.getImage().length]
for(int i = 0; i < data.length; i++)
data[i] = student.getImage()[i];
Run Code Online (Sandbox Code Playgroud)
这样你的 bean 就有一个副本(或 Arrays.copy()——无论你的船漂浮在什么地方)。我怎么强调像这样/内容类型这样简单的东西通常是错的。祝你好运。
尝试包含mime类型.在您发布的示例中,您将其设为"".空白图像可能是因为它不将流识别为图像文件,因为您将该字段设为空字符串.所以添加一个mime类型的image/png或image/jpg,看看是否有效:
String mimeType = "image/jpg";
StreamedContent file = new DefaultStreamedContent(bytes, mimeType, filename);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
83955 次 |
| 最近记录: |