前言
今天在對接阿里云OSS對象存儲(chǔ), 把這過程記錄下來
鏈接
阿里云的內(nèi)容很多,文檔是真的難找又難懂
本文主要是用的PostObject API 加上 Callback參數(shù)
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
對接過程
- 前端向后端發(fā)送請求獲取簽名
- 后端與OSS服務(wù)器交互,返回前端簽名
- 前端拿到簽名,直接上傳到OSS服務(wù)器
- 上傳成功,OSS回調(diào)應(yīng)用服務(wù)器,應(yīng)用服務(wù)器給前端返回上傳的信息
相比應(yīng)用服務(wù)器直接上傳到OSS,大大減少了帶寬和應(yīng)用服務(wù)器的壓力,缺點(diǎn)就是相對麻煩一點(diǎn)
1. pom.xml
我們用的是SpringBoot,我們導(dǎo)入aliyun-oss-spring-boot-starter
包,因?yàn)槲疫@個(gè)是 SpringCloud項(xiàng)目父項(xiàng)目管理了SpringCloud 和 SpringCloud Alibaba 、SpringBoot版本的,所以一開始我是沒有寫版本號的,結(jié)果一直爆紅,導(dǎo)不進(jìn)來,然后仔細(xì)一看,原來這是aliyun-oss-spring-boot-starter,注意這個(gè)boot-starter,我還以為是cloud系列的,然而哈哈,然后導(dǎo)入aliyun-spring-boot-dependencies,我在倉庫里面去找版本號,然而它也只有這一個(gè)1.0.0版本文章來源:http://www.zghlxwxcb.cn/news/detail-516680.html
<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
# 認(rèn)證過期 單位秒
expireTime: 1200
# 儲(chǔ)存空間名字
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;
/**
* 回調(diào)
* @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會(huì)在文件上傳完成后,把文件上傳信息發(fā)送給應(yīng)用服務(wù)器。需要外網(wǎng)ip
String callbackUrl = "https://23d4-1-196-175-217.ngrok-free.app/ossCallback";
// 設(shè)置上傳到OSS文件的前綴,可置空此項(xiàng)。置空后,文件將上傳至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;
// 過期時(shí)間
Date expiration = new Date(expireEndTime);
// 上傳回調(diào)參數(shù)。
Callback callback = new Callback();
callback.setCallbackUrl(callbackUrl);
// 設(shè)置回調(diào)請求消息頭中Host的值,即您的服務(wù)器配置Host的值。需要外網(wǎng)ip
callback.setCallbackHost("23d4-1-196-175-217.ngrok-free.app");
// 設(shè)置發(fā)起回調(diào)時(shí)請求body的值。
callback.setCallbackBody("filename=${object}&size=${size}&mimeType=${mimeType}");
// 設(shè)置發(fā)起回調(diào)請求的Content-Type。
callback.setCalbackBodyType(Callback.CalbackBodyType.JSON);
// 設(shè)置發(fā)起回調(diào)請求的自定義參數(shù),由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);
// 添加目錄權(quán)限,返回的認(rèn)證信息只能在這個(gè)目錄下進(jìn)行操作
policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);
// 生成認(rèn)證 添加過期時(shí)間
String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
byte[] binaryData = postPolicy.getBytes(StandardCharsets.UTF_8);
// 轉(zhuǎn)為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);
// 過期時(shí)間的時(shí)間戳
respMap.put("expire", String.valueOf(expireEndTime / 1000));
} catch (Exception e) {
throw new RuntimeException("aliyun上傳文件獲取認(rèn)證信息失敗:" + e.getMessage());
}
return respMap;
}
}
4. postman 調(diào)用獲取簽名返回
{
"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 + 文件名.后綴,然后按照下圖方式請求
注意:文章來源地址http://www.zghlxwxcb.cn/news/detail-516680.html
- Content-Type要為multipart/form-data;
- file 必須在表單數(shù)據(jù)中最后一個(gè)
- 上傳的file大小不能超過5 GB
- 不知道為什么 我這邊postman上傳的file,它的文件名字不能是中文的,不然就會(huì)返回405,這個(gè)問題調(diào)試我半天,我覺得應(yīng)該是字符編碼哪里要設(shè)置一下,沒有具體研究下去了
到了這里,關(guān)于SpringBoot對接阿里云OSS上傳文件以及回調(diào)(有坑)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!