Java-整合OSS

文章目录

  • 前言
  • 一、OSS 简介
  • 二、OSS 的使用
    • 1. Bucket 的创建与文件上传
    • 2. 创建 RAM 与用户授权
    • 3. 图形化管理工具-ossbrowser
  • 三、Java 整合 OSS
    • 1. 基本实现
    • 2. 客户端直传


前言

最近公司的技术负责人让我整合下 OSS 到项目中,所以花了一点时间研究了下 OSS,虽然说在 OSS 的官方文档中有如何整合 OSS 的详细说明,但是不得不说文档实在是太详细了,如果仅仅是通过看官方文档去整合,可能会看到太多暂时用不上的内容,所以我简化下文档中的内容,也是谨防日后忘记,故此作为分享。

一、OSS 简介

阿里云对象存储 OSS(Object Storage Service)是一款海量、安全、低成本、高可靠的云存储服务,提供最高可达 99.995 % 的服务可用性。多种存储类型供选择,全面优化存储成本。

可以在阿里云的产品列表中找到

地址:https://www.aliyun.com/

Java-整合OSS_第1张图片

Java-整合OSS_第2张图片

如果只是想玩一玩,做技术扩展用的,可以买一个商品类型为 OSS 资源包 的,价格很便宜

Java-整合OSS_第3张图片

对于整合这些第三方的技术,最重要的就是学会去看这些第三方提供的文档

Java-整合OSS_第4张图片
约莫看一下,大概就知道这些技术是什么?怎么用的

对象存储 OSS 产品文档:https://help.aliyun.com/zh/oss/

Java-整合OSS_第5张图片

从产品文档中可以看到 OSS 的工作原理:

数据以对象(Object)的形式存储在 OSS 的存储空间(Bucket )中。如果要使用 OSS 存储数据,需要先创建 Bucket,并指定Bucket的地域、访问权限、存储类型等属性。创建 Bucket 后,您可以将数据以 Object 的形式上传到 Bucket,并指定 Object 的文件名(Key)作为其唯一标识。

至少需要了解如下几个概念:

  • 存储空间(Bucket):存储空间是用户用于存储对象(Object)的容器,所有的对象都必须隶属于某个存储空间。存储空间具有各种配置属性,包括地域、访问权限、存储类型等。用户可以根据实际需求,创建不同类型的存储空间来存储不同的数据。
  • 对象(Object):对象是 OSS 存储数据的基本单元,也被称为 OSS 的文件。和传统的文件系统不同,对象没有文件目录层级结构的关系。对象由元信息(Object Meta)、用户数据(Data)和文件名(Key)组成,并且由存储空间内部唯一的 Key 来标识。
  • Region(地域):Region表示OSS的数据中心所在物理位置。用户可以根据费用、请求来源等选择合适的地域创建 Bucket。一般来说,距离用户更近的Region访问速度更快。Region 是在创建 Bucket 的时候指定的。Bucket 创建成功后,Region 将无法修改。
  • Endpoint(访问域名):Endpoint 表示 OSS 对外服务的访问域名。
  • AccessKey(访问密钥):AccessKey 简称 AK,指的是访问身份验证中用到的 AccessKey ID 和 AccessKey Secret。OSS 通过使用 AccessKey ID 和 AccessKey Secret 对称加密的方法来验证某个请求的发送者身份。AccessKey ID 用于标识用户;AccessKey Secret 是用户用于加密签名字符串和 OSS 用来验证签名字符串的密钥,必须保密。

OSS 产品文档 中有详细的说明,我就不多做赘述了。


二、OSS 的使用


1. Bucket 的创建与文件上传

购买 OSS 之后,登录阿里云账号,可在 产品与服务 中找到所购买的 对象存储 OSS

Java-整合OSS_第6张图片

进入 对象存储 OSS

Java-整合OSS_第7张图片

点击左侧菜单的 Bucket列表 ,就可以新建 Bucket

Java-整合OSS_第8张图片

注意:Bucket 新建之后不可修改

Java-整合OSS_第9张图片

创建成功后可在 Bucket 列表 中看到所创建的 Bucket

Java-整合OSS_第10张图片

点击该 Bucket 就可以查看其下的 文件列表 与上传文件了

Java-整合OSS_第11张图片

上传文件完成后会在 文件列表 中展示,可点击详情查看文件下载的 URL

Java-整合OSS_第12张图片

Java-整合OSS_第13张图片

可以看到这个 url 的组成:https://bucket.endpoint/filePath


2. 创建 RAM 与用户授权

在网页上虽然可以做这些文件上传等操作,但是需要登录本人的阿里云账号是不安全的,其次是在开发中也不可能在这上面进行操作,都是通过 API 进行文件上传下载等操作。

从上面的 OSS 介绍可知,OSS 的文件是存储在 Bucket 中,如果想要通过程序长期访问 Bucket 下的指定资源,就需要创建 RAM 用户(可以不登录阿里云主账号就能使用指定权限的功能),从而获取 AccessKeyIdAccessKeySecret 作为访问 OSS凭证

关于 RAM 的详细作用可参见 访问控制-RAM用户概览

(1)创建 RAM 用户

  • ① 登录阿里云,找到 AccessKey 管理,点击进入 RAM 控制台,在左侧导航栏,选择 身份管理 > 用户

Java-整合OSS_第14张图片

  • ② 点击 创建用户 ,输入 登录名称显示名称,访问方式勾选 OpenAPI 调用访问

Java-整合OSS_第15张图片

进行验证之后

Java-整合OSS_第16张图片

就能获得 AccessKey IDAccessKey Secret,这个是使用 API 连接 OSS 需要用到的,一定要及时保存 AccessKey 的信息,页面关闭后将无法再次获取信息

(2)RAM 用户分配权限

  • ① 进入 RAM 控制台,在左侧导航栏,选择 身份管理 > 用户,可以看到所有创建好的 RAM 用户
  • ② 在用户页面,单击 目标RAM用户 操作列的 添加权限

Java-整合OSS_第17张图片

  • ③ 在添加权限面板,为 RAM 用户添加权限

Java-整合OSS_第18张图片

可以看到 选择权限 这里有很多条,针对控制访问 OSS,只需要勾选 AliyunOSSFullAccess 这个权限,点击保存即可。

在这里插入图片描述

关于 RAM 用户授权 详细说明可参见:为 RAM 用户授权


3. 图形化管理工具-ossbrowser

ossbrowser 是阿里云官方提供的 OSS 图形化管理工具,提供类似 Windows 资源管理器的功能。使用 ossbrowser,您可以快速完成存储空间(Bucket)和文件(Object)的相关操作。

下载:

官方下载地址:https://help.aliyun.com/zh/oss/developer-reference/install-and-log-on-to-ossbrowser

Java-整合OSS_第19张图片

这里以 windows 64 为例,则下载 Windows 64 下的 oss-browser-win32-x64.zip 压缩包

安装与使用:

下载完成之后,进行解压,在解压后的 oss-browser-win32-x64 文件夹下找到 oss-browser.exe,双击即可打开

Java-整合OSS_第20张图片

输入之前创建 RAM 用户 时所获取的 AccessKey 账号信息,并且该账户要有访问控制 OSS 的权限(AliyunOSSFullAccess),登入

Java-整合OSS_第21张图片

在该软件上也可以进行文件上传下载等操作

Java-整合OSS_第22张图片

我使用这个图形化管理工具的目的主要是为了测试 AccessKey 信息是否能正常连接访问 OSS ~~


三、Java 整合 OSS

关于如何使用 Java 整合 OSS 其实在 OSS 产品文档 中也有比较详细的说明,我们只需要参照 开发参考 中内容基本上都能实现。

Java-整合OSS_第23张图片

所以我只提供常用的一些常用的功能实现,如果以下内容无法实现你目前的需要,可参考 OSS 产品文档 进行代码编写会比较稳妥。


1. 基本实现

首先是需要安装 OSS 的 Java SDK,在 Maven 工程中只需要在 pom.xml 中加入响应的依赖即可

(1)引入依赖

3.15.1 版本为例,在 中加入如下内容:

<dependency>
    <groupId>com.aliyun.ossgroupId>
    <artifactId>aliyun-sdk-ossartifactId>
    <version>3.15.1version>
dependency>

如果使用的是 Java 9 及以上的版本,则需要添加 jaxb 相关依赖。添加 jaxb 相关依赖示例代码如下:

<dependency>
    <groupId>javax.xml.bindgroupId>
    <artifactId>jaxb-apiartifactId>
    <version>2.3.1version>
dependency>
<dependency>
    <groupId>javax.activationgroupId>
    <artifactId>activationartifactId>
    <version>1.1.1version>
dependency>

<dependency>
    <groupId>org.glassfish.jaxbgroupId>
    <artifactId>jaxb-runtimeartifactId>
    <version>2.3.3version>
dependency>

(2)添加配置文件

想要通过程序的方式去连接 OSS,那就必须告诉程序要连接哪个 OSS 端点、哪个 Bucket、并且告诉 OSS 你是谁,交出你的访问凭证

Java-整合OSS_第24张图片

所以就需要配置 endpointbucketName 以及 AccessKey IdAccessKey Secret 信息,

endpointbucketName 可以在 Bucket 的详情页面获得

Java-整合OSS_第25张图片

这部分内容一般会放在配置文件中,例如:

yml 文件配置

aliyun:
  oss:
    access-key-id: YOUR_ACCESS_KEY_ID
    access-key-secret: YOUR_ACCESS_KEY_SECRET
    endpoint: oss-cn-xxxxxx.aliyuncs.com
    bucket-name: mike-system-file

配置类 OssProperty.java

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Data
@Component
@ConfigurationProperties("aliyun.oss")
public class OssProperty {

    /**
     * AccessKey ID
     */
    private String accessKeyId;

    /**
     * AccessKey Secret
     */
    private String accessKeySecret;

    /**
     * endpoint
     */
    private String endpoint;

    /**
     * bucketName
     */
    private String bucketName;
}

(3)代码编写

OssService.java

import com.aliyun.oss.model.Bucket;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;
import java.util.Map;

public interface OssService {

    public static final String HTTPS = "https://";
    public static final String DOT = ".";
    public static final String FORWARD_SLASH = "/";

    /**
     * 列举存储空间
     */
    List<Bucket> showBuckets();

    /**
     * 创建存储空间
     */
    void createBucket(String bucketName);

    /**
     * 删除储存空间
     */
    void removeBucket(String bucketName);

    /**
     * 上传文件
     * @param dir 存储空间某文件夹下,例如:app
     * @param file 上传的文件
     * @return 可访问的路径
     */
    String upload(String dir, MultipartFile file);

    /**
     * 下载文件
     * @param filePath 文件存储全路径,例如:dir/filename(不带 bucket 名称)
     */
    void download(String filePath);

    /**
     * 删除文件
     * @param filePath 文件存储全路径,例如:dir/filename(不带 bucket 名称)
     */
    boolean remove(String filePath);
}

OssServiceImpl.java

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.internal.OSSHeaders;
import com.aliyun.oss.model.*;
import com.aliyuncs.exceptions.ClientException;
import com.fsy.common.core.exception.CustomException;
import com.fsy.common.core.utils.DateUtils;
import com.fsy.common.core.utils.ServletUtils;
import com.fsy.tool.config.OssProperty;
import com.fsy.tool.listener.OssProgressListener;
import com.fsy.tool.service.OssService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class OssServiceImpl implements OssService {

    private final OssProperty ossProperty;
    private final HttpServletResponse response;

    /**
     * 获取 OSSClient 实例
     */
    private OSS getOssClient() {
        String endpoint = ossProperty.getEndpoint();
        return new OSSClientBuilder().build(endpoint, ossProperty.getAccessKeyId(), ossProperty.getAccessKeySecret());
    }

	/**
     * 列举存储空间
     */
    @Override
    public List<Bucket> showBuckets() {
        OSS ossClient = getOssClient();
        try {
            // 列举当前账号所有地域下的存储空间
            return ossClient.listBuckets();
        } catch (OSSException e) {
            printlnException(e);
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return null;
    }

	/**
     * 创建存储空间
     */
    @Override
    public void createBucket(String bucketName) {
        OSS ossClient = getOssClient();
        try {
            // 创建CreateBucketRequest对象。
            CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);

            // 如果创建存储空间的同时需要指定存储类型、存储空间的读写权限、数据容灾类型, 请参考如下代码
            // 此处以设置存储空间的存储类型为标准存储为例介绍
            //createBucketRequest.setStorageClass(StorageClass.Standard);
            // 数据容灾类型默认为本地冗余存储,即 DataRedundancyType.LRS。如果需要设置数据容灾类型为同城冗余存储,请设置为DataRedundancyType.ZRS
            //createBucketRequest.setDataRedundancyType(DataRedundancyType.ZRS);
            // 设置存储空间读写权限为公共读,默认为私有
            //createBucketRequest.setCannedACL(CannedAccessControlList.PublicRead);
            // 在支持资源组的地域创建Bucket时,您可以为Bucket配置资源组。
            //createBucketRequest.setResourceGroupId(rsId);

            // 创建存储空间
            ossClient.createBucket(createBucketRequest);
        } catch (OSSException e) {
            printlnException(e);
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

	/**
     * 删除储存空间
     */
    @Override
    public void removeBucket(String bucketName) {
        OSS ossClient = getOssClient();
        try {
            // 删除存储空间
            ossClient.deleteBucket(bucketName);
        } catch (OSSException e) {
            printlnException(e);
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

	/**
     * 上传文件
     * @param dir 存储空间某文件夹下,例如:app
     * @param file 上传的文件
     * @return 可访问的路径
     */
    @Override
    public String upload(String dir, MultipartFile file) {

        // 获取文件名称
        String sourceName = file.getOriginalFilename();

        // 获取地域节点
        String endpoint = ossProperty.getEndpoint();
        // 获取存储空间名称
        String bucketName = ossProperty.getBucketName();
        // 当前日期
        String ymd = DateUtils.parseDateToStr(DateUtils.YYMMDD, new Date());
        // 文件存放地址(不带 bucket)
        String filePath;
        if (StringUtils.isNotBlank(dir)) {
            // 例如:app/ymd/wms.apk
            filePath = dir + FORWARD_SLASH + ymd + FORWARD_SLASH + sourceName;
        } else {
            filePath = ymd + FORWARD_SLASH + sourceName;
        }

        // 访问路径:https://bucket.endpoint/filePath
        String urlPath = HTTPS + bucketName + DOT +  endpoint + FORWARD_SLASH + filePath;
        // 相对路径
        String relativePath = FORWARD_SLASH + filePath;

        OSS ossClient = getOssClient();

        try {
            // 判断 bucket 是否存在
            if (!ossClient.doesBucketExist(bucketName)) {
                throw new CustomException("存储空间不存在");
            }
            // 创建PutObjectRequest对象。
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, filePath, file.getInputStream());
            ObjectMetadata metadata = new ObjectMetadata();

            /*
             * 指定存储类型:
             *      对于任意存储类型的Bucket,如果上传Object时指定此参数,则此次上传的Object将存储为指定的类型
             * 取值:
             *      Standard:标准存储
             *      IA:低频访问
             *      Archive:归档存储
             *      ColdArchive:冷归档存储
             *      DeepColdArchive:深度冷归档存储
             */

            // 设置存储类型:标准存储(默认标准存储)
            metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());

            /*
             * 指定上传文件的访问权限:
             * 取值:
             *      default(默认):Object遵循所在存储空间的访问权限
             *      private:私有
             *      public-read:公共读
             *      public-read-write:公共读写
             */

            // 设置访问权限:默认(遵循所在存储空间的访问权限)
            metadata.setObjectAcl(CannedAccessControlList.Default);

            /*
             * 指定上传文件操作时是否覆盖同名 Object:
             *      不指定 x-oss-forbid-overwrite 时,默认覆盖同名 Object
             *      指定 x-oss-forbid-overwrite 为 false 时,表示允许覆盖同名 Object
             *      指定 x-oss-forbid-overwrite 为 true 时,表示禁止覆盖同名 Object,如果同名 Object 已存在,程序将报错
             */

            // 设置禁止覆盖同名文件
            metadata.setHeader("x-oss-forbid-overwrite", "false");

            // 设置元数据
            putObjectRequest.setMetadata(metadata);

            // 上传文件
            ossClient.putObject(putObjectRequest);

        } catch (IOException e) {
            log.error("failed to upload file.detail message:{}", e.getMessage());

        } catch (OSSException e) {
            printlnException(e);
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return urlPath;
    }

	/**
     * 下载文件
     * @param filePath 文件存储全路径,例如:dir/filename(不带 bucket 名称)
     */
    @Override
    public void download(String filePath) {

        String bucketName = ossProperty.getBucketName();
        OSS ossClient = getOssClient();

        // 截取文件名称
        String fileName = filePath.substring(filePath.lastIndexOf(FORWARD_SLASH));

        try {
            // 判断文件是否存在
            if (!ossClient.doesObjectExist(bucketName, filePath)) {
                throw new CustomException("文件不存在");
            }

            // ossObject 包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流
            OSSObject ossObject = ossClient.getObject(new GetObjectRequest(bucketName, filePath));
            InputStream inputStream = ossObject.getObjectContent();

            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int num;
            while ((num = inputStream.read(buffer)) != -1) {
                byteArrayOutputStream.write(buffer, 0, num);
            }
            byteArrayOutputStream.flush();
            byte[] bytes = byteArrayOutputStream.toByteArray();
            byteArrayOutputStream.close();

            // 读取,返回
            ServletUtils.writeAttachment(response, fileName, bytes);

            // ossObject 对象使用完毕后必须关闭,否则会造成连接泄漏,导致请求无连接可用,程序无法正常工作
            ossObject.close();

        } catch (OSSException oe) {
            printlnException(oe);
        } catch (Throwable ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    @Override
    public boolean remove(String filePath) {
        String bucketName = ossProperty.getBucketName();

        OSS ossClient = getOssClient();
        try {
            // 判断文件是否存在
            if (!ossClient.doesObjectExist(bucketName, filePath)) {
                log.warn("need delete file:{} not exists", filePath);
                return false;
            }
            // 删除文件或目录。如果要删除目录,目录必须为空
            ossClient.deleteObject(bucketName, filePath);

            return true;

        } catch (OSSException oe) {
            printlnException(oe);
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return false;
    }

	/**
	 * 返回附件
	 */
	public void writeAttachment(HttpServletResponse response, String filename, byte[] content) throws IOException {
        // 设置 header 和 contentType
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
        // 输出附件
        IoUtil.write(response.getOutputStream(), false, content);
    }

    /**
     * 打印异常日志
     */
    public void printlnException(Exception e) {
        if (e instanceof OSSException) {
            OSSException oe = (OSSException) e;
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        }
        if (e instanceof ClientException) {
            ClientException ce = (ClientException) e;
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        }
    }
}

(4)测试

Java-整合OSS_第26张图片

上传文件

Java-整合OSS_第27张图片

Java-整合OSS_第28张图片

以上便是 Java 对 OSS 的简单整合全部内容。

OSS 产品文档 中还有很多个案例,写得也是比较详细,我就不多做赘述了,只要先实现以上的功能,其它的都可以参照产品文档慢慢研究,比如说分片上传、进图条等等。

Java-整合OSS_第29张图片


2. 客户端直传

除了通过服务器代理上传文件的方式外,OSS 还提供了客户端直传的方式。

在典型的服务端和客户端架构下,常见的文件上传方式是服务端代理上传:客户端将文件上传到业务服务器,然后业务服务器将文件上传到OSS。在这个过程中,一份数据需要在网络上传输两次,会造成网络资源的浪费、增大服务端的资源开销。为了解决这一问题,可以在客户端直连 OSS 来完成文件上传,无需经过业务服务器中转。

Java-整合OSS_第30张图片

服务端代理上传和客户端直传相比,有以下三个缺点:

  • 上传慢:用户数据先上传到应用服务器,之后再上传到 OSS,网络传输时间比直传到 OSS 多一倍,如果用户数据不通过应用服务器中转,而是直传到 OSS,速度将大大提升,而且 OSS 采用 BGP 宽带,能保证各地各运营商之间的传输速度
  • 扩展性差:如果后续用户多了,应用服务器会成为瓶颈
  • 费用高:需要准备多台应用服务器,用于 OSS 上传流量是免费的,如果数据直传到 OSS,不通过应用服务器,那么将能省下几台应用服务器

从服务端代理上传的案例可知,要想要上传图片,那就必须提供 endpointbucketAccessKey 的信息,但是在前端直接将这些信息写在 js 里面是非常不安全的,容易造成信息泄漏,遭受攻击

所以通常的做法就是前端先向后端发送上传文件的 Post Policy 请求,应用服务器返回签名给前端,前端再携带签名直接将文件上传至 OSS

Java-整合OSS_第31张图片

后端可以参照 OSS 产品文档 来编写接口,提供签名

Java-整合OSS_第32张图片

例如(在 基本实现 的案例上添加代码):

Controller

    @GetMapping(value = "/signature")
    @ApiOperation(value = "获取签名")
    public ResponseBean signature(@ApiParam(required = true, value = "上传路径") @RequestParam(required = true) String dir) {
        return ResponseBean.success(ossService.signature(dir));
    }

Service

    /**
     * 服务端签名直传
     * @param dir 设置上传到 OSS 的路径(目录)
     * @return 签名信息
     */
    Map<String, String> signature(String dir);

ServiceImpl

    @Override
    public Map<String, String> signature(String dir) {

        String accessId = ossProperty.getAccessKeyId();
        String endpoint = ossProperty.getEndpoint();
        String bucket = ossProperty.getBucketName();
        // Host 地址,格式为:https://bucket.endpoint
        String host = HTTPS + bucket + DOT +  endpoint;
        // 设置上传回调 URL
        String callbackUrl = "https://www.xxxx.xxx";

        // 创建ossClient实例
        OSS ossClient = getOssClient();
        try {
            long expireTime = 30;
            long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
            Date expiration = new Date(expireEndTime);
            PolicyConditions policyConditions = new PolicyConditions();
            policyConditions.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
            policyConditions.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);

            String postPolicy = ossClient.generatePostPolicy(expiration, policyConditions);
            byte[] binaryData = postPolicy.getBytes(StandardCharsets.UTF_8);
            String encodedPolicy = BinaryUtil.toBase64String(binaryData);
            String postSignature = ossClient.calculatePostSignature(postPolicy);

            Map<String, String> respMap = new LinkedHashMap<>();
            respMap.put("access_id", accessId);
            respMap.put("policy", encodedPolicy);
            respMap.put("signature", postSignature);
            respMap.put("dir", dir);
            respMap.put("host", host);
            respMap.put("expire", String.valueOf(expireEndTime / 1000));

            /*
             * 设置回调接口的一些相关参数
             * 
             *      JSONObject jasonCallback = new JSONObject();
             *      jasonCallback.put("callbackUrl", callbackUrl);
             *      jasonCallback.put("callbackBody",
             *              "filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}");
             *      jasonCallback.put("callbackBodyType", "application/x-www-form-urlencoded");
             *      String base64CallbackBody = BinaryUtil.toBase64String(jasonCallback.toString().getBytes());
             *      respMap.put("callback", base64CallbackBody);
             */
            
            return respMap;

        } catch (Exception e) {
            // Assert.fail(e.getMessage());
            System.out.println(e.getMessage());
        }
        return null;
    }

Body中的各字段说明如下:

字段 描述
accessid 用户请求的AccessKey ID
host 用户发送上传请求的域名
policy 用户表单上传的策略(Policy),Policy为经过Base64编码过的字符串。详情请参见Post Policy
signature 对Policy签名后的字符串
expire 由服务器端指定的Policy过期时间,格式为Unix时间戳(自UTC时间1970年01月01号开始的秒数)
dir 限制上传的文件前缀

测试:

Java-整合OSS_第33张图片

后端就这样写就行了,

前端 vue + element-ui,OSS 上传文件代码如下:

...

未完待续...


参考博客

JAVA整合阿里云OSS/VUE上传阿里云OSS:https://blog.51cto.com/u_15899048/5903392

你可能感兴趣的:(java,阿里云)