Отображение p:fileupload изображения в p: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>

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

Нет ошибки в компоненте поддержки, и изображение не будет загружаться и отображаться на внешнем интерфейсе. Клиент упоминает, что изображение вернуло ошибку 404 not found.

1 ответ

Решение

Ваша проблема двоякая. Не удалось, потому что содержимое загруженного файла является областью запроса и потому что изображение запрашивается в другом HTTP-запросе. Чтобы лучше понять внутреннюю работу, внимательно прочитайте ответы на следующие тесно связанные вопросы и ответы:

Чтобы решить первую проблему, вам необходимо немедленно прочитать содержимое загруженного файла в методе действия, связанном с отправкой формы. В вашем конкретном случае это будет выглядеть так:

private UploadedFile uploadedFile;
private byte[] fileContents;

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

// ...

Чтобы решить вторую проблему, лучше всего использовать схему URI данных. Это позволяет визуализировать изображение непосредственно в том же ответе, и поэтому вы можете безопасно использовать @ViewScoped bean, не сталкиваясь с проблемами "context not active" или сохраняя byte[] в сеансе или на диске, чтобы включить обслуживание изображения в другом запросе. Поддержка браузера по схеме URI данных в настоящее время довольно хорошая. Заменить весь <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}">
Другие вопросы по тегам