一、开发前戏
1.先导入maven依赖
( MinIO版本不能太低不然运行时会出现:org.xmlpull.v1.XmlPullParserException 错误)
<!-- minio 相关依赖 --><dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>3.0.10</version></dependency><!-- alibaba的fastjson --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.51</version></dependency><!-- thymeleaf模板引擎 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency>
2、添加配置信息
在 application.yml 文件中加入 MinIO 服务器的相关信息
#minio 文件存储配置信息minio:endpoint: http://127.0.0.1:9000accesskey: adminsecretKey: admin123456
3、创建实体类package com.zyxx.email.common.minio;
import lombok.Data;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.stereotype.Component;/*** minio 属性值*/@Data@Component@ConfigurationProperties(prefix = "minio")public class MinioProp {/*** 连接url*/private String endpoint;/*** 用户名*/private String accesskey;/*** 密码*/private String secretKey;}
这一步,我们将配置文件中 minio 的配置信息通过注解的方式注入到 MinioProp 这个实体中,方便后面我们使用
4、创建核心配置类
package com.zyxx.email.common.minio;import io.minio.MinioClient;import io.minio.errors.InvalidEndpointException;import io.minio.errors.InvalidPortException;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.context.properties.EnableConfigurationProperties;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;/*** minio 核心配置类*/@Configuration@EnableConfigurationProperties(MinioProp.class)public class MinioConfig {@Autowiredprivate MinioProp minioProp;/*** 获取 MinioClient** @return* @throws InvalidPortException* @throws InvalidEndpointException*/@Beanpublic MinioClient minioClient() throws InvalidPortException, InvalidEndpointException {return new MinioClient(minioProp.getEndpoint(), minioProp.getAccesskey(), minioProp.getSecretKey());}}
通过注入 MinIO 服务器的相关配置信息,得到 MinioClient 对象,我们上传文件依赖此对象
5、上传工具类
package com.zyxx.email.common.minio;import com.alibaba.fastjson.JSONObject;import com.zyxx.email.common.redis.RedisUtil;import com.zyxx.email.utils.DateUtils;import io.minio.MinioClient;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;@Slf4j@Componentpublic class MinioUtils {@Autowiredprivate MinioClient client;@Autowiredprivate MinioProp minioProp;/*** 创建bucket** @param bucketName bucket名称*/@SneakyThrowspublic void createBucket(String bucketName) {if (!client.bucketExists(bucketName)) {client.makeBucket(bucketName);}}/*** 上传文件** @param file 文件* @param bucketName 存储桶* @return*/public JSONObject uploadFile(MultipartFile file, String bucketName) throws Exception {JSONObject res = new JSONObject();res.put("code", 0);// 判断上传文件是否为空if (null == file || 0 == file.getSize()) {res.put("msg", "上传文件不能为空");return res;}// 判断存储桶是否存在createBucket(bucketName);// 文件名String originalFilename = file.getOriginalFilename();// 新的文件名 = 存储桶名称_时间戳.后缀名String fileName = bucketName + "_" + System.currentTimeMillis() + originalFilename.substring(originalFilename.lastIndexOf("."));// 开始上传client.putObject(bucketName, fileName, file.getInputStream(), file.getContentType());res.put("code", 1);res.put("msg", minioProp.getEndpoint() + "/" + bucketName + "/" + fileName);return res;}}
二、开发进行中
1、编写 Controller
package com.zyxx.email.controller;import com.alibaba.fastjson.JSONObject;import com.zyxx.email.common.minio.MinioUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.*;import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletRequest;@Controllerpublic class MinioController {@Autowiredprivate MinioUtils minioUtils;@GetMapping("init")public String init() {return "file";}/*** 上传** @param file* @param request* @return*/@PostMapping("/upload")@ResponseBodypublic String upload(@RequestParam(name = "file", required = false) MultipartFile file, HttpServletRequest request) {JSONObject res = null;try {res = minioUtils.uploadFile(file, "product");} catch (Exception e) {e.printStackTrace();res.put("code", 0);res.put("msg", "上传失败");}return res.toJSONString();}}
2、上传页面
<!DOCTYPE html><html lang="en" xmlns:th="http://www.thymeleaf.org"><head><meta charset="UTF-8"><title>首页</title></head><body><form accept-charset="UTF-8" th:action="@{upload}" method="post" enctype="multipart/form-data" target="_blank">文件:<input type="file" name="file"/><input type="submit" value="上传"/></form></body></html>
这里我用的 thymeleaf 模板引擎
三、上传测试
1、访问地址

2、启动 MinIO 文件服务器
3、响应信息
{“msg”:”http://127.0.0.1:9000/product/product_1589105654237.png”,”code”:1}
1
http://127.0.0.1:9000/product/product_1589105654237.png 就是我们上传之后得到的文件地址了
4、访问文件
MinIO 形式上传的文件也不支持直接访问,我们如果需要直接访问,还需要做如下操作:
设置 bucket 的 policy 策略:
设置该存储桶下面的文件为 Read and Write,这时我们就可以直接访问了
四、完整工具类代码
package com.zyxx.email.common.minio;import com.alibaba.fastjson.JSONObject;import com.zyxx.email.utils.DateUtils;import io.minio.MinioClient;import io.minio.ObjectStat;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 java.io.InputStream;import java.util.*;@Slf4j@Componentpublic class MinioUtils {@Autowiredprivate MinioClient client;@Autowiredprivate MinioProp minioProp;/*** 创建bucket** @param bucketName bucket名称*/@SneakyThrowspublic void createBucket(String bucketName) {if (!client.bucketExists(bucketName)) {client.makeBucket(bucketName);}}/*** 获取全部bucket*/@SneakyThrowspublic List<Bucket> getAllBuckets() {return client.listBuckets();}/*** 根据bucketName获取信息** @param bucketName bucket名称*/@SneakyThrowspublic Optional<Bucket> getBucket(String bucketName) {return client.listBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();}/*** 根据bucketName删除信息** @param bucketName bucket名称*/@SneakyThrowspublic void removeBucket(String bucketName) {client.removeBucket(bucketName);}/*** 获取文件外链** @param bucketName bucket名称* @param objectName 文件名称* @param expires 过期时间 <=7* @return url*/@SneakyThrowspublic String getObjectURL(String bucketName, String objectName, Integer expires) {return client.presignedGetObject(bucketName, objectName, expires);}/*** 获取文件** @param bucketName bucket名称* @param objectName 文件名称* @return 二进制流*/@SneakyThrowspublic InputStream getObject(String bucketName, String objectName) {return client.getObject(bucketName, objectName);}/*** 上传文件** @param bucketName bucket名称* @param objectName 文件名称* @param stream 文件流* @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#putObject*/public void putObject(String bucketName, String objectName, InputStream stream) throws Exception {client.putObject(bucketName, objectName, stream, stream.available(), "application/octet-stream");}/*** 上传文件** @param bucketName bucket名称* @param objectName 文件名称* @param stream 文件流* @param size 大小* @param contextType 类型* @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#putObject*/public void putObject(String bucketName, String objectName, InputStream stream, long size, String contextType) throws Exception {client.putObject(bucketName, objectName, stream, size, contextType);}/*** 获取文件信息** @param bucketName bucket名称* @param objectName 文件名称* @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#statObject*/public ObjectStat getObjectInfo(String bucketName, String objectName) throws Exception {return client.statObject(bucketName, objectName);}/*** 删除文件** @param bucketName bucket名称* @param objectName 文件名称* @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#removeObject*/public void removeObject(String bucketName, String objectName) throws Exception {client.removeObject(bucketName, objectName);}/*** 上传文件** @param file 文件* @param bucketName 存储桶* @return*/public JSONObject uploadFile(MultipartFile file, String bucketName) throws Exception {JSONObject res = new JSONObject();res.put("code", 0);// 判断上传文件是否为空if (null == file || 0 == file.getSize()) {res.put("msg", "上传文件不能为空");return res;}// 判断存储桶是否存在createBucket(bucketName);// 文件名String originalFilename = file.getOriginalFilename();// 新的文件名String fileName = bucketName + "_" + DateUtils.getYyyymmdd() + originalFilename.substring(originalFilename.lastIndexOf("."));// 开始上传client.putObject(bucketName, fileName, file.getInputStream(), file.getContentType());res.put("code", 1);res.put("msg", minioProp.getEndpoint() + "/" + bucketName + "/" + fileName);return res;}}
文件的下载功能代码,在后续的文章中会贴出
Java Client 指南地址如下:
https://docs.min.io/docs/java-client-quickstart-guide.html
