一、创建springboot,引入minio依赖:

    1. <dependency>
    2. <groupId>io.minio</groupId>
    3. <artifactId>minio</artifactId>
    4. <version>7.0.2</version>
    5. </dependency>

    其它的依赖看自己需求引入

    二、创建包结构
    1.png
    三、修改配置文件

    1. min.io.endpoint = http://xx.xx.xx.xx:9000
    2. min.io.accessKey = username
    3. min.io.secretKey = password

    四、编写配置类

    1. package com.zym.minio.config;
    2. import io.minio.MinioClient;
    3. import io.minio.errors.InvalidEndpointException;
    4. import io.minio.errors.InvalidPortException;
    5. import lombok.Data;
    6. import org.springframework.boot.context.properties.ConfigurationProperties;
    7. import org.springframework.context.annotation.Bean;
    8. import org.springframework.stereotype.Component;
    9. @Data
    10. @Component
    11. @ConfigurationProperties(prefix = "min.io")
    12. public class MinIoConfig {
    13. private String endpoint;
    14. private String accessKey;
    15. private String secretKey;
    16. @Bean
    17. public MinioClient getMinioClient() throws InvalidPortException, InvalidEndpointException {
    18. MinioClient client = new MinioClient(endpoint,accessKey,secretKey);
    19. return client;
    20. }
    21. }

    五、编写测试方法

    controller:

    1. package com.zym.minio.controller;
    2. import com.zym.minio.common.result.Result;
    3. import com.zym.minio.common.result.ResultUtil;
    4. import com.zym.minio.config.MinIoConfig;
    5. import com.zym.minio.service.MinioService;
    6. import io.swagger.annotations.Api;
    7. import io.swagger.annotations.ApiOperation;
    8. import org.apache.commons.lang3.StringUtils;
    9. import org.springframework.beans.factory.annotation.Autowired;
    10. import org.springframework.web.bind.annotation.PostMapping;
    11. import org.springframework.web.bind.annotation.RequestMapping;
    12. import org.springframework.web.bind.annotation.RestController;
    13. import org.springframework.web.multipart.MultipartFile;
    14. import javax.servlet.http.HttpServletResponse;
    15. import java.text.SimpleDateFormat;
    16. import java.util.Date;
    17. import java.util.UUID;
    18. @RequestMapping("/minio")
    19. @RestController
    20. @Api(tags = "文件操作接口")
    21. public class MinioController {
    22. @Autowired
    23. private MinioService minioService;
    24. @ApiOperation(value = "使用minio文件上传")
    25. @PostMapping("/uploadFile")
    26. public Result uploadFile(MultipartFile file, String bucketName) {
    27. try {
    28. if (StringUtils.isBlank(bucketName)){
    29. return ResultUtil.sendErrorMessage("桶名称不能为空");
    30. }
    31. if (!minioService.bucketExists(bucketName)) {
    32. minioService.makeBucket(bucketName);
    33. }
    34. String fileName = file.getOriginalFilename();
    35. String objectName = new SimpleDateFormat("yyyy-MM-dd/").format(new Date()) + UUID.randomUUID().toString().replaceAll("-", "")
    36. + fileName.substring(fileName.lastIndexOf("."));
    37. minioService.putObject(bucketName, file, objectName);
    38. System.out.println("文件格式为:"+file.getContentType());
    39. System.out.println("文件原名称为:"+fileName);
    40. System.out.println("文件存储的桶为:"+bucketName);
    41. System.out.println("文件对象路径为:"+objectName);
    42. return ResultUtil.success(minioService.getObjectUrl(bucketName, objectName));
    43. } catch (Exception e) {
    44. e.printStackTrace();
    45. return ResultUtil.sendErrorMessage("上传失败");
    46. }
    47. }
    48. @ApiOperation(value = "使用minio文件删除")
    49. @PostMapping("/deleteFile")
    50. public Result deleteFile(String bucketName,String filePath) throws Exception {
    51. if (!minioService.bucketExists(bucketName)){
    52. throw new Exception("不存在该桶");
    53. }
    54. boolean flag = minioService.removeObject(bucketName, filePath);
    55. if (flag){
    56. return ResultUtil.sendSuccessMessage("删除成功");
    57. }else{
    58. return ResultUtil.sendErrorMessage("删除失败");
    59. }
    60. }
    61. @ApiOperation(value = "使用minio文件下载")
    62. @PostMapping("/downloadFile")
    63. public Result downloadFile(String bucketName, String filePath, String originalName, HttpServletResponse response) throws Exception {
    64. if (!minioService.bucketExists(bucketName)){
    65. throw new Exception("不存在该桶");
    66. }
    67. minioService.downloadFile(bucketName, filePath, originalName, response);
    68. return ResultUtil.sendSuccessMessage("下载成功");
    69. }
    70. }

    service:

    1. package com.zym.minio.service;
    2. import org.springframework.web.multipart.MultipartFile;
    3. import javax.servlet.http.HttpServletResponse;
    4. import java.io.InputStream;
    5. public interface MinioService {
    6. /**
    7. * 判断 bucket是否存在
    8. *
    9. * @param bucketName
    10. * @return
    11. */
    12. boolean bucketExists(String bucketName);
    13. /**
    14. * 创建 bucket
    15. *
    16. * @param bucketName
    17. */
    18. void makeBucket(String bucketName);
    19. /**
    20. * 文件上传
    21. *
    22. * @param bucketName
    23. * @param objectName
    24. * @param filename
    25. */
    26. void putObject(String bucketName, String objectName, String filename);
    27. /**
    28. * 文件上传
    29. *
    30. * @param bucketName
    31. * @param objectName
    32. * @param stream
    33. */
    34. void putObject(String bucketName, String objectName, InputStream stream, String contentType);
    35. /**
    36. * 文件上传
    37. *
    38. * @param bucketName
    39. * @param multipartFile
    40. */
    41. void putObject(String bucketName, MultipartFile multipartFile, String filename);
    42. /**
    43. * 删除文件
    44. * @param bucketName
    45. * @param filePath
    46. */
    47. boolean removeObject(String bucketName,String filePath);
    48. /**
    49. * 下载文件
    50. *
    51. * @param filePath
    52. * @param originalName
    53. * @param response
    54. */
    55. void downloadFile(String bucketName, String filePath, String originalName, HttpServletResponse response);
    56. /**
    57. * 获取文件路径
    58. * @param bucketName
    59. * @param objectName
    60. * @return
    61. */
    62. String getObjectUrl(String bucketName,String objectName);
    63. /**
    64. * 以流形式获取文件
    65. * @param bucketName
    66. * @param objectName
    67. * @param offset
    68. * @return
    69. */
    70. InputStream getObject(String bucketName,String objectName,long offset);
    71. }

    impl:

    1. package com.zym.minio.service.impl;
    2. import com.zym.minio.service.MinioService;
    3. import com.zym.minio.util.MinIoUtils;
    4. import org.springframework.beans.factory.annotation.Autowired;
    5. import org.springframework.stereotype.Service;
    6. import org.springframework.web.multipart.MultipartFile;
    7. import javax.servlet.http.HttpServletResponse;
    8. import java.io.InputStream;
    9. @Service
    10. public class MinioServiceImpl implements MinioService {
    11. @Autowired
    12. private MinIoUtils minIoUtils;
    13. /**
    14. * 判断 bucket是否存在
    15. *
    16. * @param bucketName
    17. * @return
    18. */
    19. @Override
    20. public boolean bucketExists(String bucketName) {
    21. return minIoUtils.bucketExists(bucketName);
    22. }
    23. /**
    24. * 创建 bucket
    25. *
    26. * @param bucketName
    27. */
    28. @Override
    29. public void makeBucket(String bucketName) {
    30. minIoUtils.makeBucket(bucketName);
    31. }
    32. /**
    33. * 文件上传
    34. *
    35. * @param bucketName
    36. * @param objectName
    37. * @param filename
    38. */
    39. @Override
    40. public void putObject(String bucketName, String objectName, String filename) {
    41. minIoUtils.putObject(bucketName, objectName, filename);
    42. }
    43. @Override
    44. public void putObject(String bucketName, String objectName, InputStream stream, String contentType) {
    45. minIoUtils.putObject(bucketName, objectName, stream, contentType);
    46. }
    47. /**
    48. * 文件上传
    49. *
    50. * @param bucketName
    51. * @param multipartFile
    52. */
    53. @Override
    54. public void putObject(String bucketName, MultipartFile multipartFile, String filename) {
    55. minIoUtils.putObject(bucketName, multipartFile, filename);
    56. }
    57. /**
    58. * 删除文件
    59. * @param bucketName
    60. * @param filePath
    61. */
    62. @Override
    63. public boolean removeObject(String bucketName,String filePath) {
    64. return minIoUtils.removeObject(bucketName,filePath);
    65. }
    66. /**
    67. * 下载文件
    68. *
    69. * @param filePath
    70. * @param originalName
    71. * @param response
    72. */
    73. @Override
    74. public void downloadFile(String bucketName, String filePath, String originalName, HttpServletResponse response) {
    75. minIoUtils.downloadFile(bucketName,filePath, originalName, response);
    76. }
    77. /**
    78. * 获取文件路径
    79. * @param bucketName
    80. * @param objectName
    81. * @return
    82. */
    83. @Override
    84. public String getObjectUrl(String bucketName,String objectName) {
    85. return minIoUtils.getObjectUrl(bucketName,objectName);
    86. }
    87. }

    minioutils:

    1. package com.zym.minio.util;
    2. import io.minio.MinioClient;
    3. import io.minio.ObjectStat;
    4. import io.minio.PutObjectOptions;
    5. import io.minio.Result;
    6. import io.minio.errors.ErrorResponseException;
    7. import io.minio.errors.InvalidExpiresRangeException;
    8. import io.minio.messages.Bucket;
    9. import io.minio.messages.DeleteError;
    10. import io.minio.messages.Item;
    11. import lombok.SneakyThrows;
    12. import org.apache.commons.lang3.StringUtils;
    13. import org.springframework.beans.factory.annotation.Autowired;
    14. import org.springframework.stereotype.Component;
    15. import org.springframework.web.multipart.MultipartFile;
    16. import javax.servlet.ServletOutputStream;
    17. import javax.servlet.http.HttpServletResponse;
    18. import java.io.InputStream;
    19. import java.net.URLEncoder;
    20. import java.nio.charset.StandardCharsets;
    21. import java.util.ArrayList;
    22. import java.util.List;
    23. @Component
    24. public class MinIoUtils {
    25. @Autowired
    26. private MinioClient minioClient;
    27. private static final int DEFAULT_EXPIRY_TIME = 7 * 24 * 3600;
    28. /**
    29. * 检查存储桶是否存在
    30. *
    31. * @param bucketName 存储桶名称
    32. * @return
    33. */
    34. @SneakyThrows
    35. public boolean bucketExists(String bucketName) {
    36. boolean flag = false;
    37. flag = minioClient.bucketExists(bucketName);
    38. if (flag) {
    39. return true;
    40. }
    41. return false;
    42. }
    43. /**
    44. * 创建存储桶
    45. *
    46. * @param bucketName 存储桶名称
    47. */
    48. @SneakyThrows
    49. public boolean makeBucket(String bucketName) {
    50. boolean flag = bucketExists(bucketName);
    51. if (!flag) {
    52. minioClient.makeBucket(bucketName);
    53. return true;
    54. } else {
    55. return false;
    56. }
    57. }
    58. /**
    59. * 列出所有存储桶名称
    60. *
    61. * @return
    62. */
    63. @SneakyThrows
    64. public List<String> listBucketNames() {
    65. List<Bucket> bucketList = listBuckets();
    66. List<String> bucketListName = new ArrayList<>();
    67. for (Bucket bucket : bucketList) {
    68. bucketListName.add(bucket.name());
    69. }
    70. return bucketListName;
    71. }
    72. /**
    73. * 列出所有存储桶
    74. *
    75. * @return
    76. */
    77. @SneakyThrows
    78. public List<Bucket> listBuckets() {
    79. return minioClient.listBuckets();
    80. }
    81. /**
    82. * 删除存储桶
    83. *
    84. * @param bucketName 存储桶名称
    85. * @return
    86. */
    87. @SneakyThrows
    88. public boolean removeBucket(String bucketName) {
    89. boolean flag = bucketExists(bucketName);
    90. if (flag) {
    91. Iterable<Result<Item>> myObjects = listObjects(bucketName);
    92. for (Result<Item> result : myObjects) {
    93. Item item = result.get();
    94. // 有对象文件,则删除失败
    95. if (item.size() > 0) {
    96. return false;
    97. }
    98. }
    99. // 删除存储桶,注意,只有存储桶为空时才能删除成功。
    100. minioClient.removeBucket(bucketName);
    101. flag = bucketExists(bucketName);
    102. if (!flag) {
    103. return true;
    104. }
    105. }
    106. return false;
    107. }
    108. /**
    109. * 列出存储桶中的所有对象名称
    110. *
    111. * @param bucketName 存储桶名称
    112. * @return
    113. */
    114. @SneakyThrows
    115. public List<String> listObjectNames(String bucketName) {
    116. List<String> listObjectNames = new ArrayList<>();
    117. boolean flag = bucketExists(bucketName);
    118. if (flag) {
    119. Iterable<Result<Item>> myObjects = listObjects(bucketName);
    120. for (Result<Item> result : myObjects) {
    121. Item item = result.get();
    122. listObjectNames.add(item.objectName());
    123. }
    124. }
    125. return listObjectNames;
    126. }
    127. /**
    128. * 列出存储桶中的所有对象
    129. *
    130. * @param bucketName 存储桶名称
    131. * @return
    132. */
    133. @SneakyThrows
    134. public Iterable<Result<Item>> listObjects(String bucketName) {
    135. boolean flag = bucketExists(bucketName);
    136. if (flag) {
    137. return minioClient.listObjects(bucketName);
    138. }
    139. return null;
    140. }
    141. /**
    142. * 通过文件上传到对象
    143. *
    144. * @param bucketName 存储桶名称
    145. * @param objectName 存储桶里的对象名称
    146. * @param fileName File name
    147. * @return
    148. */
    149. @SneakyThrows
    150. public boolean putObject(String bucketName, String objectName, String fileName) {
    151. boolean flag = bucketExists(bucketName);
    152. if (flag) {
    153. minioClient.putObject(bucketName, objectName, fileName, null);
    154. ObjectStat statObject = statObject(bucketName, objectName);
    155. if (statObject != null && statObject.length() > 0) {
    156. return true;
    157. }
    158. }
    159. return false;
    160. }
    161. /**
    162. * 文件上传
    163. *
    164. * @param bucketName
    165. * @param multipartFile
    166. */
    167. @SneakyThrows
    168. public void putObject(String bucketName, MultipartFile multipartFile, String filename) {
    169. PutObjectOptions putObjectOptions = new PutObjectOptions(multipartFile.getSize(), PutObjectOptions.MIN_MULTIPART_SIZE);
    170. putObjectOptions.setContentType(multipartFile.getContentType());
    171. minioClient.putObject(bucketName, filename, multipartFile.getInputStream(), putObjectOptions);
    172. }
    173. /**
    174. * 通过InputStream上传对象
    175. *
    176. * @param bucketName 存储桶名称
    177. * @param objectName 存储桶里的对象名称
    178. * @param stream 要上传的流
    179. * @param stream 要上传的文件类型 MimeTypeUtils.IMAGE_JPEG_VALUE
    180. * @return
    181. */
    182. @SneakyThrows
    183. public boolean putObject(String bucketName, String objectName, InputStream stream,String contentType) {
    184. boolean flag = bucketExists(bucketName);
    185. if (flag) {
    186. PutObjectOptions putObjectOptions = new PutObjectOptions(stream.available(), -1);
    187. /**
    188. * 开启公共类功能设置setContentType
    189. */
    190. if (StringUtils.isNotBlank(contentType)) {
    191. putObjectOptions.setContentType(contentType);
    192. }
    193. minioClient.putObject(bucketName, objectName, stream, putObjectOptions);
    194. ObjectStat statObject = statObject(bucketName, objectName);
    195. if (statObject != null && statObject.length() > 0) {
    196. return true;
    197. }
    198. }
    199. return false;
    200. }
    201. /**
    202. * 以流的形式获取一个文件对象
    203. *
    204. * @param bucketName 存储桶名称
    205. * @param objectName 存储桶里的对象名称
    206. * @return
    207. */
    208. @SneakyThrows
    209. public InputStream getObject(String bucketName, String objectName) {
    210. boolean flag = bucketExists(bucketName);
    211. if (flag) {
    212. ObjectStat statObject = statObject(bucketName, objectName);
    213. if (statObject != null && statObject.length() > 0) {
    214. InputStream stream = minioClient.getObject(bucketName, objectName);
    215. return stream;
    216. }
    217. }
    218. return null;
    219. }
    220. /**
    221. * 以流的形式获取一个文件对象(断点下载)
    222. *
    223. * @param bucketName 存储桶名称
    224. * @param objectName 存储桶里的对象名称
    225. * @param offset 起始字节的位置
    226. * @param length 要读取的长度 (可选,如果无值则代表读到文件结尾)
    227. * @return
    228. */
    229. @SneakyThrows
    230. public InputStream getObject(String bucketName, String objectName, long offset, Long length) {
    231. boolean flag = bucketExists(bucketName);
    232. if (flag) {
    233. ObjectStat statObject = statObject(bucketName, objectName);
    234. if (statObject != null && statObject.length() > 0) {
    235. InputStream stream = minioClient.getObject(bucketName, objectName, offset, length);
    236. return stream;
    237. }
    238. }
    239. return null;
    240. }
    241. /**
    242. * 下载并将文件保存到本地
    243. *
    244. * @param bucketName 存储桶名称
    245. * @param objectName 存储桶里的对象名称
    246. * @param fileName File name
    247. * @return
    248. */
    249. @SneakyThrows
    250. public boolean getObject(String bucketName, String objectName, String fileName) {
    251. boolean flag = bucketExists(bucketName);
    252. if (flag) {
    253. ObjectStat statObject = statObject(bucketName, objectName);
    254. if (statObject != null && statObject.length() > 0) {
    255. minioClient.getObject(bucketName, objectName, fileName);
    256. return true;
    257. }
    258. }
    259. return false;
    260. }
    261. /**
    262. * 删除一个对象
    263. *
    264. * @param bucketName 存储桶名称
    265. * @param objectName 存储桶里的对象名称
    266. */
    267. @SneakyThrows
    268. public boolean removeObject(String bucketName, String objectName) {
    269. boolean flag = bucketExists(bucketName);
    270. if (flag) {
    271. minioClient.removeObject(bucketName, objectName);
    272. return true;
    273. }
    274. return false;
    275. }
    276. /**
    277. * 删除指定桶的多个文件对象,返回删除错误的对象列表,全部删除成功,返回空列表
    278. *
    279. * @param bucketName 存储桶名称
    280. * @param objectNames 含有要删除的多个object名称的迭代器对象
    281. * @return
    282. */
    283. @SneakyThrows
    284. public List<String> removeObject(String bucketName, List<String> objectNames) {
    285. List<String> deleteErrorNames = new ArrayList<>();
    286. boolean flag = bucketExists(bucketName);
    287. if (flag) {
    288. Iterable<Result<DeleteError>> results = minioClient.removeObjects(bucketName, objectNames);
    289. for (Result<DeleteError> result : results) {
    290. DeleteError error = result.get();
    291. deleteErrorNames.add(error.objectName());
    292. }
    293. }
    294. return deleteErrorNames;
    295. }
    296. /**
    297. * 生成一个给HTTP GET请求用的presigned URL。
    298. * 浏览器/移动端的客户端可以用这个URL进行下载,即使其所在的存储桶是私有的。这个presigned URL可以设置一个失效时间,默认值是7天。
    299. *
    300. * @param bucketName 存储桶名称
    301. * @param objectName 存储桶里的对象名称
    302. * @param expires 失效时间(以秒为单位),默认是7天,不得大于七天
    303. * @return
    304. */
    305. @SneakyThrows
    306. public String presignedGetObject(String bucketName, String objectName, Integer expires) {
    307. boolean flag = bucketExists(bucketName);
    308. String url = "";
    309. if (flag) {
    310. if (expires < 1 || expires > DEFAULT_EXPIRY_TIME) {
    311. throw new InvalidExpiresRangeException(expires,
    312. "expires must be in range of 1 to " + DEFAULT_EXPIRY_TIME);
    313. }
    314. url = minioClient.presignedGetObject(bucketName, objectName, expires);
    315. }
    316. return url;
    317. }
    318. /**
    319. * 生成一个给HTTP PUT请求用的presigned URL。
    320. * 浏览器/移动端的客户端可以用这个URL进行上传,即使其所在的存储桶是私有的。这个presigned URL可以设置一个失效时间,默认值是7天。
    321. *
    322. * @param bucketName 存储桶名称
    323. * @param objectName 存储桶里的对象名称
    324. * @param expires 失效时间(以秒为单位),默认是7天,不得大于七天
    325. * @return
    326. */
    327. @SneakyThrows
    328. public String presignedPutObject(String bucketName, String objectName, Integer expires) {
    329. boolean flag = bucketExists(bucketName);
    330. String url = "";
    331. if (flag) {
    332. if (expires < 1 || expires > DEFAULT_EXPIRY_TIME) {
    333. throw new InvalidExpiresRangeException(expires,
    334. "expires must be in range of 1 to " + DEFAULT_EXPIRY_TIME);
    335. }
    336. url = minioClient.presignedPutObject(bucketName, objectName, expires);
    337. }
    338. return url;
    339. }
    340. /**
    341. * 获取对象的元数据
    342. *
    343. * @param bucketName 存储桶名称
    344. * @param objectName 存储桶里的对象名称
    345. * @return
    346. */
    347. @SneakyThrows
    348. public ObjectStat statObject(String bucketName, String objectName) {
    349. boolean flag = bucketExists(bucketName);
    350. if (flag) {
    351. ObjectStat statObject = minioClient.statObject(bucketName, objectName);
    352. return statObject;
    353. }
    354. return null;
    355. }
    356. /**
    357. * 文件访问路径
    358. *
    359. * @param bucketName 存储桶名称
    360. * @param objectName 存储桶里的对象名称
    361. * @return
    362. */
    363. @SneakyThrows
    364. public String getObjectUrl(String bucketName, String objectName) {
    365. boolean flag = bucketExists(bucketName);
    366. String url = "";
    367. if (flag) {
    368. url = minioClient.getObjectUrl(bucketName, objectName);
    369. }
    370. return url;
    371. }
    372. public void downloadFile(String bucketName, String filePath, String originalName, HttpServletResponse response) {
    373. try {
    374. InputStream file = minioClient.getObject(bucketName, filePath);
    375. if (StringUtils.isNotEmpty(originalName)) {
    376. response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(originalName,"UTF-8"));
    377. }else{
    378. String filename = new String(filePath.getBytes("ISO8859-1"), StandardCharsets.UTF_8);
    379. response.setHeader("Content-Disposition", "attachment;filename=" + filename);
    380. }
    381. ServletOutputStream servletOutputStream = response.getOutputStream();
    382. int len;
    383. byte[] buffer = new byte[1024];
    384. while ((len = file.read(buffer)) > 0) {
    385. servletOutputStream.write(buffer, 0, len);
    386. }
    387. servletOutputStream.flush();
    388. file.close();
    389. servletOutputStream.close();
    390. } catch (ErrorResponseException e) {
    391. e.printStackTrace();
    392. } catch (Exception e) {
    393. e.printStackTrace();
    394. }
    395. }
    396. }

    源码地址:https://gitee.com/zym213/springboot-minio.git
    下一篇说一下如何用nginx做minio的负载均衡