此次整合采用 ali-OSS 提供的服务端签名后直传的方案
——原理
- 用户发送上传 Policy 请求到应用服务器
- 应用服务器返回上传 Policy 和签名给用户
- 用户直接上传数据到 OSS
——整合
- pom.xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alicloud-oss</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
- application.properties
spring.cloud.alicloud.access-key=yourAk
spring.cloud.alicloud.secret-key=yourSk
spring.cloud.alicloud.oss.endpoint=***
spring.cloud.alicloud.oss.bucket=***
- 获取签名
@Slf4j
@RestController
public class OssController {
@Autowired
OSS ossClient;
@Value ("${spring.cloud.alicloud.oss.endpoint}")
String endpoint ;
@Value("${spring.cloud.alicloud.oss.bucket}")
String bucket ;
@Value("${spring.cloud.alicloud.access-key}")
String accessId ;
@Value("${spring.cloud.alicloud.secret-key}")
String accessKey ;
@RequestMapping("/oss/policy")
public R policy(){
// host的格式为 bucketname.endpoint
String host = "https://" + bucket + "." + endpoint;
String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
String dir = format; // 用户上传文件时指定的前缀。
Map<String, String> respMap=null;
try {
// 签名有效事件
long expireTime = 30;
long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
Date expiration = new Date(expireEndTime);
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));
} catch (Exception e) {
log.warn("获取签名异常");
} finally {
ossClient.shutdown();
}
// R 是返回数据的格式
return R.ok.put("data",respMap);
}
}
- 返回数据格式 R 类
public class R extends HashMap<String, Object> {
private static final long serialVersionUID = 1L;
public R() {
put("code", 0);
put("msg", "success");
}
public static R error() {
return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, "未知异常,请联系管理员");
}
public static R error(String msg) {
return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, msg);
}
public static R error(int code, String msg) {
R r = new R();
r.put("code", code);
r.put("msg", msg);
return r;
}
public static R ok(String msg) {
R r = new R();
r.put("msg", msg);
return r;
}
public static R ok(Map<String, Object> map) {
R r = new R();
r.putAll(map);
return r;
}
public static R ok() {
return new R();
}
public R put(String key, Object value) {
super.put(key, value);
return this;
}
}
- 返回签名的结果格式
{
"accessid": "LTAI4G3ewgWMxsrnaaeDuT1B",
"policy": "eyJleHBpcmF0aW9uIjoiMjAyMS0wMi0xNFQxMDoyOToxMS43ODhaIiwiY29uZGl0aW9ucyI6W1siY29udGVudC1sZW5ndGgtcmFuZ2UiLDAsMTA0ODU3NjAwMF0sWyJzdGFydHMtd2l0aCIsIiRrZXkiLCIyMDIxLTAyLTE0Il1dfQ==",
"signature": "0OXDXrQ1vRNl61N5IaZXRFckCKM=",
"dir": "2021-02-14",
"host": "https://gulimall-fermhan.oss-cn-qingdao.aliyuncs.com",
"expire": "1613298551"
}
- 阿里云存储开启跨域
- 结合 element-ui 组件完成上传功能
<el-upload
drag
:action="endpointUrl"
:before-upload="beforeUploadHandle"
:on-success="successHandle"
multiple
:file-list="fileList"
style="text-align: center;">
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
<div class="el-upload__tip" slot="tip">只支持jpg、png、gif格式的图片!</div>
</el-upload>
- 上传前 :before-upload 方法的实现
// 获取服务端的签名数据
function policy() {
return new Promise((resolve,reject)=>{
http({
// 先去获取签名
url: http.adornUrl("/third/party/oss/policy"),
method: "get",
params: http.adornParams({})
}).then(({ data }) => {
// 然后拿着签名去请求数据
resolve(data);
})
});
}
// 上传文件前的检验
beforeUpload(file) {
let _self = this;
return new Promise((resolve, reject) => {
policy() // 获取签名后得到相应
.then(response => {
// 意思是说policy获取到签名后,把签名信息保存起来
// console.log("这是什么${filename}");
_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;
resolve(true);
// 总的来说什么意思呢?
// 上传之前先请求签名,保存起来签名
// 根据action="http://gulimall-fermhan.oss-cn-qingdao.aliyuncs.com"
// 结合data信息,提交到云端
})
.catch(err => {
console.log("出错了...",err)
reject(false);
});
});
},