当前位置: 首页 > news >正文

spring boot学习第二十篇:使用minio上传下载文件获取文件路径

先安装好minio,参考:window10安装minio-CSDN博客

1、pom.xml文件添加依赖:

<!-- 操作minio的java客户端--><dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.2.1</version></dependency><!--        jwt鉴权相应依赖--><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.3</version></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-jackson</artifactId><version>0.11.2</version></dependency>

2、配置文件追加配置

  #minio配置minio:access-key: Irr1hKVWRacP91HAqJ60secret-key: PadLzC18woHTxbbuRRGA3oUOiwNvvvdrRa0mZF9Ourl: http://localhost:9090  #访问地址bucket-name: hmblogs-bucket

3、注册配置的bean

package com.hmblogs.backend.util;import io.minio.MinioClient;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Data
@Configuration
@ConfigurationProperties(prefix = "spring.minio")
public class MinioConfig {private String accessKey;private String secretKey;private String url;private String bucketName;@Beanpublic MinioClient minioClient(){return MinioClient.builder().endpoint(url).credentials(accessKey,secretKey).build();}
}

4、工具类

package com.hmblogs.backend.util;import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;
import lombok.SneakyThrows;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;/*** @Description Minio工具类*/@Component
public class MinioUtils {@Autowiredprivate MinioClient minioClient;@Autowiredprivate MinioConfig configuration;/*** @param name 名字* @Description description: 判断bucket是否存在,不存在则创建*/public boolean existBucket(String name) {boolean exists;try {exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(name).build());if (!exists) {minioClient.makeBucket(MakeBucketArgs.builder().bucket(name).build());exists = true;}} catch (Exception e) {e.printStackTrace();exists = false;}return exists;}/*** @param bucketName 存储bucket名称* @Description 创建存储bucket*/public Boolean makeBucket(String bucketName) {try {minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());} catch (Exception e) {e.printStackTrace();return false;}return true;}/*** @param bucketName 存储bucket名称* @Description 删除存储bucket*/public Boolean removeBucket(String bucketName) {try {minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());} catch (Exception e) {e.printStackTrace();return false;}return true;}/*** @param fileName 文件名称* @param time     时间* @Description 获取上传临时签名*/@SneakyThrowspublic Map getPolicy(String fileName, ZonedDateTime time) {PostPolicy postPolicy = new PostPolicy(configuration.getBucketName(), time);postPolicy.addEqualsCondition("key", fileName);try {Map<String, String> map = minioClient.getPresignedPostFormData(postPolicy);HashMap<String, String> map1 = new HashMap<>();map.forEach((k, v) -> {map1.put(k.replaceAll("-", ""), v);});map1.put("host", configuration.getUrl() + "/" + configuration.getBucketName());return map1;} catch (ErrorResponseException e) {e.printStackTrace();} catch (InsufficientDataException e) {e.printStackTrace();} catch (InternalException e) {e.printStackTrace();} catch (InvalidKeyException e) {e.printStackTrace();} catch (InvalidResponseException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (ServerException e) {e.printStackTrace();} catch (XmlParserException e) {e.printStackTrace();}return null;}/*** @param objectName 对象名称* @param method     方法* @param time       时间* @param timeUnit   时间单位* @Description 获取上传文件的url*/public String getPolicyUrl(String objectName, Method method, int time, TimeUnit timeUnit) {try {return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(method).bucket(configuration.getBucketName()).object(objectName).expiry(time, timeUnit).build());} catch (ErrorResponseException e) {e.printStackTrace();} catch (InsufficientDataException e) {e.printStackTrace();} catch (InternalException e) {e.printStackTrace();} catch (InvalidKeyException e) {e.printStackTrace();} catch (InvalidResponseException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (XmlParserException e) {e.printStackTrace();} catch (ServerException e) {e.printStackTrace();}return null;}/*** @param file     文件* @param fileName 文件名称* @Description 上传文件*/public void upload(MultipartFile file, String fileName) {// 使用putObject上传一个文件到存储桶中。try {InputStream inputStream = file.getInputStream();minioClient.putObject(PutObjectArgs.builder().bucket(configuration.getBucketName()).object(fileName).stream(inputStream, file.getSize(), -1).contentType(file.getContentType()).build());} catch (ErrorResponseException e) {e.printStackTrace();} catch (InsufficientDataException e) {e.printStackTrace();} catch (InternalException e) {e.printStackTrace();} catch (InvalidKeyException e) {e.printStackTrace();} catch (InvalidResponseException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (ServerException e) {e.printStackTrace();} catch (XmlParserException e) {e.printStackTrace();}}/*** @param objectName 对象名称* @param time       时间* @param timeUnit   时间单位* @Description 根据filename获取文件访问地址*/public String getUrl(String objectName, int time, TimeUnit timeUnit) {String url = null;try {url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(configuration.getBucketName()).object(objectName).expiry(time, timeUnit).build());} catch (ErrorResponseException e) {e.printStackTrace();} catch (InsufficientDataException e) {e.printStackTrace();} catch (InternalException e) {e.printStackTrace();} catch (InvalidKeyException e) {e.printStackTrace();} catch (InvalidResponseException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (XmlParserException e) {e.printStackTrace();} catch (ServerException e) {e.printStackTrace();}return url;}/*** @Description description: 下载文件*/public ResponseEntity<byte[]> download(String fileName) {ResponseEntity<byte[]> responseEntity = null;InputStream in = null;ByteArrayOutputStream out = null;try {in = minioClient.getObject(GetObjectArgs.builder().bucket(configuration.getBucketName()).object(fileName).build());out = new ByteArrayOutputStream();IOUtils.copy(in, out);//封装返回值byte[] bytes = out.toByteArray();HttpHeaders headers = new HttpHeaders();try {headers.add("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));} catch (UnsupportedEncodingException e) {e.printStackTrace();}headers.setContentLength(bytes.length);headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);headers.setAccessControlExposeHeaders(Arrays.asList("*"));responseEntity = new ResponseEntity<byte[]>(bytes, headers, 200);} catch (Exception e) {e.printStackTrace();} finally {try {if (in != null) {try {in.close();} catch (IOException e) {e.printStackTrace();}}if (out != null) {out.close();}} catch (IOException e) {e.printStackTrace();}}return responseEntity;}/*** @param objectFile 对象文件*/public String getFileUrl(String objectFile) {try {return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(configuration.getBucketName()).object(objectFile).build());} catch (Exception e) {e.printStackTrace();}return null;}
}

5、处理响应的类

package com.hmblogs.backend.util;import java.util.HashMap;/*** @Description ajax结果*/
public class AjaxResult extends HashMap<String, Object>
{private static final long serialVersionUID = 1L;/** 状态码 */public static final String CODE_TAG = "code";/** 返回内容 */public static final String MSG_TAG = "msg";/** 数据对象 */public static final String DATA_TAG = "data";/*** 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。*/public AjaxResult(){}/*** 初始化一个新创建的 AjaxResult 对象** @param code 状态码* @param msg 返回内容*/public AjaxResult(int code, String msg){super.put(CODE_TAG, code);super.put(MSG_TAG, msg);}/*** 初始化一个新创建的 AjaxResult 对象** @param code 状态码* @param msg 返回内容* @param data 数据对象*/public AjaxResult(int code, String msg, Object data){super.put(CODE_TAG, code);super.put(MSG_TAG, msg);if (data!=null){super.put(DATA_TAG, data);}}/*** 返回成功消息** @return 成功消息*/public static AjaxResult success(){return AjaxResult.success("操作成功");}/*** 返回成功数据** @return 成功消息*/public static AjaxResult success(Object data){return AjaxResult.success("操作成功", data);}/*** 返回成功消息** @param msg 返回内容* @return 成功消息*/public static AjaxResult success(String msg){return AjaxResult.success(msg, null);}/*** 返回成功消息** @param msg 返回内容* @param data 数据对象* @return 成功消息*/public static AjaxResult success(String msg, Object data){return new AjaxResult(200, msg, data);}/*** 返回警告消息** @param msg 返回内容* @return 警告消息*/public static AjaxResult warn(String msg){return AjaxResult.warn(msg, null);}/*** 返回警告消息** @param msg 返回内容* @param data 数据对象* @return 警告消息*/public static AjaxResult warn(String msg, Object data){return new AjaxResult(601, msg, data);}/*** 返回错误消息** @return 错误消息*/public static AjaxResult error(){return AjaxResult.error("操作失败");}/*** 返回错误消息** @param msg 返回内容* @return 错误消息*/public static AjaxResult error(String msg){return AjaxResult.error(msg, null);}/*** 返回错误消息** @param msg 返回内容* @param data 数据对象* @return 错误消息*/public static AjaxResult error(String msg, Object data){return new AjaxResult(500, msg, data);}/*** 返回错误消息** @param code 状态码* @param msg 返回内容* @return 错误消息*/public static AjaxResult error(int code, String msg){return new AjaxResult(code, msg, null);}/*** 方便链式调用** @param key 键* @param value 值* @return 数据对象*/@Overridepublic AjaxResult put(String key, Object value){super.put(key, value);return this;}
}

6、接口类逻辑如下:

package com.hmblogs.backend.controller;import com.hmblogs.backend.util.AjaxResult;
import com.hmblogs.backend.util.MinioUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;import java.util.HashMap;/*** @Description minio文件上传控制器*/
@CrossOrigin
@RestController
@RequestMapping("/minio")
public class MinioFileUploadController {@Autowiredprivate MinioUtils minioUtils;/*** @param file     文件* @param fileName 文件名称* @Description 上传文件*/@PostMapping("/upload")public AjaxResult uploadFile(@RequestParam("file") MultipartFile file, String fileName) {minioUtils.upload(file, fileName);return AjaxResult.success("上传成功");}/*** @param fileName 文件名称* @Description dowload文件*/@GetMapping("/dowload")public ResponseEntity dowloadFile(@RequestParam("fileName") String fileName) {return minioUtils.download(fileName);}/*** @param fileName 文件名称* @Description 得到文件url*/@GetMapping("/getUrl")public AjaxResult getFileUrl(@RequestParam("fileName") String fileName){HashMap map=new HashMap();map.put("FileUrl",minioUtils.getFileUrl(fileName));return AjaxResult.success(map);}
}

7、验证上传、下载文件,获取文件路径接口

7.1、上传文件

实际报错了,minio上没有这个文件,报错如下:

io.minio.errors.InvalidResponseException: Non-XML response from server. Response code: 400, Content-Type: text/xml; charset=utf-8, body: <?xml version="1.0" encoding="UTF-8"?><Error><Code>InvalidArgument</Code><Message>S3 API Requests must be made to API port.</Message><RequestId>0</RequestId></Error>at io.minio.S3Base.execute(S3Base.java:577)at io.minio.S3Base.getRegion(S3Base.java:691)at io.minio.S3Base.putObject(S3Base.java:2003)at io.minio.S3Base.putObject(S3Base.java:1153)at io.minio.MinioClient.putObject(MinioClient.java:1666)at com.hmblogs.backend.util.MinioUtils.upload(MinioUtils.java:177)at com.hmblogs.backend.controller.MinioFileUploadController.uploadFile(MinioFileUploadController.java:31)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)at javax.servlet.http.HttpServlet.service(HttpServlet.java:681)at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540)at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:359)at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399)at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:889)at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1735)at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)at java.lang.Thread.run(Thread.java:750)

找了一下资料,有提到在java中用的端口应该是9000的,换成9000然后就好了。9090端口是UI使用。

7.2、下载文件

访问:http://localhost:8081/hmblogs/minio/dowload?fileName=640.png

即可

7.3、获取文件路径

访问http://localhost:8081/hmblogs/minio/getUrl?fileName=640.png

{"msg":"操作成功","code":200,"data":{"FileUrl":"http://localhost:9000/hmblogs-bucket/640.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=Irr1hKVWRacP91HAqJ60%2F20240819%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20240819T040640Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=1bdcd1a3e56e59754ba5eaeb1d18e465ef316f55142539a8eedf0deb23a85b46"}}

更多的,可以参考:Minio对象存储零基础入门教程-CSDN博客

还有,涉及到使用https安全协议的,也可以参考:https://zhuanlan.zhihu.com/p/692821394

还有,和阿里OSS对象存储服务 有关的可以参考:阿里云对象存储OSS简介和使用_oss资源包有什么作用-CSDN博客

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • UniApp中的Flex布局技巧
  • 上书房信息咨询:商业项目调研方法有哪些
  • 用ClouDNS注册免费永久域名
  • Ant-Design-Vue快速上手指南 + 排坑
  • Go语言高级秘籍:提升代码效率的10大技巧
  • Kubernetes 集群部署 Prometheus 和 Grafana
  • 阿里云服务器的基本使用
  • 解码极氪汽车的短期成效与长期定力
  • Live800:重塑企业客户服务,以客户为中心的创新策略
  • 新“冰桶挑战”风靡奥运年,荣耀让科技有温度
  • Springboot功能模块之EasyExcel
  • Vue3+Vite 解决“找不到模块“@/components/xxx.vue”或其相应的类型声明 ts(2307)”
  • 【Git】更新拉取Coding子仓库代码 及 过程中用户名密码输什么 git submodule
  • 做其他的不好吗?别写代码了(3)
  • 深度解读AI大模型最火的智能体(AI Agent)
  • Apache Spark Streaming 使用实例
  • Java到底能干嘛?
  • java第三方包学习之lombok
  • jQuery(一)
  • PermissionScope Swift4 兼容问题
  • Python学习之路13-记分
  • spring-boot List转Page
  • vue-router的history模式发布配置
  • vue数据传递--我有特殊的实现技巧
  • 半理解系列--Promise的进化史
  • 仿天猫超市收藏抛物线动画工具库
  • 高度不固定时垂直居中
  • 看完九篇字体系列的文章,你还觉得我是在说字体?
  • 前端每日实战 2018 年 7 月份项目汇总(共 29 个项目)
  • 让你的分享飞起来——极光推出社会化分享组件
  • 思否第一天
  • 用mpvue开发微信小程序
  • 原生JS动态加载JS、CSS文件及代码脚本
  • 字符串匹配基础上
  • No resource identifier found for attribute,RxJava之zip操作符
  • ​ 无限可能性的探索:Amazon Lightsail轻量应用服务器引领数字化时代创新发展
  • ​【已解决】npm install​卡主不动的情况
  • ​2020 年大前端技术趋势解读
  • ​一些不规范的GTID使用场景
  • "无招胜有招"nbsp;史上最全的互…
  • # include “ “ 和 # include < >两者的区别
  • #数据结构 笔记三
  • (10)ATF MMU转换表
  • (第27天)Oracle 数据泵转换分区表
  • (附源码)spring boot智能服药提醒app 毕业设计 102151
  • (三)Pytorch快速搭建卷积神经网络模型实现手写数字识别(代码+详细注解)
  • (十六)串口UART
  • .dwp和.webpart的区别
  • .NET 6 在已知拓扑路径的情况下使用 Dijkstra,A*算法搜索最短路径
  • .NET CF命令行调试器MDbg入门(二) 设备模拟器
  • .net core docker部署教程和细节问题
  • .net core使用RPC方式进行高效的HTTP服务访问
  • .NetCore实践篇:分布式监控Zipkin持久化之殇
  • .net的socket示例
  • 。Net下Windows服务程序开发疑惑