Использование хранилища файлов
Хранилище файлов – это абстракция, обеспечивающая различные реализации того, как и где хранятся файлы, и предоставляющая единый интерфейс для доступа к файлам и создания ссылок на них из сущностей модели данных.
Jmix поставляется с двумя реализациями хранения файлов: локальной и AWS. При создании нового проекта в Studio в него включена локальная реализация.
В файловом хранилище можно хранить файлы любого размера, поскольку передача файлов в хранилище и из него выполняется путем копирования небольших фрагментов данных между входными и выходными потоками, поэтому файлы никогда не загружаются в память полностью. |
Примеры
Работа с файлами в UI
В этом разделе приводится пример работы с файлами в файловом хранилище с использованием компонентов UI.
Во-первых, создайте в сущности атрибут типа FileRef
, например:
@JmixEntity
@Entity
@Table(name = "ATTACHMENT")
public class Attachment {
// ...
@Column(name = "FILE_")
private FileRef file;
public FileRef getFile() {
return file;
}
public void setFile(FileRef file) {
this.file = file;
}
При запуске приложения Studio генерирует скрипт миграции базы данных для создания соответствующего столбца строкового типа, поскольку FileRef
имеет строковое представление в формате URI.
Для загрузки файлов с экрана UI используйте компонент fileStorageUploadField, привязанный к атрибуту сущности:
<iframe/>
<formLayout id="form" dataContainer="attachmentDc">
<fileStorageUploadField id="fileField" property="file"/>
Чтобы скачать прикрепленные файлы, добавьте в таблицу в экране списка колонку с компонентом:
@ViewComponent
private DataGrid<Attachment> attachmentsDataGrid;
@Autowired
private UiComponents uiComponents;
@Autowired
private Downloader downloader; (1)
@Subscribe
public void onInit(final InitEvent event) {
attachmentsDataGrid.addComponentColumn(attachment -> {
Button button = uiComponents.create(Button.class);
button.setText("Download");
button.addThemeName("tertiary-inline");
button.addClickListener(clickEvent -> {
downloader.download(attachment.getFile()); (2)
});
return button;
});
}
1 | Используйте бин Downloader для скачивания файлов. |
2 | Метод download() принимает значение FileRef и извлекает файл из хранилища файлов, указанного в объекте FileRef . Имя и тип файла также закодированы в FileRef , поэтому веб-браузер правильно выбирает, загружать или отображать файл. |
Использование интерфейса FileStorage
В следующем примере показано, как работать напрямую с интерфейсом FileStorage.
Первый метод сохраняет в файловом хранилище полученный из веб-службы файл. Второй метод загружает файл из хранилища и сохраняет его в локальной файловой системе.
Используется та же сущность Attachment
, что и в предыдущем примере.
@Autowired
private FileStorageLocator fileStorageLocator; (1)
@Autowired
private DataManager dataManager;
private void getAndSaveImage() {
try {
(2)
URLConnection connection = new URL("https://picsum.photos/300").openConnection();
try (InputStream responseStream = connection.getInputStream()) {
(3)
FileStorage fileStorage = fileStorageLocator.getDefault();
FileRef fileRef = fileStorage.saveStream("photo.jpg", responseStream);
(4)
Attachment attachment = dataManager.create(Attachment.class);
attachment.setFile(fileRef);
dataManager.save(attachment);
}
} catch (IOException e) {
throw new RuntimeException("Error getting image", e);
}
}
private void saveToLocalFile(Attachment attachment, Path path) {
FileStorage fileStorage = fileStorageLocator.getDefault();
FileRef fileRef = attachment.getFile();
(5)
InputStream inputStream = fileStorage.openStream(fileRef);
try {
(6)
Files.copy(inputStream, path.resolve(fileRef.getFileName()),
StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
throw new RuntimeException("Error saving image", e);
}
}
1 | FileStorageLocator позволяет работать с определенным хранилищем файлов, если вы определили в проекте несколько хранилищ. Если у вас одно хранилище файлов (что является ситуацией по умолчанию), интерфейс FileStorage можно внедрить напрямую. |
2 | Получение входного потока для веб-ресурса. Вместо класса URLConnection можно использовать HttpClient , или стороннюю библиотеку, такую как Apache HttpClient. |
3 | Сохранение содержимого ресурса в хранилище файлов. Возвращаемый объект FileRef является ссылкой на файл в хранилище. |
4 | Сохранение ссылки на атрибут сущности. |
5 | Получение входного потока для загрузки файла из хранилища файлов. |
6 | Сохранение файла в локальной файловой системе. |
Локальное хранилище файлов
Реализация локального хранилища позволяет хранить файлы в локальной файловой системе сервера приложения или в любом сетевом хранилище (NAS).
Чтобы использовать локальное хранилище файлов в своем приложении, убедитесь, что файл build.gradle
содержит следующую строку в разделе dependencies
:
implementation 'io.jmix.localfs:jmix-localfs-starter'
Файлы хранятся в специальной структуре каталогов, которая поддерживается файловым хранилищем. По умолчанию корневым каталогом является ${user.dir}/.jmix/work/filestorage
, где ${user.dir}
является рабочим каталогом пользователя (где была запущена JVM). Его можно изменить, указав рабочий каталог в свойстве приложения jmix.core.work-dir, или нужный путь целиком в свойстве jmix.localfs.storage-dir
, например:
jmix.localfs.storage-dir = /opt/file-storage
Хранилище файлов AWS
Реализация хранилища файлов AWS позволяет хранить файлы в Amazon S3.
Чтобы использовать в приложении хранилище файлов AWS, установите дополнение AWS File Storage из каталога, как описано в разделе Дополнения, или вручную добавьте следующую строку в раздел dependencies
файла build.gradle
:
implementation 'io.jmix.awsfs:jmix-awsfs-starter'
Если вы планируете использовать только хранилище файлов AWS, удалите зависимость локального хранилища файлов из build.gradle
(строку, содержащую io.jmix.localfs:jmix-localfs-starter
). В противном случае см. следующий раздел о том, как настроить несколько хранилищ файлов.
Определите свойства приложения:
jmix.awsfs.access-key = <access key ID>
jmix.awsfs.secret-access-key = <secret access key>
jmix.awsfs.region = <AWS region, for example eu-north-1>
jmix.awsfs.bucket = <S3 bucket name>
jmix.awsfs.chunk-size = <optional upload chunk size in KB, default is 8192>
jmix.awsfs.endpoint-url = <optional endpoint URL for S3-compatible cloud storages>
The S3 bucket in the selected region must be created beforehand.
Использование нескольких хранилищ
Если вы хотите использовать в приложении несколько хранилищ файлов, укажите имя хранилища по умолчанию в свойстве приложения:
jmix.core.default-file-storage = fs
Имя локального хранилища файлов – fs
; имя хранилища файлов AWS – s3
.
Чтобы использовать несколько хранилищ одного типа, определите дополнительные хранилища с уникальными именами. Например, чтобы определить дополнительное локальное хранилище файлов с корневым каталогом в /var/tmp/myfs
, добавьте следующий код в основной класс приложения:
@Bean
FileStorage myFileStorage() {
return new LocalFileStorage("myfs", "/var/tmp/myfs");
}
Для программной работы с различными хранилищами используйте бин FileStorageLocator
. Он позволяет получить файловое хранилище по его имени.
Компонент fileStorageUploadField имеет атрибут fileStorage
для указания имени хранилища файлов. Если он не установлен, компонент использует файловое хранилище по умолчанию.