Display p:fileupload image in p:graphicImage preview without saving it

江枫思渺然 提交于 2019-11-30 04:08:59

问题


I am using PrimeFaces 5.3 <p:fileUpload> to upload a PNG image and I would like to show a preview of it in <p:graphicImage> before saving in database.

Here's a 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"); 
    }
}

No error occurring on the backing bean, and the image won't be load and display at front-end. The client mentions that the image returned a 404 not found error.


回答1:


Your problem is two-fold. It failed because the uploaded file contents is request scoped and because the image is requested in a different HTTP request. To better understand the inner working, carefully read the answers on following closely related Q&A:

  • Display dynamic image from database with p:graphicImage and StreamedContent
  • How to choose the right bean scope?

To solve the first problem, you need to read the uploaded file contents immediately in the action method associated with the form submit. In your specific case, that would look like:

private UploadedFile uploadedFile;
private byte[] fileContents;

public void preview() {
    fileContents = uploadedFile.getContents();
}

// ...

To solve the second problem, your best bet is to use the data URI scheme. This makes it possible to render the image directly in the very same response and therefore you can safely use a @ViewScoped bean without facing "context not active" issues or saving the byte[] in session or disk in order to enable serving the image in a different request. Browser support on data URI scheme is currently pretty good. Replace the entire <p:graphicImage> with below:

<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);
}

Note: I assume that Java 8 is available to you as java.util.Base64 was only introduced in that version. In case you're using an older Java version, use DatatypeConverter.printBase64Binary(imageContents) instead.

In case you happen to use JSF utility library OmniFaces, you can also just use its <o:graphicImage> component instead which is on contrary to <p:graphicImage> capable of directly referencing a byte[] and InputStream bean property and rendering a data URI.

<o:graphicImage value="#{bean.imageContents}" dataURI="true" rendered="#{not empty bean.imageContents}">


来源:https://stackoverflow.com/questions/38817131/display-pfileupload-image-in-pgraphicimage-preview-without-saving-it

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!