Отображение P:fileupload с изображения в P:графического изображения предварительного просмотра без сохранения


Я использую 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 6

1 ответ:

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

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

private UploadedFile uploadedFile;
private byte[] fileContents;

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

// ...

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