我正在使用PrimeFaces 5.3 <p:fileUpload>
上传PNG图片,我希望在保存到数据库之前在<p:graphicImage>
中显示它的预览。
这是一个MCVE:
<h:form enctype="multipart/form-data">
<p:fileUpload value="#{bean.uploadedFile}" mode="simple" />
<p:graphicImage value="#{bean.image}" />
<p:commandButton action="#{bean.preview}" ajax="false" value="Preview" />
</h:form>
private UploadedFile uploadedFile;
public UploadedFile getUploadedFile() {
return uploadedFile;
}
public void setUploadedFile(UploadedFile uploadedFile) {
this.uploadedFile = uploadedFile;
}
public void preview() {
// NOOP for now.
}
public StreamedContent getImage() {
if (uploadedFile == null) {
return new DefaultStreamedContent();
} else {
return new DefaultStreamedContent(new ByteArrayInputStream(uploadedFile.getContents()), "image/png");
}
}
在辅助bean上没有发生错误,图像不会加载并显示在前端。客户端提到图像返回404未找到错误。
答案 0 :(得分:11)
你的问题是双重的。它失败了,因为上传的文件内容是请求范围的,并且因为在不同的HTTP请求中请求了图像。为了更好地理解内部工作,请仔细阅读以下密切相关的Q&amp; A:
的答案要解决第一个问题,您需要在与表单提交相关联的操作方法中阅读上传的文件内容立即。在您的具体情况下,这将是:
private UploadedFile uploadedFile;
private byte[] fileContents;
public void preview() {
fileContents = uploadedFile.getContents();
}
// ...
要解决第二个问题,最好的办法是使用数据URI方案。这使得可以直接在完全相同的响应中呈现图像,因此您可以安全地使用@ViewScoped
bean而不会遇到“上下文不活动”问题或将byte[]
保存在会话或磁盘中以便允许在不同的请求中提供图像。 Browser support on data URI scheme目前相当不错。将以下全部<p:graphicImage>
替换为:
<ui:fragment rendered="#{not empty bean.uploadedFile}">
<img src="data:image/png;base64,#{bean.imageContentsAsBase64}" />
</ui:fragment>
public String getImageContentsAsBase64() {
return Base64.getEncoder().encodeToString(imageContents);
}
注意:我假设您可以使用Java 8,因为java.util.Base64
仅在该版本中引入。如果您使用的是较旧的Java版本,请改用DatatypeConverter.printBase64Binary(imageContents)
。
如果您碰巧使用JSF实用程序库OmniFaces,您也可以使用其<o:graphicImage>
组件,而不是<p:graphicImage>
能够直接引用byte[]
}和InputStream
bean属性并呈现数据URI。
<o:graphicImage value="#{bean.imageContents}" dataURI="true" rendered="#{not empty bean.imageContents}">