前言

今天在对接阿里云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

对接过程

  1. 前端向后端发送请求获取签名
  2. 后端与OSS服务器交互,返回前端签名
  3. 前端拿到签名,直接上传到OSS服务器
  4. 上传成功,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版本

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <!-- 阿里云OSS -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>aliyun-oss-spring-boot-starter</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>aliyun-spring-boot-dependencies</artifactId>
<version>1.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencyManagement>

2. application.yml

alibaba:
cloud:
# 阿里控制台OSS子账户的信息
access-key: LTAI5tDZ51bANyHxYpwZzvpi
secret-key: zPxHPuaZMTPzTPy0WF88vI99HHLOzO
oss:
# 深圳endpoint
endpoint: oss-cn-shenzhen.aliyuncs.com
# 认证过期 单位秒
expireTime: 1200
# 储存空间名字
bucket: yues-oss

3. 核心代码

package com.yues.gulimall.thirdparty.controller;

import com.aliyun.oss.OSS;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.Callback;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions; import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*; @RestController
public class OssController {
@Autowired
private OSS ossClient;
@Value("${alibaba.cloud.oss.endpoint}")
private String endpoint;
@Value("${alibaba.cloud.access-key}")
private String accessId;
@Value("${alibaba.cloud.oss.expireTime}")
private long expireTime;
@Value("${alibaba.cloud.oss.bucket}")
private String bucket; /**
* 回调
* @param request request
* @return Map
*/
@RequestMapping("/ossCallback")
public Map<String,String> ossCallback(HttpServletRequest request) {
HashMap<String, String> result = new HashMap<>();
String filename = request.getParameter("filename");
Map<String, String[]> parameterMap = request.getParameterMap();
parameterMap.forEach((item,value) -> {
System.out.println(item);
System.out.println(Arrays.toString(value));
});
filename = "https://".concat(bucket).concat(".").concat(endpoint).concat("/").concat(filename);
result.put("url", filename);
result.put("size", request.getParameter("size"));
result.put("mimeType", request.getParameter("mimeType"));
return result;
} /**
* 签名
* @return Map
*/
@PostMapping("/getOssSecret")
public Map<String,String> getOssSign() {
// 填写Host地址,格式为https://bucketname.endpoint。
String host = "https://" + bucket + "."+ endpoint;
// OSS会在文件上传完成后,把文件上传信息发送给应用服务器。需要外网ip
String callbackUrl = "https://23d4-1-196-175-217.ngrok-free.app/ossCallback";
// 设置上传到OSS文件的前缀,可置空此项。置空后,文件将上传至Bucket的根目录下。
// 将日期作为上传的文件夹目录
String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
String dir = format+"/";
Map<String, String> respMap = null;
try {
long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
// 过期时间
Date expiration = new Date(expireEndTime);
// 上传回调参数。
Callback callback = new Callback();
callback.setCallbackUrl(callbackUrl);
// 设置回调请求消息头中Host的值,即您的服务器配置Host的值。需要外网ip
callback.setCallbackHost("23d4-1-196-175-217.ngrok-free.app");
// 设置发起回调时请求body的值。
callback.setCallbackBody("filename=${object}&size=${size}&mimeType=${mimeType}");
// 设置发起回调请求的Content-Type。
callback.setCalbackBodyType(Callback.CalbackBodyType.JSON);
// 设置发起回调请求的自定义参数,由Key和Value组成,Key必须以x:开始。
callback.addCallbackVar("x:var1", "value1");
callback.addCallbackVar("x:var2", "value2");
// 序列化callback
String callbackString = BinaryUtil.toBase64String(new ObjectMapper().writeValueAsString(callback).getBytes(StandardCharsets.UTF_8)); PolicyConditions policyConds = new PolicyConditions();
policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
// 添加目录权限,返回的认证信息只能在这个目录下进行操作
policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir); // 生成认证 添加过期时间
String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
byte[] binaryData = postPolicy.getBytes(StandardCharsets.UTF_8);
// 转为Base64
String encodedPolicy = BinaryUtil.toBase64String(binaryData);
String postSignature = ossClient.calculatePostSignature(postPolicy); respMap = new LinkedHashMap<>();
respMap.put("OSSAccessKeyId", accessId);
respMap.put("policy", encodedPolicy);
respMap.put("Signature", postSignature);
respMap.put("dir", dir);
respMap.put("host", host);
respMap.put("callback", callbackString);
// 过期时间的时间戳
respMap.put("expire", String.valueOf(expireEndTime / 1000));
} catch (Exception e) {
throw new RuntimeException("aliyun上传文件获取认证信息失败:" + e.getMessage());
}
return respMap;
}
}

4. postman 调用获取签名返回

{
"OSSAccessKeyId": "LTAI5tDZ51bANyHxYpwZzvpi",
"policy": "eyJleHBpcmF0aW9uIjoiMjAyMy0wNy0wM1QxNzoxNzo1MS44ODBaIiwiY29uZGl0aW9ucyI6W1siY29udGVudC1sZW5ndGgtcmFuZ2UiLDAsMTA0ODU3NjAwMF0sWyJzdGFydHMtd2l0aCIsIiRrZXkiLCIyMDIzLTA3LTA0LyJdXX0=",
"Signature": "yK5oF8Cj0ncR0ceuIMtXdMW1yco=",
"dir": "2023-07-04/",
"host": "https://yues-oss.oss-cn-shenzhen.aliyuncs.com",
"callback": "eyJjYWxsYmFja1VybCI6Imh0dHBzOi8vMjNkNC0xLTE5Ni0xNzUtMjE3Lm5ncm9rLWZyZWUuYXBwL29zc0NhbGxiYWNrIiwiY2FsbGJhY2tIb3N0IjoiMjNkNC0xLTE5Ni0xNzUtMjE3Lm5ncm9rLWZyZWUuYXBwIiwiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JHtvYmplY3R9JnNpemU9JHtzaXplfSZtaW1lVHlwZT0ke21pbWVUeXBlfSIsImNhbGJhY2tCb2R5VHlwZSI6IkpTT04iLCJjYWxsYmFja1ZhciI6eyJ4OnZhcjIiOiJ2YWx1ZTIiLCJ4OnZhcjEiOiJ2YWx1ZTEifX0=",
"expire": "1688404671"
}

5. 前端上传到OSS

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



注意:

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

SpringBoot对接阿里云OSS上传文件以及回调(有坑)的更多相关文章

  1. 关于 tp5.0 阿里云 oss 上传文件操作

    tp5.0 结合阿里云oss 上传文件 1.引入 oss 的空间( composer install 跑下第三方拓展包及核心代码包) 备注:本地测试无误,放到线上有问题  应该是移动后的路劲(相对于服 ...

  2. TP5+阿里云OSS上传文件第三节,实现淘宝上传商品图片

    **TP5+阿里云OSS上传文件第三节,实现淘宝上传商品图片首先我们来看看淘宝的功能和样式:** 之后看看制作完成的演示:(由于全部功能弄成GIF有点大,限制上传大小好像在1M之内,压缩之后也有1.9 ...

  3. 使用阿里云OSS上传文件

    本文介绍如何利用Java API操作阿里云OSS对象存储. 1.控制台操作 首先介绍一下阿里云OSS对象存储的一些基本概念. 1.1 进入对象存储界面 登录阿里云账号,进入对象存储界面,如图所示. 进 ...

  4. 阿里云OSS上传文件本地调试跨域问题解决

    问题描述: 最近后台说为了提高上传效率,要前端直接上传文件到阿里云,而不经过后台.因为在阿里云服务器设置的允许源(region)为某个固定的域名下的源(例如*.cheche.com),直接在本地访问会 ...

  5. 阿里云OSS 上传文件SDK

    Aliyun OSS SDK for C# 上传文件 另外:查找的其他实现C#上传文件功能例子: 1.WPF用流的方式上传/显示/下载图片文件(保存在数据库) (文末有案例下载链接) 2.WPF中利用 ...

  6. 阿里云OSS上传文件demo

    1.安装ali-oss npm install ali-oss --save 2.demo 此例中使用到了ElementUI的el-upload组件.因为样式为自定义的 所以没有用element的自动 ...

  7. 阿里云oss上传文件如何支持https?

    let client = new OSS.Wrapper({ accessKeyId: res.data.accessKeyId, accessKeySecret: res.data.accessKe ...

  8. 阿里云 oss 上传文件,js直传,.net 签名,回调

    后台签名 添加引用 string dir = string.Format("{0:yyyy-MM-dd}", date) + "/"; OssClient cl ...

  9. 基于SqlSugar的开发框架循序渐进介绍(26)-- 实现本地上传、FTP上传、阿里云OSS上传三者合一处理

    在前面介绍的随笔<基于SqlSugar的开发框架循序渐进介绍(7)-- 在文件上传模块中采用选项模式[Options]处理常规上传和FTP文件上传>中介绍过在文件上传处理的过程中,整合了本 ...

  10. android 阿里云oss上传

    购买了阿里云的oss空间,于是用它来存储图片,不过中间的使用算是出了些问题,导致很长的才成功. 不得不说,阿里云文档真的是无力吐槽...乱七八糟的.我完全是东拼西凑,才完成的图片上传功能. 走了很多的 ...

随机推荐

  1. Vue修改单页面背景颜色

  2. Java关键字以及标识符

    Java中有许多关键字,关键字是什么意思呢? 我用自己的分析来表达一下吧. Java就是源自于生活的,我们都有自己的名字.所以它也会有许多的名字,每个名字都有各自不同的特性(作用),都是系统定义好的. ...

  3. 21-HMR

    /* HMR:hot module replacement 热模块替换 / 模块热替换 作用:一个模块发生变化,只会重新打包这一个模块(而不是打包所有模块) 极大提升构建速度 样式文件:可以使用HMR ...

  4. js对象方法大全

    JavaScript中Object构造函数的方法 Object构造函数的方法节 Object.assign() 通过复制一个或多个对象来创建一个新的对象. Object.create() 使用指定的原 ...

  5. Prism Sample 21-PassingParameters

    这个例子是说明导航中传递参数,类似Asp.net中实现. 例子的模板,是例16中使用regionContext实现过的.在例16中, <Grid x:Name="LayoutRoot& ...

  6. 2022-10-11:一个整数区间 [a, b] ( a < b ) 代表着从 a 到 b 的所有连续整数,包括 a 和 b。 给你一组整数区间intervals,请找到一个最小的集合 S, 使得

    2022-10-11:一个整数区间 [a, b] ( a < b ) 代表着从 a 到 b 的所有连续整数,包括 a 和 b. 给你一组整数区间intervals,请找到一个最小的集合 S, 使 ...

  7. 2020-10-22:谈谈java中的LongAdder和LongAccumulator的相同点和不同点。

    福哥答案2020-10-22: 简单回答:相同点:都是多个单元操作.不同点:LongAdder相加,LongAccumulator自定义计算规则. 中级回答:相同点: LongAddr与LongAcc ...

  8. 2021-03-07:在一个数组中,对于每个数num,求有多少个后面的数 * 2 依然<num,求总个数。比如:[3,1,7,0,2],3的后面有:1,0;1的后面有:0;7的后面有:0,2;0的后面没有;2的后面没有;所以总共有5个。

    2021-03-07:在一个数组中,对于每个数num,求有多少个后面的数 * 2 依然<num,求总个数.比如:[3,1,7,0,2],3的后面有:1,0:1的后面有:0:7的后面有:0,2:0 ...

  9. 2021-05-01:给定一个有序数组arr,代表坐落在X轴上的点。给定一个正数K,代表绳子的长度。返回绳子最多压中几个点?即使绳子边缘处盖住点也算盖住。

    2021-05-01:给定一个有序数组arr,代表坐落在X轴上的点.给定一个正数K,代表绳子的长度.返回绳子最多压中几个点?即使绳子边缘处盖住点也算盖住. 福大大 答案2021-05-01: 滑动窗口 ...

  10. 2013年蓝桥杯C/C++大学A组省赛真题(排它平方数)

    题目描述: 小明正看着 203879 这个数字发呆. 原来,203879 * 203879 = 41566646641 这有什么神奇呢?仔细观察,203879 是个6位数,并且它的每个数位上的数字都是 ...