1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/dromara-x-file-storage

 / Детали:

[Проблемная обратная связь]: Загрузка изображения для создания миниатюр не поддерживает формат WebP

Предстоит сделать
Владелец
Создано  
28.02.2025

Есть ли уже существующий вопрос?

Связанные зависимости и версии

X File Storage версия: v2.2.1
Spring Boot версия: bk.2.7.2
Solon версия:
JVM версия:
openjdk версия "1.8.0_412"
OpenJDK Runtime Environment (Zulu 8.78.0.19-CA-macos-aarch64) (build 1.8.0_412-b08)
OpenJDK 64-Bit Server VM (Zulu 8.78.0.19-CA-macos-aarch64) (build 25.412-b08, mixed mode)
Другие зависимости с названием и версией:

Конфигурационные файлы

# Введите конфигурационные файлы здесь
server:
  port: 8030

spring:
  profiles:
    active: xu-dev
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/x-file-storage-test?characterEncoding=UTF-8&useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: mysql@G2ZH
    driver-class-name: com.mysql.cj.jdbc.Driver

  servlet:
    multipart:
      resolve-lazily: true # ленивая загрузка многопоточных запросов
``````yaml
x-file-storage: # Настройка хранения файлов, если не используется, можно пропустить
default-platform: local-plus-1 # По умолчанию используемый платформенный идентификатор
thumbnail-suffix: ".min.jpg" # Расширение миниатюр, например ["min.jpg", "png"]
# local: # Локальное хранилище (не рекомендуется использовать)
# - platform: local-1 # Идентификатор платформенного хранилища
# enable-storage: true # Активировать хранение
# enable-access: true # Активировать доступ (в продакшн лучше использовать конфигурацию Nginx, более эффективно)
# domain: "" # Домен для доступа, например: "http://127.0.0.1:8030/test/file/", обратите внимание, что он должен совпадать с path-patterns, заканчивается слешом "/", локальному хранилищу рекомендуется использовать относительные пути, чтобы было удобнее менять домены в будущем
# base-path: /Users/gaogzhen/logs/x-file-storage/ # Базовый путь для хранения
# path-patterns: /test/file/** # Путь для доступа, если активирован enable-access, то через этот путь можно получить доступ к загруженным файлам
local-plus: # Улучшенное локальное хранилище
- platform: local-plus-1 # Идентификатор платформенного хранилища
enable-storage: true # Активировать хранение
enable-access: true # Активировать доступ (в продакшн лучше использовать конфигурацию Nginx, более эффективно)
domain: http://127.0.0.1:8030/file/ # Домен для доступа, пример: "http://127.0.0.1:8030/file/", обратите внимание, что он должен совпадать с path-patterns, заканчивается слешом "/", локальному хранилищу рекомендуется использовать относительные пути, чтобы было удобнее менять домены в будущем
base-path: local-plus/ # Базовый путь
path-patterns: /file/** # Путь для доступа
storage-path: /Users/gaogzhen/logs/x-file-storage/ # Путь для хранения
# huawei-obs: # Huawei Cloud OBS, если не используется, можно пропустить
# - platform: huawei-obs-1 # Идентификатор платформенного хранилища
# enable-storage: false # Активировать хранение
# access-key: ??
# secret-key: ??
# end-point: ??
# bucket-name: ??
# domain: ?? # Домен для доступа, обратите внимание, что он должен заканчиваться слешом "/", пример: http://abc.obs.com/
# base-path: hy/ # Базовый путь
# aliyun-oss: # Alibaba Cloud OSS, если не используется, можно пропустить
# - platform: aliyun-oss-1 # Идентификатор платформенного хранилища
# enable-storage: false # Активировать хранение
# access-key: ??
# secret-key: ??
# end-point: ??
# bucket-name: ??
# domain: ?? # Домен для доступа, обратите внимание, что он должен заканчиваться слешом "/", пример: https://abc.oss-cn-shanghai.aliyuncs.com/
# base-path: hy/ # Базовый путь
# qiniu-kodo: # Qiniu Cloud KODO, если не используется, можно пропустить
# - platform: qiniu-kodo-1 # Идентификатор платформенного хранилища
# enable-storage: false # Активировать хранение
# access-key: ??
# secret-key: ??
# bucket-name: ??
# domain: ?? # Домен для доступа, обратите внимание, что он должен заканчиваться слешом "/", пример: http://abc.hn-bkt.clouddn.com/
# base-path: base/ # Базовый путь
# tencent-cos: # Tencent Cloud COS
# - platform: tencent-cos-1 # Идентификатор платформенного хранилища
# enable-storage: true # Активировать хранение
# secret-id: ??
# secret-key: ??
# region: ?? # Регион расположения бакета
# bucket-name: ??
# domain: ?? # Домен для доступа, обратите внимание, что он должен заканчиваться слешом "/", пример: https://abc.cos.ap-nanjing.myqcloud.com/
# base-path: hy/ # Базовый путь
# baidu-bos: # Baidu Cloud BOS
# - platform: baidu-bos-1 # Идентификатор платформенного хранилища
# enable-storage: true # Активировать хранение
# access-key: ??
# secret-key: ??
# end-point: ?? # Пример abc.fsh.bcebos.com
# bucket-name: ??
# domain: ?? # Домен для доступа, обратите внимание, что он должен заканчиваться слешом "/", пример: https://abc.fsh.bcebos.com/abc/
# base-path: hy/ # Базовый путь
# upyun-uss: # UpYun Cloud USS
# - platform: upyun-uss-1 # Идентификатор платформенного хранилища
# enable-storage: true # Активировать хранение
# username: ??
# password: ??
# bucket-name: ??
# domain: ?? # Домен для доступа, обратите внимание, что он должен заканчиваться слешом "/", пример: http://abc.test.upcdn.net/
# base-path: hy/ # Базовый путь
# minio: # MinIO, поскольку MinIO SDK поддерживает Amazon S3, все другие хранилища, совместимые с протоколом Amazon S3, также могут быть настроены здесь
# - platform: minio-1 # Идентификатор платформенного хранилища
# enable-storage: true # Активировать хранение
# access-key: ??
# secret-key: ??
# end-point: ??
# bucket-name: ??
# domain: ?? # Домен для доступа, обратите внимание, что он должен заканчиваться слешом "/", пример: http://minio.abc.com/abc/
# base-path: hy/ # Базовый путь
# amazon-s3: # Amazon S3, все другие хранилища, совместимые с протоколом Amazon S3, также могут быть настроены здесь
# - platform: amazon-s3-1 # Идентификатор платформенного хранилища
# enable-storage: true # Активировать хранение
# access-key: ??
# secret-key: ??
# region: ?? # Следует заполнить хотя бы один из этих параметров
# end-point: ?? # Следует заполнить хотя бы один из этих параметров
# bucket-name: ??
# domain: ?? # Домен для доступа, обратите внимание, что он должен заканчиваться слешом "/", пример: https://abc.hn-bkt.clouddn.com/
# base-path: s3/ # Базовый путь
# ftp: # FTP
# - platform: ftp-1 # Идентификатор платформенного хранилища
# enable-storage: true # Активировать хранение
# host: ?? # Хост, пример: 192.168.1.105
# port: 21 # Порт, по умолчанию 21
# user: anonymous # Имя пользователя, по умолчанию anonymous (анонимный)
# password: "" # Пароль, по умолчанию пустой
# domain: ?? # Домен для доступа, обратите внимание, что он должен заканчиваться слешом "/", пример: ftp://192.168.1.105/
# base-path: ftp/ # Базовый путь
# storage-path: / # Путь для хранения, все загружаемые файлы будут сохранены в этом пути, по умолчанию "/", обратите внимание, что он должен заканчиваться слешом "/"
# sftp: # SFTP
# - platform: sftp-1 # Идентификатор платформенного хранилища
# enable-storage: true # Активировать хранение
# host: ?? # Хост, пример: 192.168.1.105
# port: 22 # Порт, по умолчанию 22
# user: root # Имя пользователя
# password: ?? # Пароль или пароль для приватного ключа
# private-key-path: ?? # Путь до приватного ключа, совместимый с Spring ClassPath, файловым путем, HTTP-путем и т.д., пример: classpath:id_rsa_2048
# domain: ?? # Домен для доступа, обратите внимание, что он должен заканчиваться слешом "/", пример: https://file.abc.com/
# base-path: sftp/ # Базовый путь
# storage-path: /www/wwwroot/file.abc.com/ # Путь для хранения, обратите внимание, что он должен заканчиваться слешом "/"
# webdav: # WebDAV
# - platform: webdav-1 # Идентификатор платформенного хранилища
# enable-storage: true # Активировать хранение
# server: ?? # Адрес сервера, пример: http://192.168.1.105:8405/
# user: ?? # Имя пользователя
# password: ?? # Пароль
# domain: ?? # Домен для доступа, обратите внимание, что он должен заканчиваться слешом "/", пример: https://file.abc.com/
# base-path: webdav/ # Базовый путь
# storage-path: / # Путь для хранения, все загружаемые файлы будут сохранены в этом пути, по умолчанию "/", обратите внимание, что он должен заканчиваться слешом "/"
# google-cloud-storage: # Google Cloud Storage
# - platform: google-1 # Идентификатор платформенного хранилища
# enable-storage: true # Активировать хранение
# project-id: ?? # Проект ID
# bucket-name: ??
# credentials-path: file:/deploy/example-key.json # Путь до файла с учетными данными JSON, совместимый с Spring ClassPath, файловым путем, HTTP-путем и т.д.
# domain: ?? # Домен для доступа, обратите внимание, что он должен заканчиваться слешом "/", пример: https://storage.googleapis.com/test-bucket/
# base-path: hy/ # Базовый путь
# fastdfs:
# - platform: fastdfs-1 # Идентификатор платформенного хранилища
# enable-storage: true # Активировать хранение
# run-mod: COVER # Режим выполнения
# tracker-server: # Конфигурация сервера Tracker
# server-addr: ?? # Адрес сервера Tracker (IP:PORT), несколько адресов разделены запятой
# http-port: 80 # По умолчанию: 80
# extra: # Дополнительные настройки
# group-name: group2 # Название группы, может быть пустым
# http-secret-key: FastDFS1234567890 # Секретный ключ безопасности, по умолчанию: FastDFS1234567890
# domain: ?? # Домен для доступа, обратите внимание, что он должен заканчиваться слешом "/", пример: https://file.abc.com/
# base-path: hy/ # Базовый путь
# azure-blob:
# - platform: azure-blob-1 # Идентификатор платформенного хранилища
# enable-storage: true # Активировать хранение
# connection-string: ?? # Строка подключения, Azure Blob Console - Безопасность и сеть - Ключ доступа - Строка подключения
# end-point: ?? # Эндпоинт Azure Blob Console - Настройки - Эндпоинты - Основной эндпоинт - Blob службы
# container-name: ?? # Имя контейнера, аналогично s3 bucketName, Azure Blob Console - Данные - Контейнеры
# domain: ?? # Домен для доступа, обратите внимание, что он должен заканчиваться слешом "/", должен совпадать с end-point
# base-path: hy/ # Базовый путь
```### Код воспроизведения ошибки

```java
/**
 * Загрузка изображения, успешная загрузка возвращает информацию о файле
 * Обработка изображений осуществляется с помощью https://github.com/coobird/thumbnailator
 */
@PostMapping("/upload-image")
public FileInfo uploadImage(@RequestParam("file") MultipartFile file) {
    return fileStorageService
            .of(file)
            .image(img -> img.size(1000, 1000)) // Изменяет размер изображения до 1000x1000
            .thumbnail(th -> th.size(200, 200)) // Генерирует миниатюру размером 200x200
            .upload();
}

Ожидаемый результат

Успешная загрузка и генерация миниатюры

Реальный результат или подробная информация об ошибке

2025-01-15 11:00:10.136 ERROR 68888 --- [nio-8030-exec-4] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() для сервлета [dispatcherServlet] в контексте с путем [] вызвало исключение [Обработка запроса завершилась ошибкой; вложенные исключения есть org.dromara.x.file.storage.core.exception.FileStorageRuntimeException: Обработка изображения завершилась ошибкой!] с корневой причиной net.coobird.thumbnailator.tasks.UnsupportedFormatException: Для исходных данных не найдено подходящее ImageReader.
at net.coobird.thumbnailator.tasks.io.InputStreamImageSource.read(Unknown Source) ~[thumbnailator-0.4.20.jar:0.4.20]
at net.coobird.thumbnailator.tasks.SourceSinkThumbnailTask.read(Unknown Source) ~[thumbnailator-0.4.20.jar:0.4.20]
at net.coobird.thumbnailator.Thumbnailator.createThumbnail(Unknown Source) ~[thumbnailator-0.4.20.jar:0.4.20]
at net.coobird.thumbnailator.Thumbnails$Builder.toOutputStream(Unknown Source) ~[thumbnailator-0.4.20.jar:0.4.20]
at org.dromara.x.file.storage.core.UploadPretreatment.image(UploadPretreatment.java:556) ~[classes/:na]
at org.dromara.x.file.storage.core.upload.UploadPretreatment.image(UploadPretreatment.java:688) ~[classes/:na]
at org.dromara.x.file.storage.test.controller.FileDetailController.uploadImage(FileDetailController.java:48) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_362]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_362]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_362]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_362]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-5.3.22.jar:5.3.22]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) ~[spring-web-5.3.22.jar:5.3.22]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) ~[spring-webmvc-5.3.22.jar:5.3.22]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.3.22.jar:5.3.22]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.22.jar:5.3.22]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.22.jar:5.3.22]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1070) ~[spring-webmvc-5.3.22.jar:5.3.22]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) ~[spring-webmvc-5.3.22.jar:5.3.22]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.22.jar:5.3.22]
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) ~[spring-webmvc-5.3.22.jar:5.3.22]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) ~[tomcat-embed-core-9.0.65.jar:4.0.FR]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.22.jar:5.3.22]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) ~[tomcat-embed-core-9.0.65.jar:4.0.FR]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.65.jar:9.0.65]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.22.jar:5.3.22]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.22.jar:5.3.22]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.22.jar:5.3.22]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.22.jar:5.3.22]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.22.jar:5.3.22]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.22.jar:5.3.22]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) ~[tomcat-embed-core-9.0.65.jar:9.0.65]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) [tomcat-embed-core-9.0.65.jar:9.0.65]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) [tomcat-embed-core-9.0.65.jar:9.0.65]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) [tomcat-embed-core-9.0.65.jar:9.0.65]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.65.jar:9.0.65]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) [tomcat-embed-core-9.0.65.jar:9.0.65]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360) [tomcat-embed-core-9.0.65.jar:9.0.65]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399) [tomcat-embed-core-9.0.65.jar:9.0.65]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.65.jar:9.0.65]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:890) [tomcat-embed-core-9.0.65.jar:9.0.65]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1789) [tomcat-embed-core-9.0.65.jar:9.0.65]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.65.jar:9.0.65]
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) [tomcat-embed-core-9.0.65.jar:9.0.65]
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) [tomcat-embed-core-9.0.65.jar:9.0.65]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.65.jar:9.0.65]
at java.lang.Thread.run(Thread.java:750) [na:1.8.0_362]

Скриншот или видео

[Здесь можно загрузить изображение]

Комментарий (0)

GitLife Service Account Задача создана
GitLife Service Account добавлено
 
question
label.
Развернуть журнал операций

Вход Перед тем как оставить комментарий

Статус
Ответственный
Контрольная точка
Pull Requests
Связанные запросы на слияние могут быть закрыты после их объединения
Ветки
Дата начала   -   Крайний срок
-
Закрепить/Открепить
Приоритет
Участники(1)
1
https://api.gitlife.ru/oschina-mirror/dromara-x-file-storage.git
git@api.gitlife.ru:oschina-mirror/dromara-x-file-storage.git
oschina-mirror
dromara-x-file-storage
dromara-x-file-storage