跳至主要內容

Springboot系列之接入腾讯云对象存储COS

holic-x...大约 8 分钟框架Springboot

Springboot-接入腾讯云对象存储COS

腾讯云存储

​ 腾讯云对象存储(Tencent Cloud Object Storage,COS)是一种安全、可靠、低成本、高扩展的云端存储服务。COS能够存储各种非结构化数据,包括图片、视频、音频、文本等。COS支持标准的HTTP/HTTPS协议,可以通过API、SDK、控制台等方式进行数据的上传、下载和管理。COS还提供了数据保护、数据备份、数据恢复、数据传输加密等多项安全措施,确保用户数据的安全性和可靠性。COS还支持自动化、智能化的数据生命周期管理,帮助用户降低数据存储成本。COS是云计算领域中存储服务的重要组成部分,广泛应用于云存储、备份、归档、内容分发等场景

腾讯云对象存储COSopen in new window初始化:

  • 申请腾讯云账号、进行实名认证

  • 开通对象存储COS服务,进入管理控制台

  • 创建Bucket(管理控制台=》存储桶列表=》创建存储桶),选择公有读取(其他选择默认)

  • Bucket创建完成,可在存储桶列表进行管理

  • 创建API秘钥:访问管理=》API秘钥管理open in new window,创建秘钥用于API访问(注意23.11.30起SecretKey只支持在创建的时候查看,需要在初始化的时候进行保存)

代码对接腾讯云COS

​ 参考腾讯云对象存储API接口对接文档open in new window

​ 对接腾讯云COS需要使用其请提供的SDKopen in new window进行构建,通过调用请求完成操作。此处参考Java SDK快速入门open in new window

​ 建议创建子用户,使用子用户秘钥(例如创建一个dev-COS子用户,构建子用户秘钥)进行访问(避免主账号秘钥泄露造成风险),腾讯云用户管理open in new window

Maven引入cos依赖open in new window

<!-- https://mvnrepository.com/artifact/com.qcloud/cos_api -->
<dependency>
    <groupId>com.qcloud</groupId>
    <artifactId>cos_api</artifactId>
    <version>5.6.211</version>
</dependency>

测试网络联通

# 方式1:ping测试网络联通
ping cos.ap-guangzhou.myqcloud.com

PING gz.file.myqcloud.com (27.155.119.181): 56 data bytes
64 bytes from 27.155.119.181: icmp_seq=0 ttl=45 time=16.814 ms
64 bytes from 27.155.119.181: icmp_seq=1 ttl=45 time=16.858 ms
64 bytes from 27.155.119.181: icmp_seq=2 ttl=45 time=17.273 ms
64 bytes from 27.155.119.181: icmp_seq=3 ttl=45 time=16.924 ms
64 bytes from 27.155.119.181: icmp_seq=4 ttl=45 time=16.884 ms
64 bytes from 27.155.119.181: icmp_seq=5 ttl=45 time=17.422 ms


# 方式2:curl测试访问
// curl测试http访问
curl http://cos.ap-guangzhou.myqcloud.com -v

// curl测试https范文
curl https://cos.ap-guangzhou.myqcloud.com -vk

# 如果可以正常响应则说明访问正常

application.yml:配置腾讯云服务API密钥(secretId、secretKey)

考虑安全问题,如果是单独测试可考虑创建一个临时的访问凭据,避免密钥泄露导致不可预测的安全问题

# 腾讯云COS
txCloud:
  dev-COS:
    appId: xxx
    secretId: xxxx
    secretKey: xxxx
    bucket: example-bucket

创建测试类测试腾讯云COS连接(获取所有存储桶信息)

import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.model.Bucket;
import com.qcloud.cos.region.Region;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
public class TxCloudTest {

    @Value("${txCloud.dev-COS.secretId}")
    private String secretId;

    @Value("${txCloud.dev-COS.secretKey}")
    private String secretKey;

    @Value("${txCloud.dev-COS.appId}")
    private String appId;

    @Value("${txCloud.dev-COS.bucket}")
    private String bucket;

    // cos客户端定义
    private COSClient cosClient;

    /**
     * 测试腾讯云COS服务
     */
    @Test
    public void testGetBucket() {
        // 初始化用户身份信息(secretId, secretKey)
        COSCredentials cred = new BasicCOSCredentials(secretId,secretKey);
        // 设置bucket的区域, COS地域的简称请参照 https://www.qcloud.com/document/product/436/6224
        ClientConfig clientConfig = new ClientConfig(new Region("ap-guangzhou"));
        // 生成cos客户端
        COSClient cosClient = new COSClient(cred, clientConfig);
        List<Bucket> buckets = cosClient.listBuckets();
        for (Bucket bucketElement : buckets) {
            String bucketName = bucketElement.getName();
            String bucketLocation = bucketElement.getLocation();
            System.out.println("存储桶"+bucketName+"-"+bucketLocation);
        }
    }

}

​ 测试testGetBucket查看控制台打印相关的存储桶信息

1.创建桶

​ SpringbootTest,测试方法将创建COS客户端对象抽离出来,随后直接通过客户端对象访问COS

​ 创建桶:需注意Bucket名称必须为小写(否则创建提示java.lang.IllegalArgumentException: Bucket name should not contain uppercase characters)

@SpringBootTest
public class TxCloudTest {

    @Value("${txCloud.dev-COS.secretId}")
    private String secretId;

    @Value("${txCloud.dev-COS.secretKey}")
    private String secretKey;

    @Value("${txCloud.dev-COS.appId}")
    private String appId;

    @Value("${txCloud.dev-COS.bucket}")
    private String bucket;

    // cos客户端定义
    private COSClient cosClient;

    /**
     * 初始化(每个测试方法执行前执行初始化)
     */
    @BeforeEach
    public void initClient(){
        // 初始化用户身份信息(secretId, secretKey)
        COSCredentials cred = new BasicCOSCredentials(secretId,secretKey);
        // 设置bucket的区域, COS地域的简称请参照 https://www.qcloud.com/document/product/436/6224
        ClientConfig clientConfig = new ClientConfig(new Region("ap-guangzhou"));
        // 生成cos客户端
        cosClient = new COSClient(cred, clientConfig);
    }

    /**
     * 测试腾讯云COS服务
     */
    @Test
    public void testGetBucket() {
        List<Bucket> buckets = cosClient.listBuckets();
        for (Bucket bucketElement : buckets) {
            String bucketName = bucketElement.getName();
            String bucketLocation = bucketElement.getLocation();
            System.out.println("存储桶:"+bucketName+"-"+bucketLocation);
        }
    }

    /**
     * 创建存储桶
     */
    @Test
    public void testCreateBucket() {
        String bucketName = bucket + "-" + appId; // 存储桶名称,格式:Bucket-APPID
        CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
        // 设置 bucket 的权限为 Private(私有读写), 其他可选有公有读私有写, 公有读写
        createBucketRequest.setCannedAcl(CannedAccessControlList.Private);
        Bucket bucketResult = cosClient.createBucket(createBucketRequest);
    }

}

image-20240515104713803

2.上传指定对象到桶中

​ 将本地文件或者已知长度的输入流内容上传到 COS,适用于20M以下图片类小文件上传,最大支持上传不超过5GB文件。5GB以上的文件必须使用分块上传或高级 API 接口上传。(高级API接口在com.qcloud.cos.transfer.\* 子包下)

如果存在重复的key,则上传的时候会覆盖旧的对象,对象键(key)是对象在存储桶中的唯一标识(例如bucketName-AppId.cos.ap-guangzhou.myqcloud.com/folder/logo.jpg)

​ 上传不超过5GB的文件参考示例:

		/**
     * 上传指定对象
     */
    @Test
    public void uploadObj(){
        // 指定上传文件(例如此处上传一个照片)
        String  localFilePath = "/Users/xxxx/Desktop/mine/logo.jpg";
        // 指定要上传的文件
        File localFile = new File(localFilePath);
        // 指定文件将要存放的存储桶
        String bucketName = bucket + "-" + appId;
        // 对象key(存储桶的唯一标识):指定文件上传到 COS 上的路径,即对象键。例如此处设定表示将文件 logo.jpg 上传到 folder 路径下
        String key = "folder/logo.jpg";
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, localFile);
        // 执行文件上传操作
        PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);
        System.out.println(putObjectResult);
    }

3.查询对象列表

​ 查询对象列表数据

		/**
     * 查询对象列表
     */
    @Test
    public void getObj(){
        // Bucket 的命名格式为 Bucket-APPID ,此处填写的存储桶名称必须为此格式
        String bucketName = bucket + "-" + appId;
        ListObjectsRequest listObjectsRequest = new ListObjectsRequest();
        // 设置 bucket 名称
        listObjectsRequest.setBucketName(bucketName);
        // prefix 表示列出的 object 的 key 以 prefix 开始
        listObjectsRequest.setPrefix("folder/");
        // deliter 表示分隔符, 设置为/表示列出当前目录下的 object, 设置为空表示列出所有的 object
        listObjectsRequest.setDelimiter("/");
        // 设置最大遍历出多少个对象, 一次 listobject 最大支持1000
        listObjectsRequest.setMaxKeys(1000);
        ObjectListing objectListing = null;
        do {
            try {
                objectListing = cosClient.listObjects(listObjectsRequest);
            } catch (CosServiceException e) {
                e.printStackTrace();
                return;
            } catch (CosClientException e) {
                e.printStackTrace();
                return;
            }
            // common prefix 表示被 delimiter 截断的路径, 如 delimter 设置为/, common prefix 则表示所有子目录的路径
            List<String> commonPrefixs = objectListing.getCommonPrefixes();

            // object summary 表示所有列出的 object 列表
            List<COSObjectSummary> cosObjectSummaries = objectListing.getObjectSummaries();
            for (COSObjectSummary cosObjectSummary : cosObjectSummaries) {
                // 文件的路径 key
                String key = cosObjectSummary.getKey();
                // 文件的 etag
                String etag = cosObjectSummary.getETag();
                // 文件的长度
                long fileSize = cosObjectSummary.getSize();
                // 文件的存储类型
                String storageClasses = cosObjectSummary.getStorageClass();
                System.out.println("对象:" + key);
            }

            String nextMarker = objectListing.getNextMarker();
            listObjectsRequest.setMarker(nextMarker);
        } while (objectListing.isTruncated());
    }

4.下载对象

​ 下载对象有两种方式:获取下载对象的CRC64(对象流)、直接下载到本地

		/**
     * 下载对象(方式1)
     */
    @Test
    public void downloadObj01() throws IOException {
        // Bucket 的命名格式为 BucketName-APPID ,此处填写的存储桶名称必须为此格式
        String bucketName = bucket + "-" + appId;
       // 指定文件在 COS 上的路径(对象键)例如对象键为 folder/logo.jpg,则表示下载的文件 logo.jpg 在 folder 路径下
        String key = "folder/logo.jpg";
        // 获取下载输入流
        GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, key);
        COSObject cosObject = cosClient.getObject(getObjectRequest);
        COSObjectInputStream cosObjectInput = cosObject.getObjectContent();
        // 下载对象的 CRC64
        String crc64Ecma = cosObject.getObjectMetadata().getCrc64Ecma();
        System.out.println("对象流:" + crc64Ecma);
        // 关闭输入流
        cosObjectInput.close();
    }


    /**
     * 下载对象(方式2)
     */
    @Test
    public void downloadObj02(){
        // Bucket 的命名格式为 Bucket-APPID ,此处填写的存储桶名称必须为此格式
        String bucketName = bucket + "-" + appId;
        // 指定文件在 COS 上的路径(对象键)例如对象键为 folder/logo.jpg,则表示下载的文件 logo.jpg 在 folder 路径下
        String key = "folder/logo.jpg";

        // 下载文件到本地的路径,例如 把文件下载到本地的指定路径下的文件夹中(指定下载对象)
        GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, key);
        String outputFilePath = "/Users/holic-x/Desktop/mine/newLogo.jpg";
        File downFile = new File(outputFilePath);
        getObjectRequest = new GetObjectRequest(bucketName, key);
        ObjectMetadata downObjectMeta = cosClient.getObject(getObjectRequest, downFile);
    }

5.删除对象

		/**
     * 删除对象(根据key值删除指定对象)
     */
    @Test
    public void delObj(){
        // Bucket 的命名格式为 BucketName-APPID ,此处填写的存储桶名称必须为此格式
        String bucketName = "example-bucket-" + appId;
        String key = "folder/logo.jpg";
        cosClient.deleteObject(bucketName, key);
    }

6.删除桶

		/**
     * 删除桶
     */
    @Test
    public void delBucket(){
        // Bucket 的命名格式为 BucketName-APPID ,此处填写的存储桶名称必须为此格式
        String bucketName = "example-bucket-" + appId;
        cosClient.deleteBucket(bucketName);
    }

需注意,存储桶的权限开放,如果默认是私有读写,则上传的文件会带sign后缀,直接通过url不允许方法

如果希望通过url访问,访问失败则考虑是否开设了访问权限,其次就算开设了存储桶访问权限,一些通过私有读写上传的文件也是不能直接访问的(需要设定sign签名认证通过之后才可以访问);其次确认是否设定了防盗链。(如果设定防盗链,则不允许直接访问图片url)

针对域名映射,如果不希望存储桶信息暴露在外部,则可创建域名进行映射,进而隐藏真正的存储桶信息,保护个人系统

文件上传后端处理:

  • 结合腾讯云cos 需要将上传的文件进行暂存(有多种方式,最基础的就是先暂存到一个地方然后等到对接cos完毕之后再清理临时文件。或者借助第三方工具进行构建)

文件上传前端的现存问题:

通过action上传不带cookie(参考bi智能分析相关内容,文件上传部分看是如何处理)

customRequestopen in new window(无法带指定参数),没有可行案例,待定

评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v3.1.3