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

一、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;@Beanpublic MinioClient minioClient() {return MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build();}
}

3. 配置文件

# application.yml
minio:endpoint: http://your-server-ip:9000accessKey: adminsecretKey: your-strong-passwordbucket: 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 {@Autowiredprivate 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());}}