SpringBoot项目集成MinIO

一、MinIO的下载安装以及基本使用

1.下载地址:https://dl.min.io/server/minio/release/windows-amd64/minio.exe

2.下载好后需要手动创建【data】文件夹用于存储Minio中的数据

3.在对应文件路径处,键入【cmd】 后设置MinIO的一些变量(第一次启动需要配置)****

复制代码
set MINIO_ROOT_USER=admin

set MINIO_ROOT_PASSWORD=admin123

set MINIO_ACCESS_KEY=admin

set MINIO_SECRET_KEY=admin123

5.下面是我踩的坑,如果只设置了MINIO_ROOT_USER和MINIO_ROOT_PASSWORD的值,而不设置MINIO_ACCESS_KEY和MINIO_SECRET_KEY的值,当启动minio服务的时候就会报以下异常:

6. 启动minio服务

复制代码
minio.exe server data

7.进入登录页面后,输入对应的用户名和密码,也就是之前设置的MINIO_ROOT_USER和MINIO_ROOT_PASSWORD的值。

8. 进入主界面后,点击左侧导航栏中的Buckets,然后点击Create Bucket。

9.进入该桶,点击upload,上传一个文件

10.点击左侧导航栏中的Buckets,进入该桶,修改权限为public,这样外界就可以访问上传的文件了。

复制代码
桶的默认权限是private,所以外界访问不到,需要修改访问权限为public,但是要注意安全问题

二. SpringBoot集成MinIO

1.引入依赖

复制代码
<dependency>
  <groupId>io.minio</groupId>
  <artifactId>minio</artifactId>
  <version>7.0.2</version>
</dependency>
<dependency>
   <groupId>org.projectlombok</groupId>
   <artifactId>lombok</artifactId>
   <version>1.18.20</version>
</dependency>

2.编写配置文件

复制代码
server:
 port: 8080
spring:
 # 配置文件上传大小限制
 servlet:
  multipart:
   max-file-size: 200MB
   max-request-size: 200MB
minio:
 host: http://127.0.0.1:9000 # 访问地址
 url: ${minio.host}/${minio.bucket}/  # 对象存储服务的url
 access-key: minioadmin # 登录账号
 secret-key: minioadmin # 登录账号密码
 bucketName: test-bucket # 文件桶的名称
 bucket: public  // 权限

3.编写minio配置类

复制代码
@Configuration
public class MinIoClientConfig {
    /**
     * minio配置
     */
    @Value("${minio.url}")
    private String endpoint;
    @Value("${minio.accessKey}")
    private String accessKey;
    @Value("${minio.secretKey}")
    private String secretKey;
    @Value("${minio.bucketName}")
    private String bucketName;

    /**
     * 注入minio客户端
     *
     * @return minio客户端对象
     */
    @Bean
    public MinioClient minioClient() {
        return MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build();
    }
}

4.编写minio工具类

复制代码
@Component
public class MinioUtil {

    /**
     * minio配置
     */
    @Value("${minio.url}")
    private String endpoint;

    @Autowired
    private MinioClient minioClient;
    
    /**
     * 创建一个桶
     */
    public void createBucket(String bucket) throws Exception {
        boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucket).build());
        if (!found) {
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucket).build());
        }
    }
    
    /**
     * 上传一个文件
     */
    public void uploadFile(InputStream stream, String bucket, String objectName) throws Exception {
        ObjectWriteResponse objectWriteResponse = minioClient.putObject(PutObjectArgs.builder().bucket(bucket).object(objectName)
                .stream(stream, -1, 10485760).build());

        System.out.println(objectWriteResponse.object() + " is uploaded successfully.");
    }
    
    /**
     * 列出所有的桶
     */
    public List<String> listBuckets() throws Exception {
        List<Bucket> list = minioClient.listBuckets();
        List<String> names = new ArrayList<>();
        list.forEach(b -> {
            names.add(b.name());
        });
        return names;
    }
    
    /**
     * 列出一个桶中的所有文件和目录
     */
    public List<Fileinfo> listFiles(String bucket) throws Exception {
        Iterable<Result<Item>> results = minioClient.listObjects(
                ListObjectsArgs.builder().bucket(bucket).recursive(true).build());
            
            List<Fileinfo> infos = new ArrayList<>();
                results.forEach(r->{
                    Fileinfo info = new Fileinfo();
                    try {
                        Item item = r.get();
                        info.setFilename(item.objectName());
                        info.setDirectory(item.isDir());
                        info.setFilepath(endpoint+"/"+bucket+"/"+item.objectName());
                        infos.add(info);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                });
        return infos;
    }
    
    /**
     * 下载一个文件
     */
    public InputStream download(String bucket, String objectName) throws Exception {
        InputStream stream = minioClient.getObject(
                      GetObjectArgs.builder().bucket(bucket).object(objectName).build());
        return stream;
    }
    
    /**
     * 删除一个桶
     */
    public void deleteBucket(String bucket) throws Exception {
        minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucket).build());
    }
    
    /**
     * 删除一个对象
     */
    public void deleteObject(String bucket, String objectName) throws Exception {
        minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucket).object(objectName).build());
    }


    /**
     * 复制文件
     */
    public void copyObject(String sourceBucket, String sourceObject, String targetBucket, String targetObject) throws Exception {
        this.createBucket(targetBucket);
        minioClient.copyObject(CopyObjectArgs.builder().bucket(targetBucket).object(targetObject)
                .source(CopySource.builder().bucket(sourceBucket).object(sourceObject).build()).build());
    }

    /**
     * 获取文件信息
     */
    public String getObjectInfo(String bucket, String objectName) throws Exception {
        return minioClient.statObject(StatObjectArgs.builder().bucket(bucket).object(objectName).build()).toString();

    }

    /**
     * 生成一个给HTTP GET请求用的presigned URL。
     * 浏览器/移动端的客户端可以用这个URL进行下载,
     * 即使其所在的存储桶是私有的。
     */
    public String getPresignedObjectUrl(String bucketName, String objectName, Integer expires) throws Exception {
        GetPresignedObjectUrlArgs build = GetPresignedObjectUrlArgs
                .builder().bucket(bucketName).object(objectName).expiry(expires).method(Method.GET).build();
        return minioClient.getPresignedObjectUrl(build);
    }

    /**
     * 获取minio中所有的文件
     */
    public List<Fileinfo> listAllFile() throws Exception {
        List<String> list = this.listBuckets();
        List<Fileinfo> fileinfos = new ArrayList<>();
        for (String bucketName : list) {
            fileinfos.addAll(this.listFiles(bucketName));
        }
        return fileinfos;
    }
}

5.编写文件实体类

复制代码
@Data
public class Fileinfo {
    String filename;
    String filepath;
    Boolean directory;
}

6.编写接口响应实体

复制代码
@Data
public class ResultData<T> {

    public static final Integer SUCCESS_CODE = 200;
    public static final Integer FAIL_CODE = 4000;
    public static final String SUCCESS_MESSAGE = "操作成功";
    public static final String FAIL_MESSAGE = "操作失败";
    /**
     * 返回状态码
     */
    private Integer code;
    /**
     * 返回信息
     */
    private String message;

    /**
     * 返回数据
     */
    private T data;


    public ResultData() {

    }

    public static <T> ResultData<T> success() {
        ResultData<T> resultUtil = new ResultData<>();
        resultUtil.setCode(SUCCESS_CODE);
        resultUtil.setMessage(SUCCESS_MESSAGE);
        return resultUtil;
    }

    public static <T> ResultData<T> success(T data) {
        ResultData<T> resultUtil = success();
        resultUtil.setData(data);
        return resultUtil;
    }

    public static <T> ResultData<T> success(String message, T data) {
        ResultData<T> resultUtil = success();
        resultUtil.setMessage(message);
        resultUtil.setData(data);
        return resultUtil;
    }

    public static <T> ResultData<T> success(Integer code, String message, T data) {
        ResultData<T> resultUtil = new ResultData<>();
        resultUtil.setCode(code);
        resultUtil.setMessage(message);
        resultUtil.setData(data);
        return resultUtil;
    }

    public static <T> ResultData<T> success(Integer code, String message,Integer count, T data) {
        ResultData<T> resultUtil = new ResultData<>();
        resultUtil.setCode(code);
        resultUtil.setMessage(message);
        resultUtil.setData(data);
        return resultUtil;
    }

    public static <T> ResultData<T> fail() {
        ResultData<T> resultUtil = new ResultData<>();
        resultUtil.setCode(FAIL_CODE);
        resultUtil.setMessage(FAIL_MESSAGE);
        return resultUtil;
    }

    public static <T> ResultData<T> fail(T data) {
        ResultData<T> resultUtil = fail();
        resultUtil.setData(data);
        return resultUtil;
    }

    public static <T> ResultData<T> fail(String message, T data) {
        ResultData<T> resultUtil = fail();
        resultUtil.setMessage(message);
        resultUtil.setData(data);
        return resultUtil;
    }

    public static <T> ResultData<T> fail(Integer code, String message) {
        ResultData<T> resultUtil = fail();
        resultUtil.setCode(code);
        resultUtil.setMessage(message);
        return resultUtil;
    }

    public static <T> ResultData<T> fail(Integer code, String message, T data) {
        ResultData<T> resultUtil = new ResultData<>();
        resultUtil.setCode(code);
        resultUtil.setMessage(message);
        resultUtil.setData(data);
        return resultUtil;
    }

    public void setCode(int code){
        this.code = code;
    }
    public int getCode(){
        return this.code;
    }
    public void setMessage(String message){
        this.message = message;
    }
    public String getMessage(){
        return message;
    }
    public void setData(T data){
        this.data = data;
    }
    public T getData(){
        return data;
    }
}

7.创建minio控制器

复制代码
/**
 * minio相关接口
 *
 * @author songwp
 * @date 2024/11/11 11:28
 */
@RestController
@RequestMapping("minio")
public class MinioController {

    @Autowired
    MinioUtil minioUtil;


    /**
     * 文件上传
     *
     * @param file 文件
     * @param bucket 桶名
     * @param objectName 对象名
     * @return 是否成功
     * @throws Exception
     */
    @RequestMapping(value = "/upload", method = RequestMethod.POST)
    public ResultData upload(@RequestParam MultipartFile file,
                             @RequestParam String bucket,
                             @RequestParam(required = false) String objectName) throws Exception {
        minioUtil.createBucket(bucket);
        if (objectName != null) {
            minioUtil.uploadFile(file.getInputStream(), bucket, objectName + "/" + file.getOriginalFilename());
        } else {
            minioUtil.uploadFile(file.getInputStream(), bucket, file.getOriginalFilename());
        }
        return ResultData.success();
    }

    /**
     * 获取文件信息
     * @param bucket 桶名
     * @return 是否成功
     */
    @RequestMapping(value = "/getFile", method = RequestMethod.GET)
    public ResultData getFile(@RequestParam ("bucket")String bucket){
        try {
            List<Fileinfo> fileinfos = minioUtil.listFiles(bucket);
            return ResultData.success(fileinfos);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 文件下载
     *
     * @param bucket 桶名
     * @param objectName 对象名
     * @return 是否成功
     */
    @GetMapping("download")
    public ResultData download(@RequestParam("bucket") String bucket,
                               @RequestParam("objectName") String objectName){
        try {
            InputStream download = minioUtil.download(bucket, objectName);
            return ResultData.success();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取文件信息
     *
     * @param bucket 桶名
     * @param objectName 对象名
     * @return 是否成功
     */
    @GetMapping("getObjectInfo")
    public ResultData getObjectInfo(@RequestParam("bucket") String bucket,
                               @RequestParam("objectName") String objectName) throws Exception {
        String objectInfo = minioUtil.getObjectInfo(bucket, objectName);
        String objectStat = objectInfo.replaceAll("ObjectStat", "");
        return ResultData.success(objectStat);
    }


    /**
     * 生成一个给HTTP GET请求用的presigned URL。
     *
     * @param bucket 桶名
     * @param objectName 对象名
     * @return 是否成功
     */
    @GetMapping("getObjectUrl")
    public ResultData getObjectUrl(@RequestParam("bucket") String bucket,
                                    @RequestParam("objectName") String objectName) throws Exception {
        String url = minioUtil.getPresignedObjectUrl(bucket, objectName,7200);
        return ResultData.success(url);
    }


    /**
     * 列出所有的桶
     */
    @RequestMapping(value = "/listBuckets", method = RequestMethod.GET)
    public ResultData listBuckets() throws Exception {
        return ResultData.success(minioUtil.listBuckets());
    }

    /**
     * 获取minio中所有的文件
     */
    @RequestMapping(value = "/listAllFile", method = RequestMethod.GET)
    public ResultData listAllFile() throws Exception {
        return ResultData.success(minioUtil.listAllFile());
    }
}

8.postman接口调用实例

9.最后查看test-bucket桶中是否有刚才上传的文件就可以了。如果有则表明你的项目已经成功集成minio了

相关推荐
Heartsuit5 小时前
云原生之运维监控实践-使用Prometheus与Grafana实现对MinIO服务的监测
云原生·grafana·prometheus·minio·运维监控
CSDN专家-赖老师(软件之家)1 天前
养老院管理系统+小程序项目需求分析文档
vue.js·人工智能·小程序·mybatis·springboot
武子康2 天前
Java-07 深入浅出 MyBatis - 一对多模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据库·sql·mybatis·springboot
武子康3 天前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud
初晴~3 天前
【Spring】RESTful设计风格
java·后端·spring·springboot·restful
阑梦清川4 天前
SpringMVC案例学习(二)--表白墙/图书管理系统1.0版本
spring·mvc·springboot·案例
武子康5 天前
Java-04 深入浅出 MyBatis - SqlSessionFactory 与 SqlSession DAO与Mapper 代理模式
java·mysql·spring·mybatis·springboot·代理模式
进击的阿晨5 天前
Kotlin:后端开发的新宠
后端·springboot
VipSoft5 天前
RedisTemplate RedisConfig 序列化方式 fastjson2
springboot
billy_gisboy6 天前
01_MinIO部署(Windows单节点部署/Docker化部署)
minio