Научите вас шаг за шагом, как легко интегрировать Minio со SpringBoot для загрузки и скачивания файлов.
Научите вас шаг за шагом, как легко интегрировать Minio со SpringBoot для загрузки и скачивания файлов.

Ранее мы рассказали, что такое распределенная система хранения.,Представляем, что такое MinIO,наконец Как использовать MinIO для построения распределенной файловой системы. Итак, как использовать MinIO в реальных проектах? Далее я шаг за шагом научу вас, как легко интегрировать MinIO в SpringBoot.

1. SpringBoot интегрирует MinIO.

Давайте начнем легко интегрировать MinIO в SpringBoot. Сначала создайте проект Spring Boot и добавьте зависимости MinIO.

1.1 Добавьте зависимость MinIO
Язык кода:javascript
копировать
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.20</version>
</dependency>

<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>8.2.2</version>
</dependency>

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.11</version>
</dependency>
1.2 Настройка MinIO

Измените файл application.yml и добавьте адрес службы MinIO, пароль учетной записи и другие соответствующие конфигурации следующим образом:

Язык кода:javascript
копировать
minio:
  endpoint: http://192.168.78.101:9001
  accessKey: admin
  secretKey: 12345678
  bucketName: weiz-test

В приведенном выше примере BucketName относится к ранее созданному сегменту MinIO Bucket.

1.3 Класс конфигурации

Создайте класс конфигурации MinioConfig, соответствующий конфигурации MinIO, и внедрите его в клиент MinIO. Конкретный код выглядит следующим образом:

Язык кода:javascript
копировать
/**
  * @author weiz
  */
@Data
@Configuration
public class MinioConfig {

    /**
     * Адрес доступа
     */
    @Value("${minio.endpoint}")
    private String endpoint;

    /**
     * accessKey аналогичен идентификатору пользователя и используется для уникальной идентификации вашей учетной записи.
     */
    @Value("${minio.accessKey}")
    private String accessKey;

    /**
     * secretKey — пароль для вашей учетной записи
     */
    @Value("${minio.secretKey}")
    private String secretKey;

    /**
     * Ствол хранилища по умолчанию
     */
    @Value("${minio.bucketName}")
    private String bucketName;

    @Bean
    public MinioClient minioClient() {
        MinioClient minioClient = MinioClient.builder()
                .endpoint(endpoint)
                .credentials(accessKey, secretKey)
                .build();
        return minioClient;
    }
}
1.4 Создание класса операции MinIO

MinioUtils, общий класс инструментов, инкапсулирующий операции, связанные с MinIO, отвечает за создание Bucket, загрузку и выгрузку данных в службу MinIO. Конкретный код выглядит следующим образом:

Язык кода:javascript
копировать
/**
 * Инструменты MinIO
 *
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class MinioUtils {

    private final MinioClient minioClient;

    /******************************  Operate Bucket Start  ******************************/

    /**
     * Инициализируйте Bucket при запуске контейнера SpringBoot.
     * Если Бакета нет, создайте его
     *
     * @param bucketName
     */
    @SneakyThrows(Exception.class)
    private void createBucket(String bucketName) {
        if (!bucketExists(bucketName)) {
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        }
    }

    /**
     * Определить, существует ли сегмент, true: существует, false: не существует.
     *
     * @param bucketName
     * @return
     */
    @SneakyThrows(Exception.class)
    public boolean bucketExists(String bucketName) {
        return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
    }

    /**
     * Стратегия приобретения корзины
     *
     * @param bucketName
     * @return
     */
    @SneakyThrows(Exception.class)
    public String getBucketPolicy(String bucketName) {
        return minioClient.getBucketPolicy(GetBucketPolicyArgs
                .builder()
                .bucket(bucketName)
                .build());
    }

    /**
     * Получить список всех бакетов
     *
     * @return
     */
    @SneakyThrows(Exception.class)
    public List<Bucket> getAllBuckets() {
        return minioClient.listBuckets();
    }

    /**
     * Получить соответствующую информацию на основе BucketName
     *
     * @param bucketName
     * @return
     */
    @SneakyThrows(Exception.class)
    public Optional<Bucket> getBucket(String bucketName) {
        return getAllBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();
    }

    /**
     * Удалить сегмент на основе BucketName, true: удаление выполнено успешно; false: удаление не удалось, возможно, файл больше не существует.
     *
     * @param bucketName
     * @throws Exception
     */
    @SneakyThrows(Exception.class)
    public void removeBucket(String bucketName) {
        minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
    }

    /******************************  Operate Bucket End  ******************************/


    /******************************  Operate Files Start  ******************************/

    /**
     * Определить, существует ли файл
     *
     * @param bucketName
     * @param objectName
     * @return
     */
    public boolean isObjectExist(String bucketName, String objectName) {
        boolean exist = true;
        try {
            minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
        } catch (Exception e) {
            log.error("[MinioИнструменты]>>>> Определить, существует ли файл, аномальный:", e);
            exist = false;
        }
        return exist;
    }

    /**
     * Определить, существует ли папка
     *
     * @param bucketName
     * @param objectName
     * @return
     */
    public boolean isFolderExist(String bucketName, String objectName) {
        boolean exist = false;
        try {
            Iterable<Result<Item>> results = minioClient.listObjects(
                    ListObjectsArgs.builder().bucket(bucketName).prefix(objectName).recursive(false).build());
            for (Result<Item> result : results) {
                Item item = result.get();
                if (item.isDir() && objectName.equals(item.objectName())) {
                    exist = true;
                }
            }
        } catch (Exception e) {
            log.error("[MinioИнструменты]>>>> Определить, существует ли папка,аномальный:", e);
            exist = false;
        }
        return exist;
    }

    /**
     * Запрос файлов на основе префикса файла
     *
     * @param bucketName хранилищеведро     * @param prefix     префикс
     * @param recursive  Использовать ли рекурсивный запрос
     * @return MinioItem список
     */
    @SneakyThrows(Exception.class)
    public List<Item> getAllObjectsByPrefix(String bucketName,
                                            String prefix,
                                            boolean recursive) {
        List<Item> list = new ArrayList<>();
        Iterable<Result<Item>> objectsIterator = minioClient.listObjects(
                ListObjectsArgs.builder().bucket(bucketName).prefix(prefix).recursive(recursive).build());
        if (objectsIterator != null) {
            for (Result<Item> o : objectsIterator) {
                Item item = o.get();
                list.add(item);
            }
        }
        return list;
    }

    /**
     * Получить файловый поток
     *
     * @param bucketName хранилищеведро     * @param objectName имя файла
     * @return двоичный поток
     */
    @SneakyThrows(Exception.class)
    public InputStream getObject(String bucketName, String objectName) {
        return minioClient.getObject(
                GetObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .build());
    }

    /**
     * Загрузка точки останова
     *
     * @param bucketName хранилищеведро     * @param objectName имя файласказать
     * @param offset     начальная позиция байта
     * @param length     длина для чтения
     * @return двоичный поток
     */
    @SneakyThrows(Exception.class)
    public InputStream getObject(String bucketName, String objectName, long offset, long length) {
        return minioClient.getObject(
                GetObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .offset(offset)
                        .length(length)
                        .build());
    }

    /**
     * Получите список файлов по пути
     *
     * @param bucketName хранилищеведро     * @param prefix     имя файласказать
     * @param recursive  Следует ли выполнять поиск рекурсивно, false: имитировать поиск по структуре папок.
     * @return двоичный поток
     */
    public Iterable<Result<Item>> listObjects(String bucketName, String prefix, boolean recursive) {
        return minioClient.listObjects(
                ListObjectsArgs.builder()
                        .bucket(bucketName)
                        .prefix(prefix)
                        .recursive(recursive)
                        .build());
    }

    /**
     * Использование MultipartFile для загрузки файла
     *
     * @param bucketName  хранилищеведро     * @param file        имя файла
     * @param objectName  имя объекта
     * @param contentType тип
     * @return
     */
    @SneakyThrows(Exception.class)
    public ObjectWriteResponse uploadFile(String bucketName, MultipartFile file, String objectName, String contentType) {
        InputStream inputStream = file.getInputStream();
        return minioClient.putObject(
                PutObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .contentType(contentType)
                        .stream(inputStream, inputStream.available(), -1)
                        .build());
    }

    /**
     * Загрузка изображения
     * @param bucketName
     * @param imageBase64
     * @param imageName
     * @return
     */
    public ObjectWriteResponse uploadImage(String bucketName, String imageBase64, String imageName) {
        if (!StringUtils.isEmpty(imageBase64)) {
            InputStream in = base64ToInputStream(imageBase64);
            String newName = System.currentTimeMillis() + "_" + imageName + ".jpg";
            String year = String.valueOf(new Date().getYear());
            String month = String.valueOf(new Date().getMonth());
            return uploadFile(bucketName, year + "/" + month + "/" + newName, in);

        }
        return null;
    }

    public static InputStream base64ToInputStream(String base64) {
        ByteArrayInputStream stream = null;
        try {
            byte[] bytes = new BASE64Decoder().decodeBuffer(base64.trim());
            stream = new ByteArrayInputStream(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return stream;
    }


    /**
     * Загрузить локальные файлы
     *
     * @param bucketName хранилищеведро     * @param objectName имя объектасказать
     * @param fileName   локальный путь к файлу
     * @return
     */
    @SneakyThrows(Exception.class)
    public ObjectWriteResponse uploadFile(String bucketName, String objectName, String fileName) {
        return minioClient.uploadObject(
                UploadObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .filename(fileName)
                        .build());
    }

    /**
     * Загружать файлы через поток
     *
     * @param bucketName  хранилищеведро     * @param objectName  файловый объект
     * @param inputStream файловый поток
     * @return
     */
    @SneakyThrows(Exception.class)
    public ObjectWriteResponse uploadFile(String bucketName, String objectName, InputStream inputStream) {
        return minioClient.putObject(
                PutObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .stream(inputStream, inputStream.available(), -1)
                        .build());
    }

    /**
     * Создать папку или каталог
     *
     * @param bucketName хранилищеведро     * @param objectName путь к каталогу
     * @return
     */
    @SneakyThrows(Exception.class)
    public ObjectWriteResponse createDir(String bucketName, String objectName) {
        return minioClient.putObject(
                PutObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .stream(new ByteArrayInputStream(new byte[]{}), 0, -1)
                        .build());
    }

    /**
     * Получить информацию о файле, Если выдается исключение, файл не существует
     *
     * @param bucketName хранилищеведро     * @param objectName имя файласказать
     * @return
     */
    @SneakyThrows(Exception.class)
    public String getFileStatusInfo(String bucketName, String objectName) {
        return minioClient.statObject(
                StatObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .build()).toString();
    }

    /**
     * Копировать файлы
     *
     * @param bucketName    хранилищеведро     * @param objectName    имя файла
     * @param srcBucketName Целевой ствол хранилища
     * @param srcObjectName Цельимя файла
     */
    @SneakyThrows(Exception.class)
    public ObjectWriteResponse copyFile(String bucketName, String objectName, String srcBucketName, String srcObjectName) {
        return minioClient.copyObject(
                CopyObjectArgs.builder()
                        .source(CopySource.builder().bucket(bucketName).object(objectName).build())
                        .bucket(srcBucketName)
                        .object(srcObjectName)
                        .build());
    }

    /**
     * Удалить файлы
     *
     * @param bucketName хранилищеведро     * @param objectName имя файласказать
     */
    @SneakyThrows(Exception.class)
    public void removeFile(String bucketName, String objectName) {
        minioClient.removeObject(
                RemoveObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .build());
    }

    /**
     * партия Удалить файлы
     *
     * @param bucketName хранилищеведро     * @param keys       Необходимые файлы для удаления списка
     * @return
     */
    public void removeFiles(String bucketName, List<String> keys) {
        List<DeleteObject> objects = new LinkedList<>();
        keys.forEach(s -> {
            objects.add(new DeleteObject(s));
            try {
                removeFile(bucketName, s);
            } catch (Exception e) {
                log.error("[MinioИнструменты]>>>> партия Удалить файлы,аномальный:", e);
            }
        });
    }

    /**
     * Получить внешнюю ссылку на файл
     *
     * @param bucketName хранилищеведро     * @param objectName имя файла
     * @param expires    Срок годности <=7 Второй (Срок действия внешней ссылки (единица измерения: Второй))
     * @return url
     */
    @SneakyThrows(Exception.class)
    public String getPresignedObjectUrl(String bucketName, String objectName, Integer expires) {
        GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder().expiry(expires).bucket(bucketName).object(objectName).build();
        return minioClient.getPresignedObjectUrl(args);
    }

    /**
     * Получить внешнюю ссылку на файл
     *
     * @param bucketName
     * @param objectName
     * @return url
     */
    @SneakyThrows(Exception.class)
    public String getPresignedObjectUrl(String bucketName, String objectName) {
        GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .method(Method.GET).build();
        return minioClient.getPresignedObjectUrl(args);
    }

    /**
     * Преобразование кодировки URLDecoder в UTF8
     *
     * @param str
     * @return
     * @throws UnsupportedEncodingException
     */
    public String getUtf8ByURLDecoder(String str) throws UnsupportedEncodingException {
        String url = str.replaceAll("%(?![0-9a-fA-F]{2})", "%25");
        return URLDecoder.decode(url, "UTF-8");
    }
}
1.5 Создать контроллер

Создайте тестовый контроллер OSSController. Пример кода выглядит следующим образом:

Язык кода:javascript
копировать
@Slf4j
@RestController
@RequestMapping("/oss")
public class OSSController {

    @Autowired
    private MinioUtils minioUtils;
    
    @Autowired
    private MinioConfig minioConfig;
    
    /**
     * Загрузка файла
     *
     * @param file
     */
    @PostMapping("/upload")
    public String upload(@RequestParam("file") MultipartFile file) {
        try {
            //имя файла
            String fileName = file.getOriginalFilename();
            String newFileName = System.currentTimeMillis() + "." + StringUtils.substringAfterLast(fileName, ".");
            //тип
            String contentType = file.getContentType();
            minioUtils.uploadFile(minioConfig.getBucketName(), file, newFileName, contentType);
            return «Загрузка прошла успешно»;
        } catch (Exception e) {
            log.error("Загрузка не удалась");
            return «Загрузка не удалась»;
        }
    }

    /**
     * удалить
     *
     * @param fileName
     */
    @DeleteMapping("/")
    public void delete(@RequestParam("fileName") String fileName) {
        minioUtils.removeFile(minioConfig.getBucketName(), fileName);
    }

    /**
     * Получить информацию о файле
     *
     * @param fileName
     * @return
     */
    @GetMapping("/info")
    public String getFileStatusInfo(@RequestParam("fileName") String fileName) {
        return minioUtils.getFileStatusInfo(minioConfig.getBucketName(), fileName);
    }

    /**
     * Получить внешнюю ссылку на файл
     *
     * @param fileName
     * @return
     */
    @GetMapping("/url")
    public String getPresignedObjectUrl(@RequestParam("fileName") String fileName) {
        return minioUtils.getPresignedObjectUrl(minioConfig.getBucketName(), fileName);
    }

    /**
     * Загрузка файла
     *
     * @param fileName
     * @param response
     */
    @GetMapping("/download")
    public void download(@RequestParam("fileName") String fileName, HttpServletResponse response) {
        try {
            InputStream fileInputStream = minioUtils.getObject(minioConfig.getBucketName(), fileName);
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
            response.setContentType("application/force-download");
            response.setCharacterEncoding("UTF-8");
            IOUtils.copy(fileInputStream, response.getOutputStream());
        } catch (Exception e) {
            log.error("Загрузка не удалась");
        }
    }

}

2. Тестовая проверка

Выше мы интегрировали MinIO в проект Spring Boot. Далее мы используем Postman, чтобы проверить, нормально ли загрузка и скачивание файлов.

1) Загрузка файла

Используйте Postman для вызова интерфейса http://localhost:8080/oss/upload и выберите файл для проверки функции загрузки, как показано на следующем рисунке:

2) Загрузка файла

В браузере вызовите

http://localhost:8080/oss/download?fileName=1665744927595.jpg интерфейс проверьте интерфейс загрузки файлов, как показано на следующем рисунке:

Конечно, вы также можете напрямую получить доступ к адресу minio: http://192.168.78.101:9000/weiz-test/1665744927595.jpg. Убедитесь, что файл успешно загружен.

наконец

Выше мы рассказали, как интегрировать MinIO в проект Spring Boot. MinIO — очень популярная распределенная объектная система хранения данных (OSS), и вам как программисту все равно необходимо с ней быть знакомым.

boy illustration
Учебное пособие по Jetpack Compose для начинающих, базовые элементы управления и макет
boy illustration
Код js веб-страницы, фон частицы, код спецэффектов
boy illustration
【новый! Суперподробное】Полное руководство по свойствам компонентов Figma.
boy illustration
🎉Обязательно к прочтению новичкам: полное руководство по написанию мини-программ WeChat с использованием программного обеспечения Cursor.
boy illustration
[Забавный проект Docker] VoceChat — еще одно приложение для мгновенного чата (IM)! Может быть встроен в любую веб-страницу!
boy illustration
Как реализовать переход по странице в HTML (html переходит на указанную страницу)
boy illustration
Как решить проблему зависания и низкой скорости при установке зависимостей с помощью npm. Существуют ли доступные источники npm, которые могут решить эту проблему?
boy illustration
Серия From Zero to Fun: Uni-App WeChat Payment Practice WeChat авторизует вход в систему и украшает страницу заказа, создает интерфейс заказа и инициирует запрос заказа
boy illustration
Серия uni-app: uni.navigateЧтобы передать скачок значения
boy illustration
Апплет WeChat настраивает верхнюю панель навигации и адаптируется к различным моделям.
boy illustration
JS-время конвертации
boy illustration
Обеспечьте бесперебойную работу ChromeDriver 125: советы по решению проблемы chromedriver.exe не найдены
boy illustration
Поле комментария, щелчок мышью, специальные эффекты, js-код
boy illustration
Объект массива перемещения объекта JS
boy illustration
Как открыть разрешение на позиционирование апплета WeChat_Как использовать WeChat для определения местонахождения друзей
boy illustration
Я даю вам два набора из 18 простых в использовании фонов холста Power BI, так что вам больше не придется возиться с цветами!
boy illustration
Получить текущее время в js_Как динамически отображать дату и время в js
boy illustration
Вам необходимо изучить сочетания клавиш vsCode для форматирования и организации кода, чтобы вам больше не приходилось настраивать формат вручную.
boy illustration
У ChatGPT большое обновление. Всего за 45 минут пресс-конференция показывает, что OpenAI сделал еще один шаг вперед.
boy illustration
Copilot облачной разработки — упрощение разработки
boy illustration
Микросборка xChatGPT с низким кодом, создание апплета чат-бота с искусственным интеллектом за пять шагов
boy illustration
CUDA Out of Memory: идеальное решение проблемы нехватки памяти CUDA
boy illustration
Анализ кластеризации отдельных ячеек, который должен освоить каждый&MarkerгенетическийВизуализация
boy illustration
vLLM: мощный инструмент для ускорения вывода ИИ
boy illustration
CodeGeeX: мощный инструмент генерации кода искусственного интеллекта, который можно использовать бесплатно в дополнение к второму пилоту.
boy illustration
Машинное обучение Реальный бой LightGBM + настройка параметров случайного поиска: точность 96,67%
boy illustration
Бесшовная интеграция, мгновенный интеллект [1]: платформа больших моделей Dify-LLM, интеграция без кодирования и встраивание в сторонние системы, более 42 тысяч звезд, чтобы стать свидетелями эксклюзивных интеллектуальных решений.
boy illustration
LM Studio для создания локальных больших моделей
boy illustration
Как определить количество слоев и нейронов скрытых слоев нейронной сети?
boy illustration
[Отслеживание целей] Подробное объяснение ByteTrack и детали кода