在 p:graphicImage 预览中显示 p:fileupload 图像而不保存
Display p:fileupload image in p:graphicImage preview without saving it
我正在使用 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");
}
}
backing bean没有出错,前端不会加载和显示图片。客户提到图像返回了 404 未找到错误。
您的问题有两个方面。它失败了,因为上传的文件内容是请求范围的,并且因为图像是在不同的 HTTP 请求中请求的。为了更好地理解内部工作原理,请仔细阅读以下密切相关问答的答案:
- Display dynamic image from database with p:graphicImage and StreamedContent
- How to choose the right bean scope?
解决第一个问题,需要在表单提交关联的action方法中立即读取上传的文件内容。在您的具体情况下,它看起来像:
private UploadedFile uploadedFile;
private byte[] fileContents;
public void preview() {
fileContents = uploadedFile.getContents();
}
// ...
要解决第二个问题,最好的办法是使用数据 URI 方案。这使得直接在相同的响应中渲染图像成为可能,因此您可以安全地使用 @ViewScoped
bean 而不会遇到 "context not active" 问题或将 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
was only introduced in that version. In case you're using an older Java version, use DatatypeConverter.printBase64Binary(imageContents)
。
如果您碰巧使用 JSF 实用程序库 OmniFaces, you can also just use its <o:graphicImage>
组件,这与 <p:graphicImage>
相反,能够直接引用 byte[]
和 InputStream
bean 属性 并呈现数据 URI。
<o:graphicImage value="#{bean.imageContents}" dataURI="true" rendered="#{not empty bean.imageContents}">
我正在使用 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");
}
}
backing bean没有出错,前端不会加载和显示图片。客户提到图像返回了 404 未找到错误。
您的问题有两个方面。它失败了,因为上传的文件内容是请求范围的,并且因为图像是在不同的 HTTP 请求中请求的。为了更好地理解内部工作原理,请仔细阅读以下密切相关问答的答案:
- Display dynamic image from database with p:graphicImage and StreamedContent
- How to choose the right bean scope?
解决第一个问题,需要在表单提交关联的action方法中立即读取上传的文件内容。在您的具体情况下,它看起来像:
private UploadedFile uploadedFile;
private byte[] fileContents;
public void preview() {
fileContents = uploadedFile.getContents();
}
// ...
要解决第二个问题,最好的办法是使用数据 URI 方案。这使得直接在相同的响应中渲染图像成为可能,因此您可以安全地使用 @ViewScoped
bean 而不会遇到 "context not active" 问题或将 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
was only introduced in that version. In case you're using an older Java version, use DatatypeConverter.printBase64Binary(imageContents)
。
如果您碰巧使用 JSF 实用程序库 OmniFaces, you can also just use its <o:graphicImage>
组件,这与 <p:graphicImage>
相反,能够直接引用 byte[]
和 InputStream
bean 属性 并呈现数据 URI。
<o:graphicImage value="#{bean.imageContents}" dataURI="true" rendered="#{not empty bean.imageContents}">