一、获取sts相关信息
public static AliOssStsVo getStsToken() {
// STS接入地址,例如sts.cn-hangzhou.aliyuncs.com。
String endpoint = "sts.cn-hangzhou.aliyuncs.com";
// 填写步骤1生成的访问密钥AccessKey ID和AccessKey Secret。
String AccessKeyId = "";
String accessKeySecret = "";
// 填写步骤3获取的角色ARN。
String roleArn = "";
// 自定义角色会话名称,用来区分不同的令牌,例如可填写为SessionTest。
String roleSessionName = "ramosstest";
// 以下Policy用于限制仅允许使用临时访问凭证向目标存储空间examplebucket上传文件。
// 临时访问凭证最后获得的权限是步骤4设置的角色权限和该Policy设置权限的交集,即仅允许将文件上传至目标存储空间examplebucket下的exampledir目录。
String policy = "{\n" +
" \"Version\": \"1\", \n" +
" \"Statement\": [\n" +
" {\n" +
" \"Action\": [\n" +
" \"oss:PutObject\"\n" +
" ], \n" +
" \"Resource\": [\n" +
" \"acs:oss:*:*:bucket-qi/*\" \n" +
" ], \n" +
" \"Effect\": \"Allow\"\n" +
" }\n" +
" ]\n" +
"}";
AliOssStsVo aliOssStsVo = new AliOssStsVo();
// regionId表示RAM的地域ID。以华东1(杭州)地域为例,regionID填写为cn-hangzhou。也可以保留默认值,默认值为空字符串("")。
try {
String regionId = "cn-hangzhou";
// 添加endpoint。适用于Java SDK 3.12.0及以上版本。
DefaultProfile.addEndpoint(regionId, "Sts", endpoint);
// 添加endpoint。适用于Java SDK 3.12.0以下版本。
// DefaultProfile.addEndpoint("",regionId, "Sts", endpoint);
// 构造default profile。
IClientProfile profile = DefaultProfile.getProfile(regionId, AccessKeyId, accessKeySecret);
// 构造client。
DefaultAcsClient client = new DefaultAcsClient(profile);
final AssumeRoleRequest request = new AssumeRoleRequest();
// 适用于Java SDK 3.12.0及以上版本。
request.setSysMethod(MethodType.POST);
// 适用于Java SDK 3.12.0以下版本。
//request.setMethod(MethodType.POST);
request.setRoleArn(roleArn);
request.setRoleSessionName(roleSessionName);
// request.setPolicy(policy); // 如果policy为空,则用户将获得该角色下所有权限。
request.setDurationSeconds(3600L); // 设置临时访问凭证的有效时间为3600秒。
final AssumeRoleResponse response = client.getAcsResponse(request);
aliOssStsVo.setAccessKeyId(response.getCredentials().getAccessKeyId());
aliOssStsVo.setAccessKeySecret(response.getCredentials().getAccessKeySecret());
aliOssStsVo.setSecurityToken(response.getCredentials().getSecurityToken());
aliOssStsVo.setExpiration(response.getCredentials().getExpiration());
//
} catch (ClientException e) {
e.printStackTrace();
}
return aliOssStsVo;
}
二、前端配置
安装ali-oss ,npm iali-oss
1、组件
<template>
<div>
<h2>单文件上传</h2>
<el-button @click="ordinaryupload">普通上传</el-button>
<el-button type="primary" @click="partUpload">分片上传</el-button>
<el-button type="success" @click="pause">暂停</el-button>
<el-button type="info" @click="resumeUpload"> 恢复上传</el-button>
<div style="display: flex;margin-top: 20px;">
<span v-text="`${file.name}(${(file.size/(1024*1024)).toFixed(1)}MB)`" style="margin-right: 15px;"
v-show="file.name"></span>
<div style="width: 30%;" v-show="progress>0">
<el-progress :percentage="parseInt((progress*100))" :format="format" :text-inside="true"
:stroke-width="20"></el-progress>
</div>
</div>
<h2>多文件上传</h2>
<div>
<el-button @click="chooseFiles">多文件选择</el-button>
<el-button @click="allUpload" type="primary" :disabled="isDisable">全部上传</el-button>
</div>
<div v-for="(item,index) in fileList" :key="item.name" style="display: flex; padding:10px 20px; ">
<div v-text="item.name" style="width: 20%;"> </div>
<div style="margin: 0 20px;width: 40%;">
<el-progress :percentage="parseInt(item.progress*100)" :format=format1>
</el-progress>
</div>
<div style="width: 20%;">
<el-button size="mini" v-text="item.isStop?'上传':'暂停'" :type="item.isStop?'success':'warning'"
@click="toggleUpload(item)" v-show="!item.fileUrl"></el-button>
<el-button size="mini" type="danger" @click="cancelUpload(item,index)" v-show="!item.fileUrl">取消
</el-button>
<i class="el-icon-circle-check" style="color: green;" v-show="item.fileUrl"></i>
</div>
</div>
</div>
</template>
<script>
import {
initOssClient,
upload,
partUpload,
resumeUpload,
ossClient,
getStsToken,
abortUpload
} from '../api/aliOssUpload.js'
import OSS from 'ali-oss'
export default {
data() {
return {
client: {},
checkPoint: {},
file: {},
dir: {},
progress: 0,
fileList: [],
isDisable: false
}
},
methods: {
format1(p) {
return p === 100 ? '完成' : p + "%"
},
// 取消上传并删除已上传的分片
cancelUpload(item, index) {
if (Object.keys(item.client).length > 0) {
abortUpload(item.client, item.checkPoint.uploadId, item.checkPoint.name)
}
this.fileList.splice(index, 1)
},
// 切换上传与暂停
async toggleUpload(item) {
item.isStop = 1 - item.isStop
if (item.isStop) {
item.client.cancel()
} else {
// 上传
if (Object.keys(item.client).length === 0) {
const {
client,
dir
} = await initOssClient()
item.client = client
item.dir = dir
}
const resp = await resumeUpload(item.client, item.file, item.dir, (p, cpt) => {
item.progress = p
item.checkPoint = cpt
}, item.checkPoint)
if (resp) {
item.fileUrl = resp[0].split("?")[0]
}
}
},
// 全部上传
async allUpload() {
if (this.fileList.some(item => item.isStop === 0)) {
return
}
const {
data: res
} = await getStsToken()
for (let item of this.fileList) {
if (Object.keys(item.client).length === 0) {
const client = ossClient(res)
item.client = client
item.dir = res.data.dir
}
item.isStop = 0
const resp = partUpload(item.client, item.file, item.dir, (p, cpt) => {
item.progress = p
item.checkPoint = cpt
}).then(res => {
if (res) {
item.fileUrl = res[0].split("?")[0]
}
})
}
this.isDisable = true
},
async chooseFiles() {
let files = await this.$chooseFile({
multiple: 'multiple'
})
for (var i = 0; i < files.length; i++) {
let item = {}
item.file = files[i]
item.name = `${files[i].name}(${(files[i].size/(1024*1024)).toFixed(1)}MB)`
item.isStop = 1
item.progress = 0,
item.client = {}
item.dir = ''
item.checkPoint = {}
item.fileUrl = ''
this.fileList.push(item)
}
this.isDisable = false
},
format() {
return (this.progress * 100).toFixed(2) + '%'
},
async init() {
if (Object.keys(this.client).length === 0) {
const {
client,
dir
} = await initOssClient()
this.client = client
this.dir = dir
console.log(this.client);
}
},
// 普通上传
async ordinaryupload() {
this.init()
let files = await this.$chooseFile()
let url = await upload(this.client, files[0], this.dir)
console.log(url);
},
// 分片上传
async partUpload() {
this.init()
let files = await this.$chooseFile()
this.file = files[0]
const resp = await partUpload(this.client, this.file, this.dir, (p, cpt) => {
this.progress = p
this.checkPoint = cpt
})
console.log(resp);
},
// 断点续传
async resumeUpload() {
const resp = await resumeUpload(this.client, this.file, this.dir, (p, cpt) => {
this.progress = p
this.checkPoint = cpt
}, this.checkPoint)
console.log(resp);
},
// 暂停上传
pause() {
this.client.cancel()
},
},
}
</script>
<style scoped>
</style>
2、api
import OSS from 'ali-oss'
import request from '../utils/request'
function getStsToken() {
return request({
url: '/getStsUpload',
method: 'get'
})
}
// 从后端获取ststoken 并初始化ossclient,通过promise返回ossclient和stsToken
export async function initOssClient() {
const {
data: res
} = await getStsToken()
if (res.code === 200) {
const client = new OSS({
region: res.data.region, // 根据那你的Bucket地点来填写
accessKeyId: res.data.accessKeyId, // 自己账户的accessKeyId或临时秘钥
accessKeySecret: res.data.accessKeySecret, // 自己账户的accessKeySecret或临时秘钥
stsToken: res.data.securityToken, // 从STS服务获取的安全令牌(SecurityToken)。
bucket: res.data.bucket, // bucket名字
refreshSTSToken: async () => {
// 向您搭建的STS服务获取临时访问凭证。
const {
data: res
} = await getSts()
return {
accessKeyId: res.data.accessKeyId, // 自己账户的accessKeyId或临时秘钥
accessKeySecret: res.data.accessKeySecret, // 自己账户的accessKeySecret或临时秘钥
stsToken: res.data.securityToken, // 从STS服务获取的安全令牌(SecurityToken)。
}
},
// 刷新临时访问凭证的时间间隔,单位为毫秒。
refreshSTSTokenInterval: 3600 * 1000
})
return {
client: client,
dir: res.data.dir
}
}
}
/**
* 普通上传
* @param {Object} client
* @param {Object} file
* @param {Object} dir
*/
export async function upload(client, file, dir) {
const {
url
} = await client.put(dir + file.name, file)
return url
}
/**
* 分片上传
* @param {Object} client oss客户端
* @param {Object} file 上传的文件
* @param {Object} dir 上传oss的文件夹
* @param {Object} progressCallback 分片进度回调
*/
export async function partUpload(client, file, dir, progressCallback) {
try {
let options = {
// 获取分片上传进度、断点和返回值。
progress: progressCallback,
// 设置并发上传的分片数量。
parallel: 8,
// 设置分片大小。默认值为1 MB,最小值为100 KB。
partSize: 100 * 1024,
mime: file.type
}
const {
res: resp
} = await client.multipartUpload(dir + file.name, file, options)
return resp.requestUrls
} catch (e) {
console.log(e);
}
}
/**
* 断点续传
* @param {Object} client oss客户端
* @param {Object} file 上传的文件
* @param {Object} dir oss上传的文件夹
* @param {Object} progressCallback 分片回调进度
* @param {Object} checkPoint 断点
*/
export async function resumeUpload(client, file, dir, progressCallback, checkPoint) {
try {
let options = {
// 获取分片上传进度、断点和返回值。
progress: progressCallback,
// 断点
checkpoint: checkPoint,
}
const {
res: resp
} = await client.multipartUpload(dir + file.name, file, options)
return resp.requestUrls
} catch (e) {
console.log(e);
}
}
/**
* 结束上传并删除碎片
* @param {Object} client
* @param {Object} uploadId
* @param {Object} name
*/
export function abortUpload(client,uploadId,name){
client.abortMultipartUpload(name,uploadId)
}
三、演示
注意:此方式页面刷新或者浏览器关闭,断点续传失效。解决方式:你可将上传的文件和暂停时的断点数据保存在localstorage中,但是这样也存在问题,当你换浏览器断点续传同样失效。