手把手教你如何利用阿里云上传文件

最近由于公司业务需要,我需要使用阿里云来保存视频文件。然后访问的话需要一个临时的url可供使用,这样不用担心长时间暴露签名信息和地址。但是完全没做过这个东西,心里是慌得一笔。手动滑稽~~~。但是也是没办法,硬着头皮冲啦~

不过还好阿里云的社区有最佳实践的例子,可以参考下~
下面废话不多说进入正题:

一、文件设置临时访问路径

1.引入OSS依赖

直接从maven仓库去找oss的依赖就行,然后版本的话随意,个人推荐选用的人比较多版本,也不要选beta版本的,这样遇到坑的几率小一点,不要问我为什么这么说,都是泪,哈哈。实在不想选下面也给准备好了,ctrl+v就行。

<!-- oss依赖 -->
<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
    <version>3.8.0</version>
</dependency>

2.在阿里云平台创建子用户

本文的前提是你已经创建好了bucket,并且已经有文件在内,需要实现的只是生成临时访问的url。

一定一定要小心权限问题,子用户给够用的权限就行,RAM角色也是。

  1. 进入阿里云的控制台找到右上角的控制台,找到下方的对象存储 oss。
  2. 进入bucket列表就可以看到自己的桶列表,
    bucket
  3. 点击权限管理 > 访问控制RAM,就可以创建自己的角色和RAM角色,创建用户的时候选择编程访问,这样就可以启用 AccessKey ID 和 AccessKey Secret,支持通过 API 或其他开发工具访问。创建完成后就可以给角色授权。给刚好能用的权限即可,不要给太过了,特别是给公司写功能的小伙伴一定要记住这个。
  4. 那么要想临时访问的oss就需要一个临时的凭证信息,这里使用了OSS SDK 和 STS SDK结合生成凭证信息。原理图给到下方了,我们需要的角色权限是AliyunSTSAssumeRoleAccess权限,使得我们可以调用STS接口生成安全令牌(SecurityToken)、临时访问密钥(AccessKeyId和AccessKeySecret)以及过期时间。以上几样就是一个完整的凭证信息,那我们可以通过这些生成一个临时的URL对象。
    STS接口调用
  5. 接下来要去创建权限策略,在左侧导航栏的权限管理菜单下,单击权限策略管理,再点击单击新建权限策略就可以创建了。配置模式选择可视化配置或脚本配置。以脚本配置为例,对ram-test添加ListObjects与GetObject等只读权限,在策略内容中配置脚本示例如下:
{
    "Version": "1",
    "Statement": [
     {
           "Effect": "Allow",
           "Action": [
             "oss:ListObjects",
             "oss:GetObject"
           ],
           "Resource": [
             "acs:oss:*:*:ram-test",
             "acs:oss:*:*:ram-test/*"
           ]
     }
    ]
}

需要配置更细颗粒度的权限,点击这里查看。

  1. 创建Ram角色并记录角色ARN,还是RAM控制台下方,
    在这里插入图片描述
    点击创建RAN角色,我使用的是阿里云账号创建的,创建完成后,我们需要给角色配置权限,给角色配置下上面添加的权限策略,还有AliyunOSSReadOnlyAccess权限,因为最后是要访问oss文件的,所以需要这个权限。顺便把角色信息的ARN记录一下,生成临时URL需要这个信息。

3.本地代码实现生成凭证信息

下面给到阿里云官方的示例代码:

package com.yijiupi.himalaya.boaomath.basic.domain.bl.aliyun;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSSClient;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.auth.sts.AssumeRoleRequest;
import com.aliyuncs.auth.sts.AssumeRoleResponse;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.yijiupi.himalaya.base.utils.AssertUtils;
import com.yijiupi.himalaya.boaomath.basic.domain.http.properties.AliyunPolicyProperties;
import com.yijiupi.himalaya.boaomath.basic.domain.http.properties.StsAccessProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.net.URL;
import java.util.Date;

/**
 * @author LiJunJie
 * @Descripiton:Sts获取临时访
 * @create 2020-07-01 9:54
 */
@Service
public class StsAccessBL {

    @Autowired
    private StsAccessProperties stsAccessProperties;

    @Autowired
    private AliyunPolicyProperties aliyunPolicyProperties;

    private static final Logger LOG = LoggerFactory.getLogger(StsAccessBL.class);

    /**
     * 获取临时访问凭证以及临时访问RAM角色的密钥信息
     * @return
     */
    public String getAccessSecurityToken() {
        String endpoint = stsAccessProperties.getEndpoint();
        String AccessKeyId = stsAccessProperties.getAccessKeyId();
        String accessKeySecret = stsAccessProperties.getAccessKeySecret();
        String roleArn = stsAccessProperties.getRoleArn();
        String roleSessionName = stsAccessProperties.getRoleSessionName();
        String policy = "{\n" +
                "    \"Version\": \"1\", \n" +
                "    \"Statement\": [\n" +
                "        {\n" +
                "            \"Action\": [\n" +
                "                \"oss:*\"\n" +
                "            ], \n" +
                "            \"Resource\": [\n" +
                "                \"acs:oss:*:*:*\" \n" +
                "            ], \n" +
                "            \"Effect\": \"Allow\"\n" +
                "        }\n" +
                "    ]\n" +
                "}";
        try {
            // 添加endpoint(直接使用STS endpoint,前两个参数留空,无需添加region ID)
            DefaultProfile.addEndpoint("", "", "Sts", endpoint);
            // 构造default profile(参数留空,无需添加region ID)
            IClientProfile profile = DefaultProfile.getProfile("", AccessKeyId, accessKeySecret);
            // 用profile构造client
            DefaultAcsClient client = new DefaultAcsClient(profile);
            final AssumeRoleRequest request = new AssumeRoleRequest();
            request.setMethod(MethodType.POST);
            request.setRoleArn(roleArn);
            request.setRoleSessionName(roleSessionName);
            request.setPolicy(policy); // 若policy为空,则用户将获得该角色下所有权限
            request.setDurationSeconds(901L); // 设置凭证有效时间
            final AssumeRoleResponse response = client.getAcsResponse(request);
            String securityToken = response.getCredentials().getSecurityToken();
            String keyId = response.getCredentials().getAccessKeyId();
            String keySecret = response.getCredentials().getAccessKeySecret();
            return securityToken + "]" + keyId + "]" + keySecret;
        } catch (ClientException e) {
            LOG.info("GET TOKEN Failed:RequestId " + e.getRequestId());
        } catch (ServerException e) {
            e.printStackTrace();
        } catch (com.aliyuncs.exceptions.ClientException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据token信息临时访问url
     * @param fileName
     * @return
     */
    public String accessVideoByToken(String fileName) {
        if (!StringUtils.hasText(fileName)) {
            AssertUtils.fail("文件名不能为空");
        }
        String accessSecurityTokenInfo = getAccessSecurityToken();
        String[] tokenInfo = accessSecurityTokenInfo.split("]");
        if(tokenInfo.length <= 0 || tokenInfo.length > 3){
            AssertUtils.fail("token信息获取失败");
        }
        // Endpoint以杭州为例,其它Region请按实际情况填写。
        String endpoint = aliyunPolicyProperties.getEndpoint();
        // 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
        String AccessKeyId = tokenInfo[1];
        String accessKeySecret =tokenInfo[2];
        String securityToken = tokenInfo[0];
        String bucketName = aliyunPolicyProperties.getBucketName();
        String objectName = aliyunPolicyProperties.getFileHost() + fileName;
        // 用户拿到STS临时凭证后,通过其中的安全令牌(SecurityToken)和临时访问密钥(AccessKeyId和AccessKeySecret)生成OSSClient。
        // 创建OSSClient实例。注意,这里使用到了上一步生成的临时访问凭证(STS访问凭证)。
        OSSClient ossClient = new OSSClient(endpoint, AccessKeyId, accessKeySecret, securityToken);
        // OSS操作。
        Date expiration = new Date(new Date().getTime() + 300 * 1000);
        // 生成以GET方法访问的签名URL,访客可以直接通过浏览器访问相关内容。
        URL url = ossClient.generatePresignedUrl(bucketName, objectName, expiration);
        // 关闭OSSClient。
        ossClient.shutdown();
        return String.valueOf(url);
    }

}

上面这种方式很安全,但是有一个缺点是限定的时间最长为12小时,我向阿里工作人员提交工单求助过,无果,做多只能12小时。想要时间长一点可以使用下面这种:

  public String accessVideoByToken(String fileName, Date expirationTime) {
        if (!StringUtils.hasText(fileName)) {
            AssertUtils.fail("文件名不能为空");
        }
        String endpoint = aliyunPolicyProperties.getEndpoint();
        // 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
        String accessKeyId = stsAccessProperties.getAccessKeyId();
        String accessKeySecret = stsAccessProperties.getAccessKeySecret();
        String bucketName = aliyunPolicyProperties.getOutputBucket();
        String fileHost = aliyunPolicyProperties.getFileHost();
        if (!Objects.equals(env, "production")) {
            fileHost = "test/";
        }
        String objectName = fileHost + fileName;

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        // OSS操作。
        // 生成以GET方法访问的签名URL,访客可以直接通过浏览器访问相关内容。
        URL url = ossClient.generatePresignedUrl(bucketName, objectName, expirationTime);
        // 关闭OSSClient。
        ossClient.shutdown();
        return String.valueOf(url);
    }
密钥信息存放

密钥信息放在代码里肯定是比较难维护的,那么大佬们肯定已经想到了,放在application的配置文件不就好了。所以我们需要在配置文件中放入密钥信息。当然你可以存入数据库,放出修改配置信息的的接口。下面介绍下使用properties文件的方式。

properties文件中:

# OSS 密钥信息
oss.file.accessKeyId=***
oss.file.accessKeySecret=***
oss.file.roleArn=***
oss.file.roleSessionName=***
oss.file.policy=***

那么提取这些信息我们需要用到@ConfigurationProperties注解,这里就不详细解释了,百度下就行。这里介绍下使用spring自带的。

<dependency>  
    <groupId>org.springframework.boot</groupId>  
    <artifactId>spring-boot-configuration-processor</artifactId>  
    <optional>true</optional>  
</dependency> 
@Component
//接收application.yml中的oss.file前缀的属性
@ConfigurationProperties(prefix = "oss.file")
public class OssProperties {
    private String accessKeyId;

    public String getAccessKeyId() {
        return accessKeyId;
    }

    public void setAccessKeyId(String accessKeyId) {
        this.accessKeyId = accessKeyId;
    }
    
    省略···
}

那么可以顺利读取之后,只需要在需要使用的地方依赖注入就行,使用@Autowired注解就行,如下。

@Autowired 
private OssProperties ossProperties;

相关参数代码中注解都有介绍这里就不详细介绍了,可以看到生成的安全令牌等信息都在AssumeRoleResponse对象里可以获取到,获取到这些之后就可以通过这些信息生成临时的url进行访问。

至此呢,临时访问路径就生成好了,将路径返回给客户端就行,可以根据需要去修改下部分逻辑。

二、文件上传

文件上传大致可分为后端上传前端直传的方式,后端上传的方式较为简单,获取表单上传对象的文件流即可,前端直传的方式因为我个人对前端不精,做的比较费力。

后端上传

这里以springboot工程为例,控制器获取文件流,使用ossClient.putObject上传数据流到OSS。

   @PostMapping("templates/oss/upload")
    public BaseResult upload(MultipartFile file) {
        try {
            InputStream is = file.getInputStream();
            // Endpoint以杭州为例,其它Region请按实际情况填写。
            String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
            // 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
            String accessKeyId = "<yourAccessKeyId>";
            String accessKeySecret = "<yourAccessKeySecret>";

            // 创建OSSClient实例。
            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

       		//bucketName是你的ossBucket的名称,fileName是需要存储文件的名称
        	PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, fileName, is);

            // 如果需要上传时设置存储类型与访问权限,请参考以下示例代码。
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
            metadata.setObjectAcl(CannedAccessControlList.Private);
            putObjectRequest.setMetadata(metadata);
            
            ossClient.putObject(putObjectRequest);

            // 关闭OSSClient。
            ossClient.shutdown();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return BaseResult.getSuccessResult();
    }

或者你想上传某处的字节类型数组:

// Endpoint以杭州为例,其它Region请按实际情况填写。
String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
String accessKeyId = "<yourAccessKeyId>";
String accessKeySecret = "<yourAccessKeySecret>";

// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId,accessKeySecret);

// 上传Byte数组。(这里就是要上传的数组)
byte[] content = "Hello OSS".getBytes();
ossClient.putObject("<yourBucketName>", "<yourObjectName>", new ByteArrayInputStream(content));

// 关闭OSSClient。
ossClient.shutdown();

此外阿里的还支持断点续传等方式,详情可以访问阿里的最佳实践,点击跳转
总之后端上传的方式很简单,下面讲一下前端上传的方式,我是直接去下载了阿里的实列包。

客户端获取签名直传

下载阿里的实列包。aliyun-oss-appserver-js-master.zip
下载好上面的压缩包。引入plupload.js在这里插入图片描述
可自行选择需要的文件,实列的演示在包内的index.html文件内,基础好一点的打开一看可能就会了,而我这种小辣鸡就一脸懵逼呀~
在这里插入图片描述
初次之外你还需要js去使用,放出我的(angular项目的):

(function () {
    'use strict';
    var pluploadModule = angular.module("pluploadModule", []);

    pluploadModule.directive('plupload', ['$timeout', 'ejpAlert', function ($timeout, ejpAlert) {
        return {
            restrict: 'A', // E = Element, A = Attribute, C = Class, M = Comment
            scope: {
                selectFileFun: "=",//选择文件
                fileUploaderSuccessFun: "=",//上传成功之后
                uploadProgress: "=",//触发进度条
                getUploadFileName: "=",//获取随机生成的文件名
                clickUploadBtn: "=",//点击开始上传按钮
                maxFileSize: '@',
                uploadFileType: '=',
                categoryType: '='
            },
            link: function ($scope, iElm, iAttrs, controller) {


                let accessid = '',
                    vaaccesskey = '',
                    host = '',
                    policyBase64 = '',
                    signature = '',
                    callbackbody = '',
                    filename = '',
                    key = '',
                    expire = 0,
                    g_object_name = '',
                    g_object_name_type = '';
                let now = Date.parse(new Date()) / 1000;

                function send_request(fileType) {
                    var xmlhttp = null;
                    if (window.XMLHttpRequest) {
                        xmlhttp = new XMLHttpRequest();
                    } else if (window.ActiveXObject) {
                        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
                    }

                    let category = $scope.categoryType;
                    if (xmlhttp != null) {
                        // serverUrl是 用户获取 '签名和Policy' 等信息的应用服务器的URL,请将下面的IP和Port配置为您自己的真实信息。
                        let serverUrl = null;
                        if (fileType > -1) {
                            serverUrl = 'oss/getPublicPolicy?fileType=' + fileType+"&category="+category;
                        } else {
                            serverUrl = 'oss/getPolicy';
                        }

                        xmlhttp.open("GET", serverUrl, false);
                        xmlhttp.send(null);
                        return xmlhttp.responseText
                    } else {
                        alert("Your browser does not support XMLHTTP.");
                    }
                };

                function check_object_radio() {
                    g_object_name_type = 'random_name';
                }

                function get_signature(fileType) {
                    // 可以判断当前expire是否超过了当前时间, 如果超过了当前时间, 就重新取一下,3s 作为缓冲。
                    now = Date.parse(new Date()) / 1000;
                    if (expire < now + 3) {
                        let body = send_request(fileType)
                        var obj = eval("(" + body + ")").data;
                        host = obj['host']
                        policyBase64 = obj['policy']
                        accessid = obj['accessid']
                        signature = obj['signature']
                        expire = parseInt(obj['expire'])
                        callbackbody = obj['callback']
                        key = obj['dir']
                        return true;
                    }
                    return false;
                };

                function random_string(len) {
                    len = len || 32;
                    var chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';
                    var maxPos = chars.length;
                    var pwd = '';
                    for (i = 0; i < len; i++) {
                        pwd += chars.charAt(Math.floor(Math.random() * maxPos));
                    }
                    return pwd;
                }

                function getNowTimeFun() {
                    let myDate = new Date();
                    let year = myDate.getFullYear();
                    let month = timeCoverFun(myDate.getMonth() + 1);
                    let date = timeCoverFun(myDate.getDate());
                    let hours = timeCoverFun(myDate.getHours());
                    let minutes = timeCoverFun(myDate.getMinutes());
                    let seconds = timeCoverFun(myDate.getSeconds());
                    let milliseconds = timeCoverFun(myDate.getMilliseconds());
                    return (year + month + date + hours + minutes + seconds + milliseconds);
                }

                function timeCoverFun(timeText) {
                    if (timeText < 10) {
                        timeText = "0" + timeText;
                    }
                    return timeText;
                }

                function get_suffix(filename) {
                    let pos = filename.lastIndexOf('.')
                    let suffix = ''
                    if (pos != -1) {
                        suffix = filename.substring(pos)
                    }
                    return suffix;
                }

                function calculate_object_name(filename) {
                    if (g_object_name_type == 'local_name') {
                        g_object_name += `${filename}`;
                    } else if (g_object_name_type == 'random_name') {
                        let suffix = get_suffix(filename)
                        g_object_name = getNowTimeFun() + suffix;
                    }
                    let fileType = $scope.uploadFileType;
                    if (fileType == -1) {
                        $scope.getUploadFileName(g_object_name);
                    } else if (fileType == 0 || fileType == 1 || fileType == 2) {
                        $scope.getUploadFileName(host + "/" + key + g_object_name);
                    }
                    return g_object_name;
                }

                function set_upload_param(up, filename, ret) {
                    let fileType = $scope.uploadFileType;
                    if (ret == false) {
                        ret = get_signature(fileType)
                    }
                    g_object_name = key;
                    if (filename != '') {
                        g_object_name = encodeURIComponent(calculate_object_name(filename))
                    }
                    let new_multipart_params = {
                        'key': key + g_object_name,
                        'policy': policyBase64,
                        'OSSAccessKeyId': accessid,
                        'success_action_status': '200', //让服务端返回200,不然,默认会返回204
                        // 'callback' : callbackbody,
                        'signature': signature,
                    };

                    up.setOption({
                        'url': host,
                        'multipart_params': new_multipart_params
                    });

                    up.start();
                }

                var uploader = new plupload.Uploader({
                    runtimes: 'html5,flash,silverlight,html4',
                    browse_button: 'selectfiles',
                    // multi_selection: false,
                    container: document.getElementById('containerOSS'),
                    flash_swf_url: '/static/assets/aliyun-oss-appserver-js-master/lib/plupload-2.1.2/js/Moxie.swf',
                    silverlight_xap_url: '/static/assets/aliyun-oss-appserver-js-master/lib/plupload-2.1.2/js/Moxie.xap',
                    url: 'http://oss.aliyuncs.com',

                    filters: {
                        mime_types: [ //只允许上传视频和图片以及文档文件
                            {title: "Video files", extensions: "mp4,flv,mp3"},
                            {title: "Image files", extensions: "jpg,gif,png,bmp"},
                            {title: "Other files", extensions: "docx,xlsx,pdf,doc,xls"}
                        ],
                        max_file_size: $scope.maxFileSize || '3000mb', //最大上传3000mb的文件
                        prevent_duplicates: false //不允许选取重复文件
                    },

                    init: {
                        PostInit: function () {
                            document.getElementById('postfiles').onclick = function () {
                                $scope.clickUploadBtn();
                                set_upload_param(uploader, '', false);
                                return false;
                            };
                        },

                        FilesAdded: function (up, files) {
                            $scope.selectFileFun(files[0]);
                            let fileType = $scope.uploadFileType;

                            let suffix = files[0].type.substring(files[0].type.lastIndexOf("/") + 1);
                            if (fileType == 0 || fileType == -1) {
                                if (suffix != "mp4" && suffix != "flv" && suffix != "mp3") {
                                    ejpAlert.show("请选择视频文件~ (类型:mp4/flv/mp3)");
                                    return;
                                }
                            } else if (fileType == 1) {
                                if (suffix != "jpg" && suffix != "jpeg" && suffix != "gif" && suffix != "png" && suffix != "bmp") {
                                    ejpAlert.show("请选择图片文件(类型:jpg/gif/png/bmp)");
                                    return;
                                }
                            }
                        },

                        BeforeUpload: function (up, file) {
                            check_object_radio();
                            set_upload_param(up, file.name, true);
                        },

                        UploadProgress: function (up, file) {
                            $scope.uploadProgress();
                        },

                        FileUploaded: function (up, file, info) {
                            if (info.status == 200) {
                                $scope.fileUploaderSuccessFun();
                            } else if (info.status == 203) {
                                ejpAlert.show("上传到OSS成功,但是oss访问用户设置的上传回调服务器失败,失败原因是:" + info.response);
                            } else {
                                ejpAlert.show(info.response);
                            }
                        },

                        Error: function (up, err) {
                            if (err.code == -600) {
                                ejpAlert.show("您选择的文件太大了~>-<");
                            } else if (err.code == -601) {
                                ejpAlert.show("您选择的文件格式不对!");
                            } else if (err.code == -602) {
                                ejpAlert.show("这个文件已经上传过一遍了哦!");
                            } else {
                                ejpAlert.show(err.response);
                            }
                        }
                    }
                });

                uploader.init();
            }
        };
    }]);
}())

angular可以双向绑定,如果你的项目不是angular也没关系,实列包的upload.js是普通项目的示例,可以拷过去修改下。
在这里插入图片描述
使用xmlhttp请求签名,获取oss授权过的签名(由bucket的Ram角色密钥获取),
在这里插入图片描述
签名接口(我这里是直接将签名信息放到了map里):

/**
     * 获取签名信息
     *
     * @param fileType 0 - video、 1 - image
     * @return
     */
    public Map<String, String> getPublicPolicy(Integer fileType) {
        String accessId = aliyunPolicyProperties.getKeyId(); // 请填写您的AccessKeyId。
        String accessKey = aliyunPolicyProperties.getKeySecret();// 请填写您的AccessKeySecret。
        String endpoint = aliyunPolicyProperties.getEndpoint();// 请填写您的 endpoint。
        String bucket = null;// 请填写您的 bucketname 。
        String host = null; // host的格式为 bucketname.endpoint
        String dir = null; // 用户上传文件时指定的前缀。

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessId, accessKey);
        try {
            long expireTime = 3600;
            long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
            Date expiration = new Date(expireEndTime);

            PolicyConditions policyConds = new PolicyConditions();
            if (Objects.equals(fileType, 0)) {
                bucket = aliyunPolicyProperties.getPublicBucketName();
                host = "https://" + bucket + "." + endpoint.substring(8);
                dir = aliyunPolicyProperties.getFileHost();
                // PostObject请求最大可支持的文件大小为1GB
                policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000L);
            } else {
                bucket = aliyunPolicyProperties.getPublicBucketName();
                host = "https://" + bucket + "." + endpoint.substring(8);
                dir = aliyunPolicyProperties.getImgFileHost();
                // PostObject请求最大可支持的文件大小为10M
                policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 10485760L);
            }
            if (!Objects.equals(env, "production")) {
                dir = "test/";
            }
            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);

            Map<String, String> 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));

            return respMap;
        } catch (Exception e) {
            AssertUtils.fail(e.getMessage());
        } finally {
            ossClient.shutdown();
        }
        return null;
    }

修改计算文件名或者路径,作者这里有特殊需求就修改了:
在这里插入图片描述
文件配置:
在这里插入图片描述
添加文件的限制:
在这里插入图片描述
表单部分(angular):

 <form name="form"
              class="form-horizontal ng-valid ng-dirty ng-valid-parse">
            <div class="form-body">
                <div class="form-group col-md-11">
                    <label class="col-md-4 control-label">课程视频: <span class="required">*</span></label>
                    <!-- 选择图片 -->
                    <div class="col-md-8 promotion-img" id="containerOSS" plupload select-file-fun="selectFile" file-uploader-success-fun="uploadSuccessFun" upload-progress="uploadProgressFun" get-upload-file-name="getUploadFileNameFun" click-upload-btn="clickUploadBtnFun" max-file-size="3000mb" upload-file-type="theFileType" >
                        <span id="selectfiles" href="javascript:void(0);" class='btn btn-primary'>选择视频</span>
                        <span style="color: red;">注:文件大小3000M以下</span>
                        <br>
                        <div class="form-control-static" id="fileName"><span ng-bind="fileData.name" ></span>&nbsp;&nbsp;&nbsp;<b id="percent"></b></div>
                        <div class="progress" style="width: 200px;" ng-if="fileData.name">
                            <div class="progress-bar progress-bar-success" style="width: 0%;background: #5cb85c" id="progress-bar"></div>
                        </div>
                    </div>
                </div>
                <div class="form-group col-md-11">
                    <label class="col-md-4 control-label">课程讲师: <span class="required">*</span></label>
                    <p class="col-md-4 form-control-static"
                       ng-bind="dto.teacherName"></p>
                    <input type="text" name="teacherName" class="form-control"
                           ng-model="dto.teacherName" required  style="display: none">
                    <p class="help-block" ng-show="form.teacherName.$touched"
                       ng-messages="form.teacherName.$error" ng-messages-multiple>
							<span class="error-messages ng-scope ng-active"
                                  ng-message="required">要选择讲师!</span>
                    </p>
                    <button class="btn bg-blue" ng-click="selectTeacher()" type="button"><i
                            class="fa fa-link"></i> 选择
                    </button>
                </div>
                <div class="form-group col-md-11">
                    <label class="col-md-4 control-label">视频描述: <span class="required">*</span></label>
                    <div class="col-md-6">
                        <input type="text" name="videoDesc" class="form-control"
                               ng-model="dto.videoDesc" required >
                        <p class="help-block" ng-show="form.videoDesc.$touched"
                           ng-messages="form.courseDesc.$error" ng-messages-multiple>
							<span class="error-messages ng-scope ng-active"
                                  ng-message="required">描述不能为空!</span>
                        </p>
                    </div>
                </div>

            </div>
            <div class="form-group ">
                <div class="col-md-6 col-md-offset-4">
                    <button type="button" class="btn btn-primary" id="postfiles" ng-disabled="hasClickUploadBtn">
                        <i class="fa fa fa-arrow-up"></i> 开始上传
                    </button>
                    <button type="button" class="btn btn-default" ng-click="cancel()">
                        <i class="fa fa fa-close"></i> 取消
                    </button>
                </div>
            </div>
        </form>

页面js:

// 上传视频
MetronicApp.controller("addVideoController", [
    '$rootScope',
    '$scope',
    '$state',
    'settings',
    '$http',
    '$location',
    '$modal',
    'getUserInfo',
    'pagedataLoading',
    'QueryDataService',
    'ejpAlert',
    'data',
    '$modalInstance',
    function ($rootScope, $scope, $state, settings, $http,
              $location, $modal, getUserInfo, pagedataLoading,
              QueryDataService, ejpAlert, data, $modalInstance) {
        $scope.dto = {};
        $scope.dto.courseProgressId = data.item.courseProgressInfoId;

        $scope.dto.videoUrl = null;
        $scope.title = "上传视频";
        $scope.isSuccessUpload = false;
        $scope.theFileType = null;
        $scope.hasClickUploadBtn = true;
        /**
         * 选择文件
         * @param fileData
         */
        $scope.selectFile = function (fileData) {
            $scope.hasClickUploadBtn = false;
            $scope.fileData = fileData;
            //文件类型
            $scope.theFileType = -1;
            $scope.$apply();
        }

        /**
         * 获取随机生成文件名
         * @param fileName
         */
        $scope.getUploadFileNameFun = function (fileName) {
            $scope.dto.videoFileName = fileName;
        }

        /**
         * 开始上传
         */
        $scope.clickUploadBtnFun = function () {
            $scope.hasClickUploadBtn = true;
        }

        /**
         * 上传视频之后调用
         */
        $scope.uploadSuccessFun = function () {
            $http.post(" ", $scope.dto)
                .success(function (data) {
                    if (data.result === 'success') {
                        ejpAlert.show("已上传!");
                        //重置参数
                        $scope.hasClickUploadBtn = false;
                        $scope.isSuccessUpload = true;
                        $modalInstance.close();
                    }
                })
        }

        /**
         * 进度条显示
         */
        $scope.uploadProgressFun = function () {
            let fileData = $scope.fileData;
            let progBar = document.getElementById('progress-bar');
            let percent = document.getElementById('percent');
            if (progBar && percent) {
                percent.innerHTML = '<span>' + fileData.percent + "%</span>";
                progBar.style.width = 2 * fileData.percent + 'px';
                progBar.setAttribute('aria-valuenow', fileData.percent);
            }
        }


        /**
         * 取消
         */
        $scope.cancel = function () {
            if (!$scope.isSuccessUpload && $scope.hasClickUploadBtn) {
                ejpAlert.confirm("正在上传视频,取消后将会看不到视频上传进度,确认取消吗?").result.then(function () {
                    let percent = document.getElementById('percent');
                    percent.innerHTML = '';
                    let progBar = document.getElementById('progress-bar');
                    if (progBar != null && typeof(progBar)  != "undefined"){
                        progBar.setAttribute('aria-valuenow', "");
                    }
                    $modalInstance.close();
                })
            } else {
                $modalInstance.close();
            }
        };
}])

好,到这里就介绍完了客户端直传的方式,如果有什么不对的地方请多包涵,请给我指正~谢谢

在这里插入图片描述

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值