在p:graphicImage预览中显示p:fileupload图像而不保存它

Lan*_*Zai 7 jsf file-upload preview primefaces graphicimage

我正在使用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>
Run Code Online (Sandbox Code Playgroud)

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"); 
    }
}
Run Code Online (Sandbox Code Playgroud)

在辅助bean上没有发生错误,图像将不会加载并显示在前端.客户端提到图像返回404未找到错误.

Bal*_*usC 11

你的问题是双重的.它失败了,因为上传的文件内容是请求范围的,并且因为在不同的HTTP请求中请求了图像.为了更好地理解内部工作,请仔细阅读以下密切相关的问答答案:

要解决第一个问题,您需要立即在与表单提交相关联的操作方法中读取上载的文件内容.在您的具体情况下,这将是:

private UploadedFile uploadedFile;
private byte[] fileContents;

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

// ...
Run Code Online (Sandbox Code Playgroud)

要解决第二个问题,最好的办法是使用数据URI方案.这使得可以直接在完全相同的响应中呈现图像,因此您可以安全地使用@ViewScopedbean而不会遇到"上下文不活动"问题或保存byte[]会话或磁盘以便能够在不同的请求中提供图像.数据URI方案的浏览器支持目前相当不错.<p:graphicImage>用以下替换整个:

<ui:fragment rendered="#{not empty bean.uploadedFile}">
    <img src="data:image/png;base64,#{bean.imageContentsAsBase64}" />
</ui:fragment>
Run Code Online (Sandbox Code Playgroud)

public String getImageContentsAsBase64() {
    return Base64.getEncoder().encodeToString(imageContents);
}
Run Code Online (Sandbox Code Playgroud)

注意:我假设您可以使用Java 8,因为java.util.Base64只在该版本中引入.如果您使用的是较旧的Java版本,请DatatypeConverter.printBase64Binary(imageContents)改用.

如果你碰巧使用JSF实用程序库OmniFaces,你也可以使用它的<o:graphicImage>组件,而不是<p:graphicImage>直接引用a byte[]InputStreambean属性并呈现数据URI.

<o:graphicImage value="#{bean.imageContents}" dataURI="true" rendered="#{not empty bean.imageContents}">
Run Code Online (Sandbox Code Playgroud)