springboot集成minio客户端


文章目录

  • springboot集成minio客户端
  • 1 配置文件桶权限
  • 2 引入minio客户端依赖
  • 3 配置文件修改
  • 4 定义minio配置类
  • 5 封装MinioClient
  • 6 HTTP接口实例
  • 7 总结



由于项目技术栈需要使用springboot框架,以下详细介绍spring boot如何集成minio客户端过程,使用intellij idea集成开发环境,maven进行项目管理。

1 配置文件桶权限

首先我们需要部署minio服务并运行

通过minio服务自带的web界面,创建文件桶test:

springboot 整合netty 容器问题 springboot整合minio_spring

配置文件桶test权限:

springboot 整合netty 容器问题 springboot整合minio_minio_02

test权限配置成公开可读写权限,便于后续演示操作,如想使用minio权限功能,可参照官方文档。

2 引入minio客户端依赖

在pom.xml中加入minio依赖:

<!--minioclient-->
        <dependency>
            <groupId>io.minio</groupId>
            <artifactId>minio</artifactId>
            <version>7.0.2</version>
        </dependency>

3 配置文件修改

在配置文件中增加minio相关配置,我的项目中配置文件格式为properties格式,在末尾增加:

#minio配置参数
minio.endpoint=10.45.154.179
minio.port=9000
minio.accessKey=minioadmin
minio.secretKey=minioadmin
minio.bucketName=test

endpoint、port改成自己minio服务器的IP和端口,accessKey/secretKey改成自己minio服务器的账号信息即可。

4 定义minio配置类

minio参数配置类定义如下,自动映射properties对应参数项,为对象bean属性捆绑数据,类名为MinioConfig。

package com.znv.manage.minio;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@Data
@Configuration
@ConfigurationProperties(prefix = "minio")
public class MinioConfig {

    //minio服务Ip地址
    private String endpoint;
    //minio服务端口
    private int port;
    //minio接入用户名
    private String accessKey;
    //minio接入密码
    private String secretKey;
    //通讯方式是否为https
    //private boolean secure;
    //存储桶名
    private String bucketName;
}

5 封装MinioClient

为了便于业务层调用,增加代码的灵活性和扩展性,对原始的MinioClient进行封装,形成minio操作的工具类,代码如下:

package com.znv.manage.minio;

import com.alibaba.cloud.commons.io.IOUtils;
import io.minio.MinioClient;
import io.minio.ObjectStat;
import io.minio.PutObjectOptions;
import io.minio.messages.Bucket;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.List;

@Slf4j
@Component
public class MinIoUtil {

    @Autowired
    MinioConfig minioConfig;
    private static MinioClient minioClient;

    /**
     * 初始化minio配置
     *
     * @param :
     * @return: void
     * @date :
     */

    @PostConstruct
    public void init() {
        try {
            minioClient = new MinioClient(minioConfig.getEndpoint(), minioConfig.getPort(), minioConfig.getAccessKey(), minioConfig.getSecretKey(), false);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("minioncliet init error: ", e.fillInStackTrace());
        }
    }

    /**
     * 判断 bucket是否存在
     *
     * @param bucketName: 文件桶名
     * @return: boolean
     * @date :
     */
    @SneakyThrows(Exception.class)
    public static boolean bucketExists(String bucketName) {
        return minioClient.bucketExists(bucketName);
    }

    /**
     * 创建 bucket
     *
     * @param bucketName: 文件桶名
     * @return: void
     * @date :
     */
    @SneakyThrows(Exception.class)
    public static void createBucket(String bucketName) {
        boolean isExist = minioClient.bucketExists(bucketName);
        if (!isExist) {
            minioClient.makeBucket(bucketName);
        }
    }

    /**
     * 获取全部bucket
     *
     * @param :
     * @return: java.util.List<io.minio.messages.Bucket>
     * @date :
     */
    @SneakyThrows(Exception.class)
    public static List<Bucket> getAllBuckets() {
        return minioClient.listBuckets();
    }

    /**
     * 文件上传
     *
     * @param bucketName: 文件桶名
     * @param fileName:   文件名
     * @param filePath:   文件路径
     * @return: void
     * @date :
     */
    @SneakyThrows(Exception.class)
    public static void upload(String bucketName, String fileName, String filePath) {
        minioClient.putObject(bucketName, fileName, filePath, null);
    }

    /**
     * 文件上传
     *
     * @param bucketName: 文件桶名
     * @param fileName:   文件名
     * @param stream:     文件流
     * @return: java.lang.String : 文件url地址
     * @date :
     */
    @SneakyThrows(Exception.class)
    public static String upload(String bucketName, String fileName, InputStream stream) {
        minioClient.putObject(bucketName, fileName, stream, new PutObjectOptions(stream.available(), -1));
        return getFileUrl(bucketName, fileName);
    }

    /**
     * 文件上传
     *
     * @param bucketName: 文件桶名
     * @param file:       文件
     * @return: java.lang.String : 文件url地址
     * @date :
     */
    @SneakyThrows(Exception.class)
    public static String upload(String bucketName, MultipartFile file) {
        final InputStream is = file.getInputStream();
        final String fileName = file.getOriginalFilename();
        minioClient.putObject(bucketName, fileName, is, new PutObjectOptions(is.available(), -1));
        is.close();
        return getFileUrl(bucketName, fileName);
    }

    /**
     * 删除文件
     *
     * @param bucketName: 文件桶名
     * @param fileName:   文件名
     * @return: void
     * @date :
     */
    @SneakyThrows(Exception.class)
    public static void deleteFile(String bucketName, String fileName) {
        minioClient.removeObject(bucketName, fileName);
    }

    /**
     * 获取minio文件的下载地址
     *
     * @param bucketName: 文件桶名
     * @param fileName:   文件名
     * @return: java.lang.String
     * @date :
     */
    @SneakyThrows(Exception.class)
    public static String getFileUrl(String bucketName, String fileName) {
        return minioClient.presignedGetObject(bucketName, fileName);
    }

    /**
     * 下载文件
     *
     * @param bucketName: 文件桶名
     * @param fileName:   文件名
     * @param
     * @return: void
     * @date :
     */
    @SneakyThrows(Exception.class)
    public static InputStream download(String bucketName, String fileName) {
        // 获取对象的元数据
        return minioClient.getObject(bucketName, fileName);
    }
}

6 HTTP接口实例

通过HTTP提供文件上传、下载、删除服务,这里以文件上传为例,实例代码如下:

package com.znv.manage.controller;

import com.alibaba.fastjson.JSONObject;
import com.znv.manage.common.bean.Result;
import com.znv.manage.common.exception.ResultCodeEnum;
import com.znv.manage.minio.MinIoUtil;
import com.znv.manage.minio.MinioConfig;
import com.znv.manage.minio.StorageFileInfo;
import com.znv.manage.service.StorageFileService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Base64Utils;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author wangdenuan
 * @version 1.0
 * @description: TODO
 * @date 2022-4-18 8:47
 */
@Slf4j
@RestController
public class testController {
    @Autowired
    MinioConfig minioConfig;

    @Autowired
    StorageFileService storageFileService;

    /**
     * minio上传文件,文件base64加密
     */
    @PostMapping(value = "/test-upload-encryption")
    public Object uploadFileEncryption(@RequestBody JSONObject jsonObj) throws IOException {
        Result ret = new Result();
        if (CollectionUtils.isEmpty(jsonObj)) {
            ret.setCode(ResultCodeEnum.SYSTEMERROR.getCode());
            ret.setMessage("jsonObj is null");
            return ret;
        }

        String fileData = jsonObj.getString("fileData");
        if ((null == fileData) || (0 >= fileData.length())) {
            ret.setCode(ResultCodeEnum.NOTACCEPTABLE.getCode());
            ret.setMessage("fileData is null");
            return ret;
        }
        byte[] picStream = Base64Utils.decodeFromString(fileData);
        String fileName = jsonObj.getString("fileName");
        String httpUrl = MinIoUtil.upload(minioConfig.getBucketName(), fileName, new ByteArrayInputStream(picStream));

        String filePath = "/LOCATEIMG/" + minioConfig.getBucketName() + "/" + fileName;
        JSONObject result = new JSONObject();
        result.put("result", "success");
        result.put("filePath", filePath);
        String[] splitstr = httpUrl.split("\\?", 2);
        httpUrl = splitstr[0];
        result.put("httpUrl", httpUrl);
        return result;
    }
}

通过HTTP接口/test-upload-encryption,上传图片base64编码数据,保存到minio存储服务上,并返回图片URL,通过图片URL可直接方案图片(这里配置的权限是公开可读写,所以直接通过urliuke访问)。

通过postman来验证端口,验证过程如下:

springboot 整合netty 容器问题 springboot整合minio_spring_03

可以通过http://10.45.156.156:9000/test/test3.jpg 图片地址直接下载图片:

springboot 整合netty 容器问题 springboot整合minio_spring_04

7 总结

springboot集成minio非常简单,通过封装minioclient,可增加代码的灵活性可扩展性,隔离底层存储接口,后续入要更换其他的存储,经过简单的适配即可实现,通过REST提供存储的基础能力接口,可非常简单的被使用。