《幻塔》主T副本實戰細節講解
阿新 • • 發佈:2022-01-13
OSS物件儲存
當專案以微服務搭建時,多個服務往往執行在多臺伺服器上,此時針對儲存檔案的獲取和儲存,難以確定具體的位置;
針對這個問題,一般有兩個辦法:
- 搭建獨立的檔案儲存伺服器,用 FastDFS等構建
- 使用第三方的物件儲存 OSS,如 阿里雲的 OSS
一、資料庫的設計
一般資料庫設計欄位儲存檔案在上傳 OSS後返回的地址值,欄位宜採用 Varchar
二、後端
一般有兩種用法:
- 前端把待傳檔案,先傳給伺服器,然後伺服器傳給阿里雲
- 前端向伺服器索取驗證用的 Access Key等校驗資訊,然後獨立傳給 阿里雲,最後再把結果傳給伺服器
一般使用後者
2.1、依賴
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alicloud-oss</artifactId> </dependency>
該依賴中包含了原始的 aliyun-sdk-oss
,並且強制在配置檔案中配置物件儲存的資訊,並且會自動建立 OSSclient
物件
2.2、配置
spring: cloud: alicloud: access-key: LTAI5tKV72y86Xty******** secret-key: BJXWfm4lxgc9Wv2LA2Z********** oss: endpoint: oss-cn-hangzhou.aliyuncs.com bucket: oliq-gulimall #這個不是預設的配置,這麼寫是為了方便程式碼裡面通過 @Value()獲取
2.3、使用
package com.zwb.gulimall.thirdparty.controller; import com.aliyun.oss.OSSClient; import com.aliyun.oss.common.utils.BinaryUtil; import com.aliyun.oss.model.MatchMode; import com.aliyun.oss.model.PolicyConditions; import com.zwb.common.utils.R; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import java.time.LocalDate; import java.util.Date; import java.util.LinkedHashMap; import java.util.Map; /** * @author:OliQ * @date: Created on 2022-01-20 16:40 * @description: */ @RestController() @RequestMapping("/oss") public class OSSController { @Resource private OSSClient ossClient; @Value("${spring.cloud.alicloud.oss.bucket}") private String bucket; @Value("${spring.cloud.alicloud.oss.endpoint}") private String endpoint; @Value("${spring.cloud.alicloud.access-key}") private String accessId; @RequestMapping("/policy") public R policy() { String host = "https://" + bucket + "." + endpoint; // host的格式為 bucketname.endpoint // callbackUrl為上傳回調伺服器的URL,請將下面的IP和Port配置為您自己的真實資訊。 // String callbackUrl = "http://88.88.88.88:8888"; String dir = LocalDate.now().toString(); // 使用者上傳檔案時指定的字首。 Map<String, String> respMap = null; try { long expireTime = 30; long expireEndTime = System.currentTimeMillis() + expireTime * 1000; Date expiration = new Date(expireEndTime); // PostObject請求最大可支援的檔案大小為5 GB,即CONTENT_LENGTH_RANGE為5*1024*1024*1024。 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("utf-8"); String encodedPolicy = BinaryUtil.toBase64String(binaryData); String postSignature = ossClient.calculatePostSignature(postPolicy); respMap = new LinkedHashMap<String, String>(); respMap.put("accessid", accessId); respMap.put("policy", encodedPolicy); respMap.put("signature", postSignature); respMap.put("dir", dir); respMap.put("host", host); respMap.put("expire", String.valueOf(expireEndTime / 1000)); // respMap.put("expire", formatISO8601Date(expiration)); } catch (Exception e) { // Assert.fail(e.getMessage()); System.out.println(e.getMessage()); } finally { ossClient.shutdown(); } return R.ok().put("data", respMap); } }
三、前端
主要邏輯就是:
- 向伺服器發請求獲取 驗證資訊
- 向阿里雲上傳資料
- 將檔案路徑交給伺服器
3.1、頁面元件
<template>
<div>
<!-- action必選引數,上傳地址,bucket的外網訪問域名 -->
<el-upload
action="https://oliq-gulimall.oss-cn-hangzhou.aliyuncs.com"
:data="dataObj"
list-type="picture"
:multiple="false"
:show-file-list="showFileList"
:file-list="fileList"
:before-upload="beforeUpload"
:on-remove="handleRemove"
:on-success="handleUploadSuccess"
:on-preview="handlePreview"
>
<el-button size="small" type="primary">點選上傳</el-button>
<div slot="tip" class="el-upload__tip">
只能上傳jpg/png檔案,且不超過10MB
</div>
</el-upload>
<el-dialog :visible.sync="dialogVisible">
<img width="100%" :src="fileList[0].url" alt="" />
</el-dialog>
</div>
</template>
3.2、資料
data() {
return {
dataObj: {
policy: "",
signature: "",
key: "",
ossaccessKeyId: "",
dir: "",
host: "",
// callback:'',
},
dialogVisible: false,
};
},
3.3、JS
methods: {
emitInput(val) {
this.$emit("input", val);
},
handleRemove(file, fileList) {
this.emitInput("");
},
handlePreview(file) {
this.dialogVisible = true;
},
beforeUpload(file) {
let _self = this;
return new Promise((resolve, reject) => {
policy()
.then((response) => {
_self.dataObj.policy = response.data.policy;
_self.dataObj.signature = response.data.signature;
_self.dataObj.ossaccessKeyId = response.data.accessid;
_self.dataObj.key =
response.data.dir + "/" + getUUID() + "_${filename}";
_self.dataObj.dir = response.data.dir;
_self.dataObj.host = response.data.host;
console.log("上傳前請求服務端簽名,得到結果:", _self.dataObj);
resolve(true);
})
.catch((err) => {
reject(false);
});
});
},
handleUploadSuccess(res, file) {
console.log("上傳成功...");
this.showFileList = true;
this.fileList.pop();
this.fileList.push({
name: file.name,
url:
this.dataObj.host +
"/" +
this.dataObj.key.replace("${filename}", file.name),
});
this.emitInput(this.fileList[0].url);
},
},
請求傳送程式碼:
import http from '@/utils/httpRequest.js'
export function policy() {
return new Promise((resolve,reject)=>{
http({
url: http.adornUrl("/thirdparty/oss/policy"),
method: "get",
params: http.adornParams({})
}).then(({ data }) => {
resolve(data);
}).catch(err => {
console.log("出錯了...",err)
reject(false);
});
});
}