当前位置:   article > 正文

分布式对象存储服务minio安装和部署_minio server

minio server

一、服务器安装minio

1.进行下载

下载地址:

https://dl.min.io/server/minio/release/linux-amd64/minio

2.新建minio安装目录,执行如下命令

mkdir -p /home/minio/data

二进制文件上传到安装目录后,执行:


chmod +x minio    //给予权限

//注意:以前的老版本minio的配置中,配置用户名和密码时,是这两个参数:

MINIO_ACCESS_KEY 和MINIO_SECRET_KEY

而现在比较新的版本的minio,需要替换成MINIO_ROOT_USER和MINIO_ROOT_PASSWORD

export MINIO_ROOT_USER=fsp-manage

export MINIO_ROOT_PASSWORD=springboot-fsp-manage


./minio server /home/minio/data        //启动

 后台启动,并打印日志

自定义端口方式:自定义启动端口号以及控制台端口号,不设置则控制台会自动配置其他端口号,非常不方便

nohup ./minio server  --address :9000 --console-address :9001 /home/minio/data > /home/minio/data/minio.log &
ps -ef|grep minio
配置开机自启
  1. [Unit]
  2. Description=minio
  3. After=network.target
  4. [Service]
  5. Type=simple
  6. Environment=MINIO_ROOT_USER=minio
  7. Environment=MINIO_ROOT_PASSWORD=minio123456
  8. ExecStart=/usr/local/Mes/env/BINARY/minio server --address :9000 --console-address :9001 /usr/local/Mes/env/minio/data
  9. ExecReload=/bin/kill -HUP $MAINPID
  10. KillMode=process
  11. Restart=always
  12. LimitNOFILE=65536
  13. [Install]
  14. WantedBy=multi-user.target

二、进行访问,并设置桶

        地址:http://127.0.0.1:9000

 

 三、springboot进行实现

1.引入依赖

  1. <!--minio客户端工具-->
  2. <dependency>
  3. <groupId>io.minio</groupId>
  4. <artifactId>minio</artifactId>
  5. <version>8.0.0</version>
  6. </dependency>
  7. <!-- alibaba的fastjson -->
  8. <dependency>
  9. <groupId>com.alibaba</groupId>
  10. <artifactId>fastjson</artifactId>
  11. <version>1.2.51</version>
  12. </dependency>
  13. <!-- thymeleaf模板引擎 -->
  14. <dependency>
  15. <groupId>org.springframework.boot</groupId>
  16. <artifactId>spring-boot-starter-thymeleaf</artifactId>
  17. </dependency>

 2.在 application.yml 文件中加入 MinIO 服务器的相关信息

  1. minio:
  2. endpoint: http://serverip
  3. port: 9002
  4. accessKey: fsp-manage
  5. secretKey: springboot-fsp-manage
  6. bucketName: fsp-dev
  7. secure: false

3.创建实体类

这一步,我们将配置文件中 minio 的配置信息通过注解的方式注入到 MinioProp 这个实体中,方便后面我们使用

  1. package com.xiaomifeng1010.minio.configuration;
  2. import io.minio.MinioClient;
  3. import io.minio.errors.InvalidPortException;
  4. import lombok.Getter;
  5. import lombok.Setter;
  6. import org.springframework.boot.context.properties.ConfigurationProperties;
  7. import org.springframework.context.annotation.Bean;
  8. import org.springframework.context.annotation.Configuration;
  9. import org.springframework.stereotype.Component;
  10. /**
  11. * @author xiaomifeng1010
  12. * @version 1.0
  13. * @date: 2022/5/20 10:30
  14. * @Description minio配置
  15. */
  16. @Configuration
  17. @Component
  18. @ConfigurationProperties(prefix = "minio")
  19. @Getter
  20. @Setter
  21. public class MinioConfig {
  22. private String endpoint;
  23. private int port;
  24. private String accessKey;
  25. private String secretKey;
  26. private Boolean secure;
  27. private String bucketName;
  28. @Bean
  29. public MinioClient getMinioClient() throws InvalidPortException {
  30. MinioClient minioClient = MinioClient.builder().endpoint(endpoint, port, secure)
  31. .credentials(accessKey, secretKey)
  32. .build();
  33. return minioClient;
  34. }
  35. //
  36. // @Bean(name = "multipartResolver")
  37. // public MultipartResolver multipartResolver(){
  38. // CommonsMultipartResolver resolver = new CommonsMultipartResolver();
  39. // resolver.setDefaultEncoding("UTF-8");
  40. // //resolveLazily属性启用是为了推迟文件解析,以在在UploadAction中捕获文件大小异常
  41. // resolver.setResolveLazily(true);
  42. // resolver.setMaxInMemorySize(40960);
  43. // //上传文件大小 50M 50*1024*1024
  44. // resolver.setMaxUploadSize(50*1024*1024);
  45. // return resolver;
  46. // }
  47. }

如何你要配置ip和port在同一个参数中,不分开,或者是直接配置域名(域名映射了ip和port),那么配置的yml 修改如下:

把port注释掉,同时配置类也修改一下就可以了:

5、上传工具类

  1. package com.hanclouds.wx.mes.basic.common.utils;
  2. import io.minio.*;
  3. import io.minio.errors.*;
  4. import io.minio.http.Method;
  5. import io.minio.messages.Bucket;
  6. import io.minio.messages.DeleteObject;
  7. import io.minio.messages.Item;
  8. import lombok.SneakyThrows;
  9. import org.apache.commons.io.IOUtils;
  10. import org.apache.commons.lang3.StringUtils;
  11. import org.springframework.beans.factory.annotation.Autowired;
  12. import org.springframework.stereotype.Component;
  13. import org.springframework.web.multipart.MultipartFile;
  14. import javax.servlet.http.HttpServletResponse;
  15. import java.io.IOException;
  16. import java.io.InputStream;
  17. import java.net.URLEncoder;
  18. import java.security.InvalidKeyException;
  19. import java.security.NoSuchAlgorithmException;
  20. import java.util.ArrayList;
  21. import java.util.Arrays;
  22. import java.util.List;
  23. import java.util.Optional;
  24. @Component
  25. public class MinioUtils {
  26. @Autowired
  27. private MinioClient minioClient;
  28. /**
  29. * 判断桶是否存在
  30. */
  31. @SneakyThrows(Exception.class)
  32. public boolean bucketExists(String bucketName) {
  33. return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
  34. }
  35. /**
  36. * 创建桶
  37. *
  38. * @param bucketName 获取全部的桶 minioClient.listBuckets();
  39. */
  40. @SneakyThrows(Exception.class)
  41. public void createBucket(String bucketName) {
  42. if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
  43. minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
  44. }
  45. }
  46. /**
  47. * 根据bucketName获取信息
  48. *
  49. * @param bucketName bucket名称
  50. */
  51. @SneakyThrows(Exception.class)
  52. public Optional<Bucket> getBucket(String bucketName) {
  53. return minioClient.listBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();
  54. }
  55. /**
  56. * 根据bucketName删除信息
  57. *
  58. * @param bucketName bucket名称
  59. */
  60. @SneakyThrows(Exception.class)
  61. public void removeBucket(String bucketName) {
  62. minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
  63. }
  64. /**
  65. * 移除指定桶下边的指定文件
  66. *
  67. * @param bucketName
  68. * @param objectName
  69. */
  70. public void removeFile(String bucketName, String objectName) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
  71. List<DeleteObject> deleteObjects =new ArrayList<>();
  72. deleteObjects.add(new DeleteObject(objectName));
  73. minioClient.removeObject(RemoveObjectArgs.builder()
  74. .bucket(bucketName)
  75. .object(objectName)
  76. .build());
  77. }
  78. /**
  79. * 获取文件流
  80. *
  81. * @param bucketName bucket名称
  82. * @param objectName 文件名称
  83. * @return 二进制流
  84. */
  85. @SneakyThrows(Exception.class)
  86. public InputStream getObject(String bucketName, String objectName) {
  87. return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());
  88. }
  89. /**
  90. * 上传本地文件
  91. *
  92. * @param bucketName 存储桶
  93. * @param objectName 对象名称
  94. * @param fileName 本地文件路径
  95. */
  96. public ObjectWriteResponse putObject(String bucketName, String objectName, String fileName) {
  97. ObjectWriteResponse o = null;
  98. try {
  99. o = minioClient.uploadObject(UploadObjectArgs.builder().bucket(bucketName).object(objectName).filename(fileName).build());
  100. } catch (Exception e) {
  101. e.printStackTrace();
  102. }
  103. return o;
  104. }
  105. /**
  106. * 通过流上传文件
  107. *
  108. * @param bucketName 存储桶
  109. * @param objectName 文件对象
  110. * @param inputStream 文件流
  111. */
  112. @SneakyThrows(Exception.class)
  113. public ObjectWriteResponse putObject(String bucketName, String objectName, InputStream inputStream) {
  114. if (!bucketExists(bucketName)) {
  115. createBucket(bucketName);
  116. }
  117. return minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(inputStream, inputStream.available(), -1).build());
  118. }
  119. /**
  120. * 單個文件上傳遞
  121. *
  122. * @param bucketName
  123. * @param multipartFile
  124. * @return
  125. */
  126. @SneakyThrows(Exception.class)
  127. public String uploadFileSingle(String bucketName, String fileName, MultipartFile multipartFile) {
  128. if (!bucketExists(bucketName)) {
  129. createBucket(bucketName);
  130. }
  131. InputStream in = null;
  132. try {
  133. in = multipartFile.getInputStream();
  134. minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(fileName).stream(in, in.available(), -1).contentType("application/octet-stream").build());
  135. } catch (Exception e) {
  136. e.printStackTrace();
  137. } finally {
  138. if (in != null) {
  139. try {
  140. in.close();
  141. } catch (IOException e) {
  142. e.printStackTrace();
  143. }
  144. }
  145. }
  146. return getUploadObjectUrl(bucketName, fileName, 7 * 24 * 60 * 60);
  147. }
  148. /**
  149. * description: 上传文件
  150. *
  151. * @param multipartFile
  152. * @return: java.lang.String
  153. */
  154. public List<String> uploadFileBatch(String bucketName, MultipartFile[] multipartFile) {
  155. if (!bucketExists(bucketName)) {
  156. createBucket(bucketName);
  157. }
  158. List<String> names = new ArrayList<>();
  159. for (MultipartFile file : multipartFile) {
  160. try {
  161. String fileName = file.getOriginalFilename();
  162. uploadFileSingle(bucketName, fileName, file);
  163. names.add(fileName);
  164. } catch (Exception e) {
  165. e.printStackTrace();
  166. }
  167. }
  168. return names;
  169. }
  170. /**
  171. * 获取文件外链
  172. *
  173. * @param bucketName bucket名称
  174. * @param objectName 文件名称
  175. * @param expires 过期时间 <=7 秒级
  176. * @return url
  177. */
  178. @SneakyThrows(Exception.class)
  179. public String getUploadObjectUrl(String bucketName, String objectName, Integer expires) {
  180. String presignedObjectUrl = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.PUT).bucket(bucketName).object(objectName).expiry(expires).build());
  181. //分割问号前边的部分获取到预览地址
  182. String[] split = presignedObjectUrl.split("\\?");
  183. String s1 = split[0];
  184. return s1;
  185. }
  186. /**
  187. * 下载文件
  188. * bucketName:桶名
  189. *
  190. * @param fileName: 文件名
  191. */
  192. @SneakyThrows(Exception.class)
  193. public void download(String bucketName, String fileName, HttpServletResponse response) {
  194. // 获取对象的元数据
  195. StatObjectResponse stat = minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(fileName).build());
  196. response.setContentType(stat.contentType());
  197. response.setCharacterEncoding("UTF-8");
  198. response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
  199. InputStream is = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(fileName).build());
  200. IOUtils.copy(is, response.getOutputStream());
  201. is.close();
  202. }
  203. /**
  204. * 将minio中的文件保存到本地
  205. *
  206. * @param bucketName 桶名称
  207. * @param fileName 文件名称
  208. * @param filePath 文件保存路径
  209. * @throws IOException
  210. * @throws NoSuchAlgorithmException
  211. * @throws InvalidKeyException
  212. */
  213. @SneakyThrows(MinioException.class)
  214. public void trasitionFileTo(String bucketName, String fileName, String filePath) throws IOException, NoSuchAlgorithmException, InvalidKeyException {
  215. minioClient.downloadObject(DownloadObjectArgs.builder()
  216. .bucket(bucketName)
  217. .object(fileName)
  218. .filename(filePath)
  219. .build());
  220. }
  221. /**
  222. * 将一个桶下边的文件复制到该桶的一个文件夹下
  223. *
  224. * @param bucketName
  225. * @param fileName
  226. * @param destinationObjectName
  227. */
  228. @SneakyThrows(Exception.class)
  229. public void copyObject(String bucketName, String fileName, String destinationObjectName) {
  230. minioClient.copyObject(
  231. CopyObjectArgs.builder()
  232. .source(CopySource.builder()
  233. .bucket(bucketName)
  234. .object(fileName).build())
  235. .bucket(bucketName)
  236. .object(destinationObjectName)
  237. .build()
  238. );
  239. }
  240. }

6.controller接口

  1. package com.dcboot.module.minio.controller;
  2. import cn.hutool.core.io.FileUtil;
  3. import com.dcboot.base.util.ApiResult;
  4. import com.dcboot.module.minio.configuration.MinioConfig;
  5. import com.dcboot.module.minio.dto.response.MinioResponseDTO;
  6. import com.dcboot.module.minio.entity.MinioFile;
  7. import com.dcboot.module.util.MinioClientUtils;
  8. import io.swagger.annotations.Api;
  9. import io.swagger.annotations.ApiImplicitParam;
  10. import io.swagger.annotations.ApiOperation;
  11. import lombok.AllArgsConstructor;
  12. import lombok.extern.slf4j.Slf4j;
  13. import org.apache.commons.collections4.CollectionUtils;
  14. import org.apache.commons.lang3.RandomStringUtils;
  15. import org.apache.commons.lang3.math.NumberUtils;
  16. import org.springframework.stereotype.Controller;
  17. import org.springframework.web.bind.annotation.*;
  18. import org.springframework.web.multipart.MultipartFile;
  19. import java.io.FileInputStream;
  20. import java.time.Instant;
  21. import java.util.ArrayList;
  22. import java.util.List;
  23. /**
  24. * @author xiaomifeng1010
  25. * @version 1.0
  26. * @date: 2022/5/21 10:33
  27. * @Description minio 文件处理(上传,下载,获取文件地址等)
  28. */
  29. @Controller
  30. @RequestMapping("/fileHandle")
  31. @Slf4j
  32. @AllArgsConstructor
  33. @Api(tags = "文件处理模块")
  34. public class FileHandleController {
  35. private MinioClientUtils minioClientUtils;
  36. private MinioConfig minioConfig;
  37. @PostMapping(value = {"/admin/uploadFile","/web/uploadFile"})
  38. @ResponseBody
  39. @ApiOperation(value = "上传文件,支持批量上传")
  40. @ApiImplicitParam(name = "files",value = "文件对象",dataType = "File")
  41. public ApiResult uploadFile(@RequestParam("files") List<MultipartFile> files) {
  42. log.info(files.toString());
  43. if (CollectionUtils.isEmpty(files)){
  44. return ApiResult.error("未选择文件!");
  45. }
  46. List<MinioResponseDTO> MinioResponseDTOList=new ArrayList<>();
  47. for (MultipartFile file : files) {
  48. String originalFilename = file.getOriginalFilename();
  49. // 获取文件拓展名
  50. String extName = FileUtil.extName(originalFilename);
  51. log.info("文件拓展名:"+extName);
  52. // 生成新的文件名,存入到minio
  53. long millSeconds = Instant.now().toEpochMilli();
  54. String minioFileName=millSeconds+ RandomStringUtils.randomNumeric(12)+"."+extName;
  55. String contentType = file.getContentType();
  56. log.info("文件mime:{}",contentType);
  57. // 返回文件大小,单位字节
  58. long size = file.getSize();
  59. log.info("文件大小:"+size);
  60. try {
  61. String bucketName = minioConfig.getBucketName();
  62. minioClientUtils.putObject(bucketName,file,minioFileName);
  63. String fileUrl = minioClientUtils.getObjectUrl(bucketName, minioFileName);
  64. MinioFile minioFile = new MinioFile();
  65. minioFile.setOriginalFileName(originalFilename);
  66. minioFile.setFileExtName(extName);
  67. minioFile.setFileName(minioFileName);
  68. minioFile.setFileSize(size);
  69. minioFile.setMime(contentType);
  70. minioFile.setIsDelete(NumberUtils.INTEGER_ZERO);
  71. minioFile.setFileUrl(fileUrl);
  72. boolean insert = minioFile.insert();
  73. if (insert) {
  74. MinioResponseDTO minioResponseDTO = new MinioResponseDTO();
  75. minioResponseDTO.setFileId(minioFile.getId());
  76. minioResponseDTO.setOriginalFileName(originalFilename);
  77. minioResponseDTO.setFileUrl(fileUrl);
  78. MinioResponseDTOList.add(minioResponseDTO);
  79. }
  80. } catch (Exception e) {
  81. log.error("上传文件出错:{}",e);
  82. return ApiResult.error("上传文件出错");
  83. }
  84. }
  85. return ApiResult.success(MinioResponseDTOList);
  86. }
  87. /**
  88. * 仅仅用于测试,是否可以正常上传文件
  89. * @return
  90. * @throws Exception
  91. */
  92. @GetMapping("/test")
  93. @ApiOperation(value = "测试minio文件上传")
  94. public ApiResult testPutObject() throws Exception {
  95. FileInputStream fileInputStream = new FileInputStream("C:\\Users\\MSI\\Desktop\\新建文本文档.txt");
  96. boolean bs = minioClientUtils.putObject("fsp-dev", "新建文本文档.txt", fileInputStream, "image/jpg");
  97. log.info("上传成功?"+bs);
  98. return ApiResult.success("上传成功");
  99. }
  100. }

删除文件:

  1. //文件删除
  2. @DeleteMapping
  3. public String delete(String name) {
  4. try {
  5. MinioClient minioClient = new MinioClient(ENDPOINT, ACCESSKEY, SECRETKEY);
  6. minioClient.removeObject(BUCKETNAME, name);
  7. } catch (Exception e) {
  8. return "删除失败"+e.getMessage();
  9. }
  10. return "删除成功";
  11. }

7.如何获取多级目录文件,例如在桶下有一个file文件夹,文件夹下边有一个aa.txt

  1. String bucketName = "log";
  2. String objectName = "file/aa.txt";
  3. InputStream stream = minioClient.getObject(bucketName,objectName);

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/554352
推荐阅读