0


在springboot中使用MinIO实现文件上传功能

1.在Linux中通过docker中拉取minio镜像

docker pull bitnami/minio 

可以使用docker images 查看是否有minio镜像,如果有说明已经获取minio镜像了

2.创建一个文件用于存储MinIO的数据

mkdir -p /minio/data

给该文件赋予完全开放的权限

chmod -R 777 minio/data

3.启动及配置 MinIo

docker run -it -d --name minio -p 9000:9000 -p 9001:9001 -v /minio/data:/data -e MINIO_ROOT_USER="minio_root" -e MINIO_ROOT_PASSWORD="minio_123456" bitnami/minio:latest

4.通过日志查看MinIo

docker logs -f minio

5.在window中访问图中的url,切记,切记浏览器访问端口9001,java API端口是9000

访问的url为 虚拟机的ip地址:9001

6.创建自己的Buckets

7.设置Buckets权限为public

8.生成密钥

导入MinIO依赖

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

配置yml文件

minio:
  endpoint: http://xxx:9000 #Minio服务所在地址
  bucketName: test-minio #存储桶名称
  accessKey: minio_root #访问的key,也可以是上面创建的AccessKey
  secretKey: minio_123456 #访问的秘钥,也可以是上面创建的SecretKey
  upload: test #文件上传路径

MinIOConfig配置类

@Configuration
public class MinIOConfig  implements InitializingBean {
​
    @Value("${minio.endpoint}")
    private String minio_endpoint;
    @Value("${minio.accessKey}")
    private String minio_accessKey;
    @Value("${minio.secretKey}")
    private String minio_secretKey;
    @Value("${minio.bucketName}")
    private String minio_bucketName;
    @Value("${minio.upload}")
    private String minio_upload;
​
    public static String MINIO_END_POINT;
    public static String MINIO_ACCESS_KEY;
    public static String MINIO_SECRET_KEY;
    public static String MINIO_BUCKET_NAME;
    public static String MINIO_UPLOAD;
​
    @Override
    public void afterPropertiesSet() throws Exception {
        MINIO_END_POINT = minio_endpoint;
        MINIO_ACCESS_KEY = minio_accessKey;
        MINIO_SECRET_KEY = minio_secretKey;
        MINIO_BUCKET_NAME = minio_bucketName;
        MINIO_UPLOAD=minio_upload;
    }
}

文件上传的controller层:

 @Autowired
private FileStrategy fileStrategy;
​
@PostMapping("upload")
@ApiOperation(value = "文件上传")
public Result<Url> upload(MultipartFile file) throws Exception{
    Result result=new Result();
    try {
        log.info("upload-------------------------------");
        if(null != file){
            if(file.getOriginalFilename().contains("mp4")){
                //如果上传的视频,校验大小不能超过2M
                if(file.getSize()>2048*1024){
                    result= new Result(CoReturnFormat.MP4_FILE_NOT_2M);
                    return result;
                }
            }
            String url=fileStrategy.upload(file);
            //fileUploadService.uploadFile(file.getOriginalFilename(),file.getInputStream(),file.getSize());
            result=new Result(new Url(url),CoReturnFormat.SUCCESS);
        }
        return result;
    } catch (Exception e) {
        log.error("upload fail " + e.getMessage(), e);
    }
    return result;
}

FileStrategy:

public interface FileStrategy {
    String upload(MultipartFile file) throws Exception;
}

MinIOAutoConfigure:

@Configuration
@Slf4j
@ConditionalOnProperty(name = "upload.type", havingValue = "MIN")
public class MinIOAutoConfigure {
    @Service
    public class MinIOServiceImpl implements FileStrategy{
        private final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        @Override
        public String upload(MultipartFile file) throws Exception {
            String filename = file.getOriginalFilename();
            InputStream in = file.getInputStream();
            long size = file.getSize();
            log.info("filename {} size {}", filename, size);
            Objects.requireNonNull(filename);
            filename = filename.replaceAll(" ", "");
            String fileName= MinIOConfig.MINIO_UPLOAD;
            // 创建MinioClient实例。
            MinioClient minioClient = MinioClient.builder().endpoint(MinIOConfig.MINIO_END_POINT).credentials(MinIOConfig.MINIO_ACCESS_KEY, MinIOConfig.MINIO_SECRET_KEY).build();
​
            String dateStr = format.format(new Date());
            //创建文件路径
            String fileUrl = fileName+"/"+(dateStr + "/" + UUID.randomUUID().toString().replace("-","") + "_" + filename);
            InputStream inputStream=in;
            if(size>5*1024*1024){
                //大于5M就压缩
                if(filename.contains("jpg")||filename.contains("png")){
                    //如果是图片,压缩一下
                    inputStream = ImageUtil.compressImg(in, 1.1f);
                }
            }
            // 上传网络流。
​
            PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(MinIOConfig.MINIO_BUCKET_NAME).object(fileUrl)
                    .stream(file.getInputStream(), file.getSize(), -1).contentType(file.getContentType()).build();
            //文件名称相同会覆盖
            minioClient.putObject(objectArgs);
​
            if (inputStream != null) {
                inputStream.close();
            }
            if (in != null) {
                in.close();
            }
            return  MinIOConfig.MINIO_END_POINT+ "/" + MinIOConfig.MINIO_BUCKET_NAME + "/" + fileUrl;
​
        }
   }

实现文件上传到minIO的主要代码就是putObject()方法

它需要我们创建一个新的

PutObjectArgs

对象的构建器(Builder),用于设置上传文件所需的参数

.bucket(MinIOConfig.MINIO_BUCKET_NAME)

:设置要上传到的MinIO存储桶(bucket)的名称

.object(fileUrl)

:设置要上传的对象(文件)的名称,表示文件在存储桶中的路径和名称。

.stream(file.getInputStream(), file.getSize(), -1)

:设置文件的输入流、文件大小以及超时时间。

file.getInputStream()

获取文件的输入流,

file.getSize()

获取文件的大小,

-1

表示使用默认的超时时间。

.contentType(file.getContentType())

:设置文件的内容类型

运行项目报错:

Caused by: java.lang.RuntimeException: Unsupported OkHttp library found. Must use okhttp >= 4.8.1
    at io.minio.S3Base.<clinit>(S3Base.java:106)
    ... 50 common frames omitted
Caused by: java.lang.NoSuchMethodError: kotlin.collections.ArraysKt.copyInto([B[BIII).............

问题需要将okhttp升级4.8.1以上版本

将okhttp升级到4.8.1版本后,还是不行,这时候就要思考是不是okhttp的版本冲突导致,可以通过下载Maven help插件看依赖树,我们可以注意到了报错信息中的NoSuchMethodError: kotlin.collections.ArraysKt.copyInto通过搜索kotlin

发现两个kotlin出现版本不同的问题,所以ArraysKt中找不到copyInto方法。

解决方法:

在 minio 的依赖中排除 okhttp 依赖,再单独引入所需的 okhttp 依赖。在引入的 okhttp 的依赖中排除 kotlin 的依赖,再单独引入所需 kotlin 依赖。

<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>8.5.2</version>
    <exclusions>
       <exclusion>
          <artifactId>okhttp</artifactId>
          <groupId>com.squareup.okhttp3</groupId>
       </exclusion>
    </exclusions>
</dependency>
​
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.8.1</version>
    <exclusions>
       <exclusion>
          <artifactId>kotlin-stdlib</artifactId>
          <groupId>org.jetbrains.kotlin</groupId>
       </exclusion>
    </exclusions>
</dependency>
​
<dependency>
    <groupId>org.jetbrains.kotlin</groupId>
    <artifactId>kotlin-stdlib</artifactId>
    <version>1.3.70</version>
</dependency>

详细可以看springboot引入minio导致的okhttp、kotlin的版本冲突问题_io.minio.s3base.(s3base.java:104)-CSDN博客

如果出现Non-XML response from server的错误,那就很有可能是在yml文件中端口号配置错误了(浏览器访问端口9001,java API端口是9000),我就是端口之前写错过,找了半天qwq。

接下来重新运行项目,应该就不会报错了

通过debug来了解流程

可以通过前端直接发送请求,也可以用postman发送请求,根据自己的情况来

我们可以看到图片已经上传到minio中了

接下来我们通过访问给前端返回url看是否可以查看图片如果可以,就说明成功了,如果不可以,可能是url写错或者忘记在创建PutObjectArgs时使用contentType(file.getContentType())

好了,以上就是根据我的项目来实现MinIo文件上传功能,以及遇到的一些问题和解决方法,希望对大家有所帮助。

标签: spring boot 后端 java

本文转载自: https://blog.csdn.net/m0_74920346/article/details/143083616
版权归原作者 不会敲码的喵喵 所有, 如有侵权,请联系我们删除。

“在springboot中使用MinIO实现文件上传功能”的评论:

还没有评论