Содержание:
0. Что важно знать o StreamedContent
1. Скачивание файлов через REST
2. Проверка расширения файла
3. Сохранение в базу и скачивание из базы
4. Отображение картинки в jsf
5. Добавление кнопки для скачивания файла
6. Добавление кнопки для загрузки данных
Это вторая часть статьи про работу со StreamedCintent в java. В первой части были рассмотрены детали, касающиеся бэкенда, а в этой части будет разобрана фронтовая часть статьи (4-6 части содержания)
Для того, чтобы прочитать первую часть статьи, относящуюся к бэкенду можно перейти на первую часть этой статьи: https://www.tune-it.ru/web/marina/blog/-/blogs/rabota-so-streameddata-na-backend
4. Отображение картинки в JSF
Отображать изображения можно при помощи тега p:graphicImage в primefaces. В него достаточно передать сам стрим.
<p:graphicImage value="#{userBean.userPhoto}"
rendered="#{userBean.userPhotoContentLength gt 0}"
cache="false"
stream="false"
/>
Разберемся с представленными атрибутами:
value - это метод для получения файла
rendered - правило для отображения контента. В нашем случае -- отображать картинку, если StreamedContent не пустой.
cache - управляет режимом кэширования ресурса браузером. По умолчанию true
stream - аттрибут, который может ввести в ступор, потому что мы передаем StreamedContent, который является стримом. Но на самом деле этот атрибут определяет, передается ли изображение в потоковом режиме или визуализируется напрямую как данные uri/base64 с поддержкой ViewScoped.
Остальные атрибуты можно посмотреть тут:
https://primefaces.github.io/primefaces/11_0_0/#/components/graphicimage?id=graphicimage
Сам бин при этом будет выглядеть так:
@Component
@Scope("view")
public class UserBean implements Serializable {
// Сервис для получение фотографии
@Autowired
privat AvatarService avatarService
// Массив данных изображения
private byte[] userPhotoBytes;
// Размер изображения
private int userPhotoContentLength;
// Пост-конструктор, в котором мы выгружаем изображение
@PostConstruct
private void init() {
Long userId = getRequestParam(); // Опустим получение id пользователя, допустим, оно получается из параметра урла
setPhoto(userId); // загрузим фото
}
// Выгрузка фото и сохранения его в массив байтов
public void setPhoto(Long userId) {
StreamedContent userPhoto = avatarService.getUserPhoto(userId);
userPhotoBytes = userPhoto.getStream().readAllBytes();
userPhotoContentLength = userPhoto.getContentLength();
}
// Getter для получения фото пользователя. Создается новый StreamedContent
public StreamedContent getUserPhoto() {
return DefaultStreamedContent.builder()
.stream(() -> new ByteArrayInputStream(userPhotoBytes))
.contentLength(userPhotoContentLength)
.contentType(userPhotoContentType)
.build();
}
// Getter для получения размера изображения
Public int getUserPhotoContentLength() {
return userPhotoContentLength;
}
}
5. Кнопка загрузки файла в JSF
Для того, чтобы загрузить файл можно воспользоваться p:fileUpload. Это файлаплоадер для загрузки файла через интерфейс.
Сам компонент будет выглядеть вот так:
<p:fileUpload listener="#{fileUploadBean.upload}"
label="Выбрать файл"
update="@this"
process="@this"
allowTypes="/(\.|\/)(pdf|gif|jpe?g|png)$/"
fileLimit="1"
sizeLimit=10000
required="true"
requiredMessage="Файл не был загружен"
invalidFileMessage="Неверный тип файла"
invalidSizeMessage="Файл слишком большой."
fileLimitMessage="Вы не можете загрузить более одного файла"/>
Давайте пройдемся по его атрибутам:
listener - метод обработки для загрузки файла. Должен возвращать StreamedContent с файлом.
label - лэйбл для файлаплоадера.
update, process - какие компоненты надо апдейтить и процессить соответственно
allowTypes - паттерн для допустимых разрешений файлов. В примере - это pdf, gif, gpeg, jpg и png.
fileLimit - максимальное количество файлов
sizeLimit - максимальный размер файла в байтах
required - является ли загрузка файла обязательной
requiredMessage - сообщение об ошибке, в случае, если файл не загружен
invalidFileMessage - сообщение о неверном типе данных
invalidSizeMessage - сообщение о неверном размере файла
fileLimitMessage - сообщение о добавлении неверного количества файлов
Остальные атрибуты можно посмотреть тут:
https://primefaces.github.io/primefaces/11_0_0/#/components/fileupload?id=fileupload
FileUpload должен вызвать listener для загрузки файла. Этот метод принимает FileUploadEvent, который хранит сам файл.
Напишем пример сохранения полученного файла:
@Autowired
private FileRepository fileRepository;
public void upload(FileUploadEvent event) {
UploadedFile uploadedFile = event.getFile();
if (uploadedFile == null) {
log.info(“Файл не был загружен”);
return;
}
fileRepository = fileRepository.save(uploadedFile);
}
6. Кнопка скачивания файла JSF
Для того, чтобы создать кнопку скачивания файлов, необходимо создать саму кнопку. В примере ниже - это commandButton. И добавить туда fileDownload, в который необходимо передать файл для загрузки.
Пример:
<p:commandButton value="Скачать файл" ajax="false">
<p:fileDownload value="#{fileDownloadBean.download}"/>
</p:commandButton>
Метод, который возвращает файл в бине выглядит так:
public StreamedContent download() {
return DefaultStreamedContent.builder()
.stream(() -> new ByteArrayInputStream(file.getContent()))
.contentLength((int) file.contentLength())
.contentType(StringUtil.safeToString(file.contentType()))
.build();
}
Завершение:
Это все, что касается StreamedContent, что я хотела рассказать в рамках данных статей.
Здесь был разобран поверхностный обзор того, как работать с этим типом данных на стороне backend и frontend
См. также:
Первая часть статьи [backend часть]:
https://www.tune-it.ru/web/marina/blog/-/blogs/rabota-so-streameddata-na-backend
Документация к компонентам:
p:graphicImage:
https://primefaces.github.io/primefaces/11_0_0/#/components/graphicimage?id=graphicimage
p:fileUpload:
https://primefaces.github.io/primefaces/11_0_0/#/components/fileupload?id=fileupload
p:fileDownload:
https://primefaces.github.io/primefaces/11_0_0/#/components/filedownload?id=filedownload