SpringBoot对接阿里云OSS上传文件以及回调(有坑)

打印 上一主题 下一主题

主题 920|帖子 920|积分 2760

前言

今天在对接阿里云OSS对象存储, 把这过程记录下来
链接

阿里云的内容很多,文档是真的难找又难懂
本文主要是用的PostObject API 加上 Callback参数
PostObject -> https://help.aliyun.com/document_detail/31988.html?spm=a2c4g.31989.0.0
Callback -> https://help.aliyun.com/document_detail/31989.html?spm=a2c4g.31988.0.0
对接过程


  • 前端向后端发送请求获取签名
  • 后端与OSS服务器交互,返回前端签名
  • 前端拿到签名,直接上传到OSS服务器
  • 上传成功,OSS回调应用服务器,应用服务器给前端返回上传的信息
相比应用服务器直接上传到OSS,大大减少了带宽和应用服务器的压力,缺点就是相对麻烦一点
1. pom.xml

我们用的是SpringBoot,我们导入aliyun-oss-spring-boot-starter包,因为我这个是 SpringCloud项目父项目管理了SpringCloud 和 SpringCloud Alibaba 、SpringBoot版本的,所以一开始我是没有写版本号的,结果一直爆红,导不进来,然后仔细一看,原来这是aliyun-oss-spring-boot-starter,注意这个boot-starter,我还以为是cloud系列的,然而哈哈,然后导入aliyun-spring-boot-dependencies,我在仓库里面去找版本号,然而它也只有这一个1.0.0版本
  1. <dependencies>
  2.         <dependency>
  3.                 <groupId>org.springframework.boot</groupId>
  4.                 <artifactId>spring-boot-starter-web</artifactId>
  5.         </dependency>
  6.        
  7.         <dependency>
  8.                 <groupId>com.alibaba.cloud</groupId>
  9.                 <artifactId>aliyun-oss-spring-boot-starter</artifactId>
  10.         </dependency>
  11. </dependencies>
  12. <dependencyManagement>
  13.         <dependency>
  14.                 <groupId>com.alibaba.cloud</groupId>
  15.                 <artifactId>aliyun-spring-boot-dependencies</artifactId>
  16.                 <version>1.0.0</version>
  17.                 <type>pom</type>
  18.                 <scope>import</scope>
  19.       </dependency>
  20. </dependencyManagement>
复制代码
2. application.yml
  1. alibaba:
  2.   cloud:
  3.     # 阿里控制台OSS子账户的信息
  4.     access-key: LTAI5tDZ51bANyHxYpwZzvpi
  5.     secret-key: zPxHPuaZMTPzTPy0WF88vI99HHLOzO
  6.     oss:
  7.       # 深圳endpoint
  8.       endpoint: oss-cn-shenzhen.aliyuncs.com
  9.       # 认证过期 单位秒
  10.       expireTime: 1200
  11.       # 储存空间名字
  12.       bucket: yues-oss
复制代码
3. 核心代码
  1. package com.yues.gulimall.thirdparty.controller;
  2. import com.aliyun.oss.OSS;
  3. import com.aliyun.oss.common.utils.BinaryUtil;
  4. import com.aliyun.oss.model.Callback;
  5. import com.aliyun.oss.model.MatchMode;
  6. import com.aliyun.oss.model.PolicyConditions;
  7. import com.fasterxml.jackson.databind.ObjectMapper;
  8. import org.springframework.beans.factory.annotation.Autowired;
  9. import org.springframework.beans.factory.annotation.Value;
  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 javax.servlet.http.HttpServletRequest;
  14. import java.nio.charset.StandardCharsets;
  15. import java.text.SimpleDateFormat;
  16. import java.util.*;
  17. @RestController
  18. public class OssController {
  19.     @Autowired
  20.     private OSS ossClient;
  21.     @Value("${alibaba.cloud.oss.endpoint}")
  22.     private String endpoint;
  23.     @Value("${alibaba.cloud.access-key}")
  24.     private String accessId;
  25.     @Value("${alibaba.cloud.oss.expireTime}")
  26.     private long expireTime;
  27.     @Value("${alibaba.cloud.oss.bucket}")
  28.     private String bucket;
  29.     /**
  30.      * 回调
  31.      * @param request request
  32.      * @return Map
  33.      */
  34.     @RequestMapping("/ossCallback")
  35.     public Map<String,String> ossCallback(HttpServletRequest request) {
  36.         HashMap<String, String> result = new HashMap<>();
  37.         String filename = request.getParameter("filename");
  38.         Map<String, String[]> parameterMap = request.getParameterMap();
  39.         parameterMap.forEach((item,value) -> {
  40.             System.out.println(item);
  41.             System.out.println(Arrays.toString(value));
  42.         });
  43.         filename = "https://".concat(bucket).concat(".").concat(endpoint).concat("/").concat(filename);
  44.         result.put("url", filename);
  45.         result.put("size", request.getParameter("size"));
  46.         result.put("mimeType", request.getParameter("mimeType"));
  47.         return result;
  48.     }
  49.     /**
  50.      * 签名
  51.      * @return Map
  52.      */
  53.     @PostMapping("/getOssSecret")
  54.     public Map<String,String> getOssSign() {
  55.         // 填写Host地址,格式为https://bucketname.endpoint。
  56.         String host = "https://" + bucket + "."+ endpoint;
  57.         // OSS会在文件上传完成后,把文件上传信息发送给应用服务器。需要外网ip
  58.         String callbackUrl = "https://23d4-1-196-175-217.ngrok-free.app/ossCallback";
  59.         // 设置上传到OSS文件的前缀,可置空此项。置空后,文件将上传至Bucket的根目录下。
  60.         // 将日期作为上传的文件夹目录
  61.         String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
  62.         String dir = format+"/";
  63.         Map<String, String> respMap = null;
  64.         try {
  65.             long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
  66.             // 过期时间
  67.             Date expiration = new Date(expireEndTime);
  68.             // 上传回调参数。
  69.             Callback callback = new Callback();
  70.             callback.setCallbackUrl(callbackUrl);
  71.             // 设置回调请求消息头中Host的值,即您的服务器配置Host的值。需要外网ip
  72.              callback.setCallbackHost("23d4-1-196-175-217.ngrok-free.app");
  73.             // 设置发起回调时请求body的值。
  74.             callback.setCallbackBody("filename=${object}&size=${size}&mimeType=${mimeType}");
  75.             // 设置发起回调请求的Content-Type。
  76.             callback.setCalbackBodyType(Callback.CalbackBodyType.JSON);
  77.             // 设置发起回调请求的自定义参数,由Key和Value组成,Key必须以x:开始。
  78.             callback.addCallbackVar("x:var1", "value1");
  79.             callback.addCallbackVar("x:var2", "value2");
  80.             // 序列化callback
  81.             String callbackString = BinaryUtil.toBase64String(new ObjectMapper().writeValueAsString(callback).getBytes(StandardCharsets.UTF_8));
  82.             PolicyConditions policyConds = new PolicyConditions();
  83.             policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
  84.             // 添加目录权限,返回的认证信息只能在这个目录下进行操作
  85.             policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);
  86.             // 生成认证 添加过期时间
  87.             String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
  88.             byte[] binaryData = postPolicy.getBytes(StandardCharsets.UTF_8);
  89.             // 转为Base64
  90.             String encodedPolicy = BinaryUtil.toBase64String(binaryData);
  91.             String postSignature = ossClient.calculatePostSignature(postPolicy);
  92.             respMap = new LinkedHashMap<>();
  93.             respMap.put("OSSAccessKeyId", accessId);
  94.             respMap.put("policy", encodedPolicy);
  95.             respMap.put("Signature", postSignature);
  96.             respMap.put("dir", dir);
  97.             respMap.put("host", host);
  98.             respMap.put("callback", callbackString);
  99.             // 过期时间的时间戳
  100.             respMap.put("expire", String.valueOf(expireEndTime / 1000));
  101.         } catch (Exception e) {
  102.             throw new RuntimeException("aliyun上传文件获取认证信息失败:" + e.getMessage());
  103.         }
  104.         return  respMap;
  105.     }
  106. }
复制代码
4. postman 调用获取签名返回
  1. {
  2.     "OSSAccessKeyId": "LTAI5tDZ51bANyHxYpwZzvpi",
  3.     "policy": "eyJleHBpcmF0aW9uIjoiMjAyMy0wNy0wM1QxNzoxNzo1MS44ODBaIiwiY29uZGl0aW9ucyI6W1siY29udGVudC1sZW5ndGgtcmFuZ2UiLDAsMTA0ODU3NjAwMF0sWyJzdGFydHMtd2l0aCIsIiRrZXkiLCIyMDIzLTA3LTA0LyJdXX0=",
  4.     "Signature": "yK5oF8Cj0ncR0ceuIMtXdMW1yco=",
  5.     "dir": "2023-07-04/",
  6.     "host": "https://yues-oss.oss-cn-shenzhen.aliyuncs.com",
  7.     "callback": "eyJjYWxsYmFja1VybCI6Imh0dHBzOi8vMjNkNC0xLTE5Ni0xNzUtMjE3Lm5ncm9rLWZyZWUuYXBwL29zc0NhbGxiYWNrIiwiY2FsbGJhY2tIb3N0IjoiMjNkNC0xLTE5Ni0xNzUtMjE3Lm5ncm9rLWZyZWUuYXBwIiwiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JHtvYmplY3R9JnNpemU9JHtzaXplfSZtaW1lVHlwZT0ke21pbWVUeXBlfSIsImNhbGJhY2tCb2R5VHlwZSI6IkpTT04iLCJjYWxsYmFja1ZhciI6eyJ4OnZhcjIiOiJ2YWx1ZTIiLCJ4OnZhcjEiOiJ2YWx1ZTEifX0=",
  8.     "expire": "1688404671"
  9. }
复制代码
5. 前端上传到OSS

拿到第四步的JSON后,请求JSON中的host,key = dir + 文件名.后缀,然后按照下图方式请求

注意:

  • Content-Type要为multipart/form-data;
  • file 必须在表单数据中最后一个
  • 上传的file大小不能超过5 GB
  • 不知道为什么 我这边postman上传的file,它的文件名字不能是中文的,不然就会返回405,这个问题调试我半天,我觉得应该是字符编码哪里要设置一下,没有具体研究下去了

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

锦通

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表