在云服务器上搭建 MinIO 图片存储服务器及 Spring Boot 整合实现图片上传下载

发布于:2025-06-27 ⋅ 阅读:(21) ⋅ 点赞:(0)

一、MinIO 核心概念

MinIO 是一个高性能的分布式对象存储服务器,兼容 Amazon S3 API,具有以下特点:

  • 高性能:针对存储和检索优化

  • 轻量级:单个二进制文件即可运行

  • 云原生:支持 Kubernetes 部署

  • S3 兼容:可以直接替换 AWS S3

  • 数据保护:纠删码和加密支持

核心组件

  1. MinIO Server:存储服务主体

  2. MinIO Client (mc):命令行管理工具

  3. MinIO Console:Web 管理界面

二、MinIO 服务端搭建

1. 单机模式部署

使用docker命令拉取镜像

docker pull minio/minio:RELEASE.2023-04-28T18-11-17Z

启动命令

docker run -d \
  -p 9000:9000 -p 9001:9001 \
   -v ~/minio/data:/data \
   --name minio \
   docker.io/minio/minio:RELEASE.2023-04-28T18-11-17Z \
   server /data --console-address ":9001"

查看启动结果:

在自己的云服务器防火墙上开放9000和9001端口

2. . 访问管理界面

浏览器访问:http://your-server-ip:9001

默认账户密码:

username:minioadmin

password:minioadmin

三、Spring Boot 集成 MinIO

1. 添加依赖

<!-- pom.xml -->
<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>8.5.2</version>
</dependency>

2. 配置 MinIO 客户端

@Configuration
public class MinioConfig {
    
    @Value("${minio.endpoint}")
    private String endpoint;
    
    @Value("${minio.accessKey}")
    private String accessKey;
    
    @Value("${minio.secretKey}")
    private String secretKey;
    
    @Bean
    public MinioClient minioClient() {
        return MinioClient.builder()
                .endpoint(endpoint)
                .credentials(accessKey, secretKey)
                .build();
    }
}

3. 配置文件

# application.yml
minio:
  endpoint: http://your-server-ip:9000
  accessKey: admin
  secretKey: your-strong-password
  bucket: images

四、核心功能实现

package com.hl.mybatisplus;
​
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Item;
import org.apache.commons.compress.utils.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
​
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.util.List;
import java.util.concurrent.TimeUnit;
​
@RestController
@RequestMapping("/minio")
public class MinioController {
    @Autowired
    private MinioClient minioClient;
​
    @Value("${minio.bucket}")
    private String bucketName;
​
    // 设置存储桶策略为只读公开
    String policy = "{\n" +
            "  \"Version\": \"2012-10-17\",\n" +
            "  \"Statement\": [\n" +
            "    {\n" +
            "      \"Effect\": \"Allow\",\n" +
            "      \"Principal\": \"*\",\n" +
            "      \"Action\": [\"s3:GetObject\"],\n" +
            "      \"Resource\": [\"arn:aws:s3:::" + bucketName + "/*\"]\n" +
            "    }\n" +
            "  ]\n" +
            "}";
​
​
    @RequestMapping("upload")
    public String uploadFile(MultipartFile file, String objectName) throws Exception {
        // 确保存储桶存在
        createBucket();
        // 上传文件
        ObjectWriteResponse response = minioClient.putObject(
                PutObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .stream(file.getInputStream(), file.getSize(), -1)
                        .contentType(file.getContentType())
                        .build());
        System.out.println(response);
​
        String url = minioClient.getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                        .method(Method.GET)
                        .bucket(bucketName)
                        .object(objectName)
                        .expiry(1, TimeUnit.HOURS)
                        .build());
        System.out.println("Temp URL: " + url);
​
​
        return objectName;
    }
​
    
    // 控制器示例
    @GetMapping("/download/{objectName}")
    public void downloadFile(@PathVariable String objectName, HttpServletResponse response) throws Exception {
        try (InputStream inputStream = downloadFile(objectName)) {
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", "attachment; filename=\"" + objectName + "\"");
            IOUtils.copy(inputStream, response.getOutputStream());
            response.flushBuffer();
        }
    }
​
    public void createBucket() throws Exception {
        boolean found = minioClient.bucketExists(BucketExistsArgs.builder()
                .bucket(bucketName)
                .build());
        if (!found) {
            // 设置存储桶策略为只读公开
            minioClient.setBucketPolicy(
                    SetBucketPolicyArgs.builder()
                            .bucket(bucketName)
                            .config(policy)
                            .build());
//            minioClient.makeBucket(MakeBucketArgs.builder()
//                    .bucket(bucketName)
//                    .build());
        }
    }
    
    
    public InputStream downloadFile(String objectName) throws Exception {
        return minioClient.getObject(
                GetObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .build());
    }
    
}

网站公告

今日签到

点亮在社区的每一天
去签到