Java-整合OSS

news2024/7/4 5:19:22

文章目录

  • 前言
  • 一、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/

在这里插入图片描述

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述
约莫看一下,大概就知道这些技术是什么?怎么用的

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

在这里插入图片描述

从产品文档中可以看到 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

在这里插入图片描述

进入 对象存储 OSS

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

在这里插入图片描述

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


2. 创建 RAM 与用户授权

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

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

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

(1)创建 RAM 用户

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

在这里插入图片描述

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

在这里插入图片描述

进行验证之后

在这里插入图片描述

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

(2)RAM 用户分配权限

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

在这里插入图片描述

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

在这里插入图片描述

可以看到 选择权限 这里有很多条,针对控制访问 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

在这里插入图片描述

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

安装与使用:

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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


三、Java 整合 OSS

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

在这里插入图片描述

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


1. 基本实现

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

(1)引入依赖

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

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

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

<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.3.1</version>
</dependency>
<dependency>
    <groupId>javax.activation</groupId>
    <artifactId>activation</artifactId>
    <version>1.1.1</version>
</dependency>
<!-- no more than 2.3.3-->
<dependency>
    <groupId>org.glassfish.jaxb</groupId>
    <artifactId>jaxb-runtime</artifactId>
    <version>2.3.3</version>
</dependency>

(2)添加配置文件

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

在这里插入图片描述

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

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

在这里插入图片描述

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

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 的简单整合全部内容。

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

在这里插入图片描述


2. 客户端直传

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

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

在这里插入图片描述

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

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

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

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

在这里插入图片描述

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

在这里插入图片描述

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

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限制上传的文件前缀

测试:

在这里插入图片描述

后端就这样写就行了,

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

...

未完待续...


参考博客

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1224076.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Docker入门学习笔记

学习笔记网址推送&#xff1a;wDocker 10分钟快速入门_哔哩哔哩_bilibili docker是用来解决什么问题的&#xff1f; 例如当你在本地主机写了个web应用&#xff0c;而你打算将该应用发送给其他客户端进行案例测试和运行&#xff0c;若是传统做法&#xff0c;就比较复杂&#xf…

十个一手app拉新地推拉新推广接单平台,放单/接任务渠道

做过地推拉新的朋友一定都非常清楚&#xff0c;app拉新推广一手接单平台&#xff0c;和非一手接任务平台之间的收益差&#xff0c;可以用天壤之别来形容。那么一手app拉新渠道应该怎么找&#xff1f;下面这十个常见的地推拉新app接单平台&#xff0c;一定要收藏。 1. 聚量推客…

TCP协议相关实验

文章目录 一.TCP相关实验1.理解CLOSE_WAIT状态2.理解TIME_WAIT状态3.解决TIME_WAIT状态引起的bind失败的方法4.理解listen的第二个参数5.使用Wireshark分析TCP通信流程 二.TCP与UDP1.TCP与UDP对比2.用UDP实现可靠传输&#xff08;经典面试题&#xff09; 一.TCP相关实验 1.理解…

C++模版初阶

泛型编程 如下的交换函数中&#xff0c;它们只有类型的不同&#xff0c;应该怎么实现一个通用的交换函数呢&#xff1f; void Swap(int& left, int& right) {int temp left;left right;right temp; }void Swap(double& left, double& right) {double temp…

大模型重塑软件设计,南京真我加入飞桨技术伙伴,大模型生态圈成员又添一员!...

为帮助伙伴更快、更好的应用大模型技术&#xff0c;飞桨技术伙伴体系及权益基于星河共创计划全面升级&#xff0c;通过丰富的场景、技术、算力、品牌等资源&#xff0c;为伙伴企业提供一站式的大模型资源对接&#xff0c;全面降低创建AI原生应用的门槛。 近日&#xff0c;南京真…

数据同步策略解读

前言 我们都知道在大多数情况下&#xff0c;通过浏览器查询到的数据都是缓存数据&#xff0c;如果缓存数据与数据库的数据存在较大差异的话&#xff0c;可能会产生比较严重的后果的。对此&#xff0c;我们应该也必须保证数据库数据、缓存数据的一致性&#xff0c;也就是就是缓…

Swagger(3):Swagger入门案例

1 编写SpringBoot项目 新建一个Rest请求控制器。 package com.example.demo.controller;import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.Reques…

Linux下查看pytorch运行时真正调用的cuda版本

一般情况我们会安装使用多个cuda版本。而且pytorch在安装时也会自动安装一个对应的版本。 正确查看方式&#xff1a; 想要查看 Pytorch 实际使用的运行时的 cuda 目录&#xff0c;可以直接输出 cpp_extension.py 中的 CUDA_HOME 变量。 import torch import torch.utils imp…

​软考-高级-系统架构设计师教程(清华第2版)【第13章 层次式架构设计理论与实践(P466~495)-思维导图】​

软考-高级-系统架构设计师教程&#xff08;清华第2版&#xff09;【第13章 层次式架构设计理论与实践&#xff08;P466~495&#xff09;-思维导图】 课本里章节里所有蓝色字体的思维导图

原型网络Prototypical Network的python代码逐行解释,新手小白也可学会!!-----系列6 (承接系列5)

文章目录 一、原始代码---随机采样和评估模型二、详细解释分析每一行代码 一、原始代码—随机采样和评估模型 def randomSample(self,D_set): #从D_set随机取支持集和查询集&#xff08;20个类中的其中一个类&#xff0c;shape为[20,105,105]&#xff09;index_list list(ran…

算法设计与分析 | 分治棋盘

题目 在一个2^k * 2^k个方格组成的棋盘中&#xff0c;恰有一个方格与其他方格不同&#xff0c;称该方格为一特殊方格&#xff0c;且称该棋盘为一特殊棋盘。在棋盘覆盖问题中&#xff0c;要用图示的4种不同形态的L型骨牌覆盖给定的特殊棋盘上除特殊方格以外的所有方格&#xff0…

2023亚太杯数学建模思路 - 案例:异常检测

文章目录 赛题思路一、简介 -- 关于异常检测异常检测监督学习 二、异常检测算法2. 箱线图分析3. 基于距离/密度4. 基于划分思想 建模资料 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 一、简介 – 关于异常…

【Linux】进程间通信 -- 管道

对于进程间通信的理解 首先&#xff0c;进程间通信的本质是&#xff0c;让不同的进程看到同一份资源&#xff08;这份资源不能隶属于任何一个进程&#xff0c;即应该是共享的&#xff09;。而进程间通信的目的是为了实现多进程之间的协同。 但由于进程运行具有独立性&#xff…

stable diffusion十七种controlnet详细使用方法总结

个人网站&#xff1a;https://tianfeng.space 前言 最近不知道发点什么&#xff0c;做个controlnet 使用方法总结好了&#xff0c;如果你们对所有controlnet用法&#xff0c;可能了解但是有点模糊&#xff0c;希望能对你们有用。 一、SD controlnet 我统一下其他参数&#…

python 对图像进行聚类分析

import cv2 import numpy as np from sklearn.cluster import KMeans import time# 中文路径读取 def cv_imread(filePath, cv2_falgcv2.COLOR_BGR2RGB): cv_img cv2.imdecode(np.fromfile(filePath, dtypenp.uint8), cv2_falg) return cv_img# 自定义装饰器计算时间 def…

解决:虚拟机远程连接失败

问题 使用FinalShell远程连接虚拟机的时候连接不上 发现 虚拟机用的VMware&#xff0c;Linux发行版是CentOs 7&#xff0c;发现在虚拟机中使用ping www.baidu.com是成功的&#xff0c;但是使用FinalShell远程连接不上虚拟机&#xff0c;本地网络也ping不通虚拟机&#xff0c…

10-19 HttpServletResponse

相应的对象 web开发模型&#xff1a;基于请求与相应的模型 一问一答的模型 Response对象:响应对象,封装服务器给客户端的相关的信息 顶级接口: ServletResponse 父接口:HttpServletResponse response对象的功能分为以下四种:(都是服务器干的事注意) 设置响应头信息; 发送状态码…

2023年【四川省安全员A证】考试资料及四川省安全员A证考试试卷

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2023年四川省安全员A证考试资料为正在备考四川省安全员A证操作证的学员准备的理论考试专题&#xff0c;每个月更新的四川省安全员A证考试试卷祝您顺利通过四川省安全员A证考试。 1、【多选题】《建设工程安全生产管理…

竞赛选题 疲劳驾驶检测系统 python

文章目录 0 前言1 课题背景2 Dlib人脸识别2.1 简介2.2 Dlib优点2.3 相关代码2.4 人脸数据库2.5 人脸录入加识别效果 3 疲劳检测算法3.1 眼睛检测算法3.2 打哈欠检测算法3.3 点头检测算法 4 PyQt54.1 简介4.2相关界面代码 5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#x…

GamingTcUI.dll丢失修复,最全面的GamingTcUI.dll修复指南

热衷于电脑游戏的用户可能会在启动游戏时遇到这样的错误信息&#xff1a;"无法启动应用&#xff0c;因为找不到GamingTcUI.dll"。那么这个GamingTcUI.dll文件是什么&#xff1f;如何解决这个问题呢&#xff1f;我们将在本文中进行详细讲解。 一.GamingTcUI.dll是什么…