0. 准备工作

0.1 oss跨域设置

前往 bucket 中的 权限管理 -> 跨域设置
image.png
并如图进行如下设置:
image.png

0.2 创建RAM 子用户

其实不创建也可以,但是强烈建议创建一个子用户,因为主体账号含有至高权限,创建子用户可以进行更细粒度的权限管控保证账号资源安全。
创建好后保存好你的子用户 AssessKeyIdAssessKeySecret 以及 bucket名称endpoint (地域),后面将会用到

0.3 两种上传方式的不同点

  • POSTObject方式 采用表单上传,使用 elementupload组件 的话可以看到上传进度。
  • PutObject方式 分简单上传和分片上传两种,只有分片上传才能获取到上传进度(其实就是可以知道上传了几个分片),并且分片上传可以断点续传,没有测试POSTObject方式能不能断点。
  • 在配置方面,POSTObject 比 PutObject要简单些。

1. PostObject 方式

1.1 后端(Java)代码如下

首先导入 Maven 依赖

<dependency>
	<groupId>com.aliyun.oss</groupId>
	<artifactId>aliyun-sdk-oss</artifactId>
	<version>3.10.2</version>
</dependency>

代码:

private static final String OSS_ENDPOINT = "oss-cn-beijing.aliyuncs.com";
private static final String ACCESS_KEY_ID = "LT***************koSL";
private static final String ACCESS_KEY_SECRET = "a0dXW*****************sSZqt";

public static JSONObject getPostPolicy() throws UnsupportedEncodingException, JSONException {
    OSS ossClient=new OSSClientBuilder().build(OSS_ENDPOINT,ACCESS_KEY_ID,ACCESS_KEY_SECRET);
    // host的格式为 bucketname.endpoint
    String host = StringFormatter.concat("https://", BUCKET_NAME, ".", OSS_ENDPOINT).getValue();
    // callbackUrl为 上传回调服务器的URL,请将下面的IP和Port配置为您自己的真实信息。
    // String callbackUrl = "http://88.88.88.88:8888";
    // 每一天产生一个文件夹
    // 用户上传文件时指定的前缀,如果是 / 则自动检测为文件夹。
    String dir = LocalDate.now().toString() + "/";

    JSONObject jsonObject = new JSONObject();
    //过期时间 100 秒
    long expireTime = 100;
    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(StandardCharsets.UTF_8);
    String encodedPolicy = BinaryUtil.toBase64String(binaryData);
    String postSignature = ossClient.calculatePostSignature(postPolicy);

    jsonObject.put("OSSAccessKeyId", ACCESS_KEY_ID);
    jsonObject.put("policy", encodedPolicy);
    jsonObject.put("signature", postSignature);
    jsonObject.put("dir", dir);
    jsonObject.put("host", host);
    jsonObject.put("expire", String.valueOf(expireEndTime / 1000));
    return jsonObject;
}

1.2 前端

<template>
    <div>
        <el-upload style="width: 340px" class="upload-demo" drag
                   action="https://***你的bucket名称****.***你的bucket地域***.aliyuncs.com"
                   :file-list="files"
                   :auto-upload="true"
                   :before-upload="beforeLoad"
                   :on-success="onSuccess"
                   :data="extraData"
                   :before-remove="beforeRemove">
            <i class="el-icon-upload"></i>
            <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
            <div class="el-upload__tip" slot="tip">不超过500kb</div>
        </el-upload>
    </div>

</template>

<script>
    import {postPolicy} from "@/network/details/ossPolicy";

    export default {
        name: "upload",
        data: () => ({
            statusMsg: "",
	    //post方式的表单域信息
            extraData: {},
            files: []
        }),
        watch: {
            statusMsg(val) {
                console.log(val)
            }
        },
        methods: {
	    // 因为向后端请求policy是异步的,我们这里同步处理就加上async
            async beforeLoad(file) {
                console.log("beforeLoad")
                console.log(file)
		//同步处理加上 await
                await postPolicy().then(res => {
                    this.extraData = {...res.data}
		    // key就是上传的文件的路径,这个是postobject的必须参数
                    this.extraData.key = res.data.dir + file.uid + "_" + file.name
                    console.log(res)
                    console.log(this.extraData)
                })
            },
            beforeRemove(file) {
                console.log("beforeRemove")
                let i = this.files.indexOf(file)
                this.files.splice(i, 1)
            },
            onSuccess() {
                console.log("onSuccess")
            },
            // 停止上传
            stop() {
                console.log("stop")
                this.statusMsg = '停止上传';
                if (ossClient) {
                    ossClient.cancel();
                } else {
                    this.statusMsg = '停止失败';
                }
            }
        }
    }
</script>

<style scoped>

</style>

2. PutObject 方式

2.0 配置

2.1 后端(Java)代码如下

首先导入 Maven 依赖

<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>aliyun-java-sdk-sts</artifactId>
    <version>3.0.0</version>
</dependency>
<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>aliyun-java-sdk-core</artifactId>
    <version>4.4.6</version>
</dependency>

代码

private static final String STS_ENDPOINT = "sts.***你的地域名***.aliyuncs.com";
private static final String ACCESS_KEY_ID = "LTA****************SL";
private static final String ACCESS_KEY_SECRET = "a0******************Zqt";
public static Map<String, String> getStsPolicy() {
    // todo
    String roleArn = "acs:ram::18*************851:role/*****";
    long durationTime = 3600L;
    // 填写步骤3获取的角色ARN。
    // 自定义角色会话名称,用来区分不同的令牌,例如可填写为SessionTest。
    String roleSessionName = "SessionTest";
    String policy = "{\n" +
            "    \"Version\": \"1\",\n" +
            "    \"Statement\": [\n" +
            "        {\n" +
            "            \"Effect\": \"Allow\",\n" +
            "            \"Action\": \"oss:PutObject\",\n" +
            "            \"Resource\": [\n" +
            "                \"acs:oss:*:*:********/\",\n" +
            "                \"acs:oss:*:*:********/*\"\n" +
            "            ]\n" +
            "        }\n" +
            "    ]\n" +
            "}";
    Map<String, String> res = null;
    try {
        res = new HashMap<>();
        // regionId表示RAM的地域ID。以华东1(杭州)地域为例,regionID填写为cn-hangzhou。也可以保留默认值,默认值为空字符串("")。
        String regionId = "";
        // 添加endpoint。适用于Java SDK 3.12.0及以上版本。
        DefaultProfile.addEndpoint(regionId, "Sts", STS_ENDPOINT);
        // 添加endpoint。适用于Java SDK 3.12.0以下版本。
        // DefaultProfile.addEndpoint(endpointName, "", regionId, product: "Sts", stsEndpoint);
        // 构造default profile。
        IClientProfile profile = DefaultProfile.getProfile(regionId, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
        // 构造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);
        // 如果policy为空,则用户将获得该角色下所有权限。
        request.setPolicy(policy);
        // 设置临时访问凭证的有效时间为3600秒。
        request.setDurationSeconds(durationTime);
        final AssumeRoleResponse response = client.getAcsResponse(request);
        AssumeRoleResponse.Credentials credentials = response.getCredentials();
        System.out.println("Expiration: " + credentials.getExpiration());
        System.out.println("Access Key Id: " + credentials.getAccessKeyId());
        System.out.println("Access Key Secret: " + credentials.getAccessKeySecret());
        System.out.println("Security Token: " + credentials.getSecurityToken());
        System.out.println("RequestId: " + response.getRequestId());
        res.put("accessKeyId", credentials.getAccessKeyId());
        res.put("accessKeySecret", credentials.getAccessKeySecret());
        res.put("securityToken", credentials.getSecurityToken());
    } catch (ClientException e) {
        System.out.println("Failed:");
        System.out.println("Error code: " + e.getErrCode());
        System.out.println("Error message: " + e.getErrMsg());
        System.out.println("RequestId: " + e.getRequestId());
    }
    return res;
}

2.2 前端代码如下

<template>
    <div>
        <el-upload style="width: 340px" class="upload-demo" drag
                   action=""
                   :http-request="onUpload"
                   :file-list="files"
                   :auto-upload="true"
                   :before-upload="beforeLoad"
                   :on-success="onSuccess"
                   :before-remove="beforeRemove">
            <i class="el-icon-upload"></i>
            <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
            <div class="el-upload__tip" slot="tip">不超过500kb</div>
        </el-upload>
    </div>

</template>

<script>
    import {stsPolicy,postPolicy} from "@/network/details/stsPolicy";

    const OSS = require('ali-oss');
    let ossClient = null; // oss客户端实例
    const partSize = 1024 * 1024 * 60; // 每个分片大小(byte)-我设置了60兆
    const parallel = 5; // 同时上传的分片数
    const checkpoints = {}; // 所有分片上传文件的检查点
    export default {
        name: "upload",
        data: () => ({
            statusMsg: "",
            progressValue: 0,
            showValue: 0,
            extraData: {},
            files: []
        }),
        watch: {
            statusMsg(val) {
                console.log(val)
            }
        },
        created() {
            // stsPolicy().then(res => {
            //     let {accessKeyId, accessKeySecret, securityToken} = res.data;
            //     this.extraData = {
            //         accessKeyId: accessKeyId,
            //         accessKeySecret: accessKeySecret,
            //         stsToken: securityToken,
            //         bucket: "clipboard-share",//todo
            //         secure: true,
            //         region: "oss-cn-beijing",//todo
            //     }
            // })
        },
        methods: {
            beforeLoad(file) {
                console.log("beforeLoad")
                console.log(file)
                this.files.push(file)
            },
            beforeRemove(file) {
                console.log("beforeRemove")
                let i = this.files.indexOf(file)
                this.files.splice(i, 1)
            },
            //清空
            clearInfo() {
                this.statusMsg = ""
                this.$refs.bigMap4UploadFile.value = ""
                this.progressValue = 0
                this.showValue = 0
            },
            onSuccess() {
                console.log("onSuccess")
            },
            //上传
            onUpload() {
                console.log("onUpload")
                this.statusMsg = '上传中';
                //获取临时sts凭证
                stsPolicy().then(res => {
                    let {accessKeyId, accessKeySecret, securityToken} = res.data;
                    ossClient = new OSS({
                        accessKeyId: accessKeyId,
                        accessKeySecret: accessKeySecret,
                        stsToken: securityToken,
                        bucket: "***你的bucket名称***",//todo
                        secure: true,
                        region: "***你的oss地域名***",//todo
                    });
                    if (ossClient) {
                        this.files.forEach(file => {
                            console.log(file)
                            // 如果文件大学小于分片大小,使用普通上传,否则使用分片上传
                            if (file.size < partSize) {
                                this.showValue = 0
                                this.commonUpload(file);
                            } else {
                                this.showValue = 1
                                this.multipartUpload(file);
                            }
                        });
                    } else {
                        console.log("ossClient null")
                        this.statusMsg = 'initOSSClient异常空,请刷新重试或联系管理员'
                    }
                }).catch(err => {
                    console.log(err)
                    this.statusMsg = 'initOSSClient异常,请刷新重试或联系管理员'
                })
            },
            //添加文件夹名字
            getDateFolder() {
                console.log("getDateFolder")
                let t = new Date();
                let timeStr = "";
                timeStr = timeStr + t.getFullYear();//年
                timeStr = timeStr + (t.getMonth() + 1);//月,因为从0开始,所以需要加1
                timeStr = timeStr + t.getDate();//日
                return timeStr
            },
            // 普通上传
            commonUpload(file) {
                console.log("commonUpload")
                console.log(file[0])
                let fileName = file.name;
                let dateFolder = this.getDateFolder();
                return ossClient.put(dateFolder + "/" + new Date().getTime() + "_" + fileName, file).then(result => {
                    console.log(`Common upload ${file.name} succeeded, result === `, result)
                    this.statusMsg = '上传成功';
                    // this.files.push(file)
                    this.$emit('change', result.url)
                }).catch(err => {
                    this.statusMsg = '上传失败';
                    this.$emit('change', "")
                    console.log(`Common upload ${file.name} failed === `, err);
                });
            },
            // 分片上传
            multipartUpload(file) {
                console.log("multipartUpload")
                let fileName = file.name;
                let dateFolder = this.getDateFolder();
                let dateStr = new Date().getTime();
                return ossClient.multipartUpload(dateFolder + "/" + dateStr + "_" + fileName, file, {
                    parallel,
                    partSize,
                    progress: this.onMultipartUploadProgress
                }).then(result => {
                    this.statusMsg = '上传成功';
                    // this.files.push(file)
                    console.log(result)
                    let url = `http://aaa.bbb.aliyuncs.com/${dateFolder}/${dateStr}_${fileName}`;//a是bucket,b是region。//todo
                    this.$emit('change', url)
                }).catch(err => {
                    this.statusMsg = '上传失败';
                    this.$emit('change', "")
                    console.log(`Multipart upload ${file.name} failed === `, err);
                    this.progressValue = 0
                    this.showValue = 0
                });
            },
            // 分片上传进度改变回调
            onMultipartUploadProgress(progress, checkpoint) {
                console.log(`${checkpoint.file.name} 上传进度 ${progress}`);
                checkpoints[checkpoint.uploadId] = checkpoint;
                this.progressValue = Math.round(progress * 100)
            },
            // 停止上传
            stop() {
                console.log("stop")
                this.statusMsg = '停止上传';
                if (ossClient) {
                    ossClient.cancel();
                } else {
                    this.statusMsg = '停止失败';
                }
            }
        }
    }
</script>

<style scoped>

</style>

3 预览图

其实也没啥预览的
image.png