Contents

@TOC

springboot+minio+docker快速入门

MinIO 是一个基于Apache License v2.0开源协议的对象存储服务。它兼容亚马逊S3云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从几kb到最大5T不等。
MinIO是一个非常轻量的服务,可以很简单的和其他应用的结合,类似 NodeJS, Redis 或者 MySQL。
Minio提供了非常方便,友好的界面,并且文档也是非常丰富,

快速入门

环境搭建,使用docker镜像快速搭建
docker pull minio/minio
使用docker-compose.yml

 1version: '3'
 2services:
 3   minio:
 4    image: minio/minio:latest
 5    container_name: minio
 6    environment:
 7      MINIO_ACCESS_KEY: AKIAIOSFODNN7EXAMPLE
 8      MINIO_SECRET_KEY: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
 9    volumes:
10    - /mnt/data:/data
11    - /mnt/config:/root/.minio
12    ports:
13      - 9000:9000
14    command: server /data
15    healthcheck:
16      test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
17      interval: 30s
18      timeout: 20s
19      retries: 3
20
1docker-compose up -d

登录管理

1http://127.0.0.1:9000/minio/login

在这里插入图片描述

输入 MINIO_ACCESS_KEY 和MINIO_SECRET_KEY
在这里插入图片描述

添加 minio

 1<?xml version="1.0" encoding="UTF-8"?>
 2<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
 4    <modelVersion>4.0.0</modelVersion>
 5    <parent>
 6        <groupId>org.springframework.boot</groupId>
 7        <artifactId>spring-boot-starter-parent</artifactId>
 8        <version>2.1.15.RELEASE</version>
 9        <relativePath/> <!-- lookup parent from repository -->
10    </parent>
11    <groupId>com.example</groupId>
12    <artifactId>minio</artifactId>
13    <version>0.0.1-SNAPSHOT</version>
14    <name>minio</name>
15    <description>Demo project for Spring Boot</description>
16
17    <properties>
18        <java.version>11</java.version>
19    </properties>
20
21    <dependencies>
22        <dependency>
23            <groupId>org.springframework.boot</groupId>
24            <artifactId>spring-boot-starter-web</artifactId>
25        </dependency>
26        <dependency>
27            <groupId>org.springframework.boot</groupId>
28            <artifactId>spring-boot-configuration-processor</artifactId>
29        </dependency>
30        <dependency>
31            <groupId>io.minio</groupId>
32            <artifactId>minio</artifactId>
33            <version>3.0.10</version>
34        </dependency>
35        <dependency>
36            <groupId>org.iherus</groupId>
37            <artifactId>qrext4j</artifactId>
38            <version>1.3.1</version>
39        </dependency>
40        <dependency>
41            <groupId>org.springframework.boot</groupId>
42            <artifactId>spring-boot-starter-test</artifactId>
43            <scope>test</scope>
44        </dependency>
45    </dependencies>
46
47    <build>
48        <plugins>
49            <plugin>
50                <groupId>org.springframework.boot</groupId>
51                <artifactId>spring-boot-maven-plugin</artifactId>
52            </plugin>
53        </plugins>
54    </build>
55
56</project>
57

配置

 1
 2import org.springframework.boot.context.properties.ConfigurationProperties;
 3import org.springframework.stereotype.Component;
 4
 5/**
 6 * 配置属性
 7 * @author top
 8 */
 9@Component
10@ConfigurationProperties(prefix = "minio")
11public class MinioProperties {
12    /**
13     * 对象存储服务的URL
14     */
15    private String endpoint;
16    /**
17     * Access key就像用户ID,可以唯一标识你的账户
18     */
19    private String accessKey;
20    /**
21     * Secret key是你账户的密码
22     */
23    private String secretKey;
24
25    /**
26     * 文件桶的名称
27     */
28    private String bucketName;
29
30
31    public String getEndpoint() {
32        return endpoint;
33    }
34
35    public void setEndpoint(String endpoint) {
36        this.endpoint = endpoint;
37    }
38
39    public String getAccessKey() {
40        return accessKey;
41    }
42
43    public void setAccessKey(String accessKey) {
44        this.accessKey = accessKey;
45    }
46
47    public String getSecretKey() {
48        return secretKey;
49    }
50
51    public void setSecretKey(String secretKey) {
52        this.secretKey = secretKey;
53    }
54
55    public String getBucketName() {
56        return bucketName;
57    }
58
59    public void setBucketName(String bucketName) {
60        this.bucketName = bucketName;
61    }
62}
63

server.port=8789
#文件大小
spring.servlet.multipart.max-file-size=1024MB
spring.servlet.multipart.max-request-size=1024MB

minio.endpoint=http://192.168.0.254:9000
minio.accessKey=AKIAIOSFODNN7EXAMPLE
minio.secretKey=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
minio.bucketName=test


配置类

 1
 2import io.minio.MinioClient;
 3import io.minio.errors.InvalidEndpointException;
 4import io.minio.errors.InvalidPortException;
 5import org.springframework.beans.factory.annotation.Autowired;
 6import org.springframework.context.annotation.Bean;
 7import org.springframework.context.annotation.Configuration;
 8
 9/**
10 * 
11 * 配置类
12 * @author top
13 */
14@Configuration
15public class MinioConfig {
16    @Autowired
17    private MinioProperties properties;
18
19    @Bean
20    public MinioClient minioClient() {
21        MinioClient minioClient = null;
22        try {
23            minioClient = new MinioClient(properties.getEndpoint(), properties.getAccessKey(), properties.getSecretKey());
24        } catch (InvalidEndpointException | InvalidPortException e) {
25            e.printStackTrace();
26        }
27        return minioClient;
28    }
29}
30

封装一个工具,实现文件上传,下载等操作

  1package com.example.minio.utils;
  2
  3import com.example.minio.config.MinioProperties;
  4import io.minio.MinioClient;
  5import io.minio.ObjectStat;
  6import io.minio.Result;
  7import io.minio.errors.MinioException;
  8import io.minio.messages.Item;
  9import org.apache.tomcat.util.http.fileupload.IOUtils;
 10import org.iherus.codegen.qrcode.QrcodeConfig;
 11import org.iherus.codegen.qrcode.SimpleQrcodeGenerator;
 12import org.springframework.beans.factory.annotation.Autowired;
 13import org.springframework.http.MediaType;
 14import org.springframework.stereotype.Component;
 15import org.springframework.web.multipart.MultipartFile;
 16import org.xmlpull.v1.XmlPullParserException;
 17
 18import javax.imageio.ImageIO;
 19import javax.servlet.http.HttpServletResponse;
 20import java.awt.image.BufferedImage;
 21import java.io.ByteArrayInputStream;
 22import java.io.ByteArrayOutputStream;
 23import java.io.IOException;
 24import java.io.InputStream;
 25import java.net.URLEncoder;
 26import java.nio.charset.StandardCharsets;
 27import java.security.InvalidKeyException;
 28import java.security.NoSuchAlgorithmException;
 29import java.util.ArrayList;
 30import java.util.List;
 31import java.util.UUID;
 32
 33/**
 34 * @author top
 35 */
 36@Component
 37public class MinioUtils {
 38
 39    @Autowired
 40    private MinioProperties properties;
 41    @Autowired
 42    private MinioClient minioClient;
 43
 44    /**
 45     * 文件上传
 46     *
 47     * @param file file
 48     */
 49    public void upload(MultipartFile file) {
 50        try {
 51            // 使用MinIO服务的URL,端口,Access key和Secret key创建一个MinioClient对象
 52
 53            // 检查存储桶是否已经存在
 54            boolean isExist = minioClient.bucketExists(properties.getBucketName());
 55            if (!isExist) {
 56                // 创建一个名为test的存储桶,用于存储照片的zip文件。
 57                minioClient.makeBucket(properties.getBucketName());
 58            }
 59            InputStream inputStream = file.getInputStream();
 60            // 使用putObject上传一个文件到存储桶中。
 61            minioClient.putObject(properties.getBucketName(), file.getOriginalFilename(), inputStream, inputStream.available(), file.getContentType());
 62            //关闭
 63            inputStream.close();
 64        } catch (MinioException | NoSuchAlgorithmException | IOException | InvalidKeyException | XmlPullParserException e) {
 65            System.out.println("Error occurred: " + e);
 66        }
 67    }
 68
 69    /**
 70     * 下载
 71     *
 72     * @param response response
 73     * @param fileName fileName
 74     */
 75    public void download(HttpServletResponse response, String fileName) {
 76        InputStream inputStream = null;
 77        try {
 78            ObjectStat stat = minioClient.statObject(properties.getBucketName(), fileName);
 79            inputStream = minioClient.getObject(properties.getBucketName(), fileName);
 80            response.setContentType(stat.contentType());
 81            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8));
 82            IOUtils.copy(inputStream, response.getOutputStream());
 83        } catch (Exception e) {
 84            e.printStackTrace();
 85        } finally {
 86            if (inputStream != null) {
 87                try {
 88                    inputStream.close();
 89                } catch (IOException e) {
 90                    e.printStackTrace();
 91                }
 92            }
 93        }
 94    }
 95
 96    /**
 97     * 获取文件url
 98     *
 99     * @param objectName objectName
100     * @return url
101     */
102    public String getObject(String objectName) {
103        try {
104            return minioClient.getObjectUrl(properties.getBucketName(), objectName);
105        } catch (Exception e) {
106            e.printStackTrace();
107        }
108        return "";
109    }
110
111    /**
112     * 获取所有
113     *
114     * @return
115     */
116    public List<Album> list() {
117        try {
118            List<Album> list = new ArrayList<Album>();
119            Iterable<Result<Item>> results = minioClient.listObjects(properties.getBucketName());
120            for (Result<Item> result : results) {
121                Item item = result.get();
122                // Create a new Album Object
123                Album album = new Album();
124                System.out.println(item.objectName());
125                // Set the presigned URL in the album object
126                album.setUrl(minioClient.getObjectUrl(properties.getBucketName(), item.objectName()));
127                album.setDescription(item.objectName() + "," + item.lastModified() + ",size:" + item.size());
128                // Add the album object to the list holding Album objects
129                list.add(album);
130            }
131            return list;
132        } catch (Exception e) {
133            e.printStackTrace();
134        }
135        return null;
136    }
137
138    /**
139     * 文件删除
140     *
141     * @param name 文件名
142     */
143    public void delete(String name) {
144        try {
145            minioClient.removeObject(properties.getBucketName(), name);
146        } catch (Exception e) {
147            e.printStackTrace();
148        }
149    }
150
151    /**
152     * 上传生成的二维码
153     */
154    public void generator() {
155        String uuid = UUID.randomUUID().toString();
156        InputStream inputStream = bufferedImageToInputStream(qrcode(uuid));
157        try {
158            minioClient.putObject(properties.getBucketName(), uuid + ".png", bufferedImageToInputStream(qrcode(uuid)), inputStream.available(), MediaType.IMAGE_PNG_VALUE);
159        } catch (Exception e) {
160            e.printStackTrace();
161        } finally {
162            try {
163                if (inputStream != null) {
164                    inputStream.close();
165                }
166            } catch (IOException e) {
167                e.printStackTrace();
168            }
169        }
170    }
171
172    public BufferedImage qrcode(String content) {
173        QrcodeConfig config = new QrcodeConfig()
174                .setBorderSize(2)
175                .setPadding(12)
176                .setMasterColor("#00BFFF")
177                .setLogoBorderColor("#B0C4DE")
178                .setHeight(250).setWidth(250);
179        return new SimpleQrcodeGenerator(config).setLogo("src/main/resources/logo.png").generate(content).getImage();
180    }
181
182    /**
183     * @param image image
184     * @return InputStream
185     */
186    public InputStream bufferedImageToInputStream(BufferedImage image) {
187        ByteArrayOutputStream os = new ByteArrayOutputStream();
188        try {
189            ImageIO.write(image, "png", os);
190            return new ByteArrayInputStream(os.toByteArray());
191        } catch (IOException e) {
192            e.fillInStackTrace();
193        } finally {
194            try {
195                os.close();
196            } catch (IOException e) {
197                e.printStackTrace();
198            }
199        }
200        return null;
201    }
202
203    public static class Album {
204        private String url;
205        private String description;
206
207        public String getUrl() {
208            return url;
209        }
210
211        public void setUrl(String url) {
212            this.url = url;
213        }
214
215        public String getDescription() {
216            return description;
217        }
218
219        public void setDescription(String description) {
220            this.description = description;
221        }
222    }
223}
224

controller

 1
 2import com.example.minio.utils.MinioUtils;
 3import org.springframework.beans.factory.annotation.Autowired;
 4import org.springframework.web.bind.annotation.*;
 5import org.springframework.web.multipart.MultipartFile;
 6
 7import javax.servlet.http.HttpServletResponse;
 8import java.io.UnsupportedEncodingException;
 9import java.util.List;
10
11/**
12 * 文件上传下载
13 *
14 * @author top
15 */
16@RestController
17public class MinioController {
18    @Autowired
19    private MinioUtils minioUtils;
20
21    @PostMapping(value = "/upload")
22    public void upload(@RequestParam("file") MultipartFile file) {
23        minioUtils.upload(file);
24    }
25
26    @GetMapping(value = "/download")
27    public void download(HttpServletResponse response, @RequestParam(value = "fileName") String fileName) throws UnsupportedEncodingException {
28        minioUtils.download(response, fileName);
29    }
30
31    @GetMapping(value = "/list")
32    public List<MinioUtils.Album> list() {
33        return minioUtils.list();
34    }
35
36    @GetMapping(value = "/objectName")
37    public String getObject(@RequestParam(value = "fileName") String fileName) {
38        return minioUtils.getObject(fileName);
39    }
40
41    @DeleteMapping(value = "/delete/{name}")
42    public void delete(@PathVariable String name) {
43        minioUtils.delete(name);
44    }
45}
46

总结

完成了一个入门的案例,遇到问题可多看看参考文档。
个人博客地址

参考https://docs.min.io/cn/java-client-quickstart-guide.html