Отображение 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-запросе. Чтобы лучше понять внутреннюю работу, внимательно прочитайте ответы на следующие тесно связанные вопросы и ответы:
- Отображение динамического изображения из базы данных с помощью p:graphicImage и StreamedContent
- Как правильно выбрать сферу применения бобов?
Чтобы решить первую проблему, вам необходимо немедленно прочитать содержимое загруженного файла в методе действия, связанном с отправкой формы. В вашем конкретном случае это будет выглядеть так:
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}">