AWS S3 协议对接 minio/oss 等

这篇具有很好参考价值的文章主要介绍了AWS S3 协议对接 minio/oss 等。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

使用亚马逊 S3 协议访问对象存储
[s3-API](https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/API/API_Operations_Amazon_Simple_Storage_Service.html)

- 兼容S3协议的对象存储有
  - minio
    - 似乎是完全兼容 [兼容文档](https://www.minio.org.cn/product/s3-compatibility.html)
  - 阿里云oss
    - [兼容主要的 API ](https://help.aliyun.com/zh/oss/developer-reference/compatibility-with-amazon-s3?spm=a2c4g.11186623.0.0.590b32bcHb4D6a)
  - 七牛云oss
  - 等等

依赖

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--使用的依赖-->
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-java-sdk-s3</artifactId>
            <version>1.12.522</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.12.0</version>
        </dependency>


    </dependencies>

读取配置

package com.xx.awss3demo.config;

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

@Data
@ConfigurationProperties(prefix = "s3")
@Component
public class S3Properties {
    /**
     * 对象存储服务的URL
     */
    private String endpoint;


    /**
     *  path-style nginx 反向代理和S3默认支持
     * 模式 {http://bucketname.endpoint}  -- true
     * 模式 {http://endpoint/bucketname}  -- false
     */
    private Boolean pathStyleAccess = false;

    /**
     * 区域
     */
    private String region;

    /**
     * Access key就像用户ID,可以唯一标识你的账户
     */
    private String accessKey;

    /**
     * Secret key是你账户的密码
     */
    private String secretKey;

    /**
     * 最大线程数,默认: 100
     */
    private Integer maxConnections = 50;


}

配置文件

server:
  port: 8888

s3:
  # aliyun oss
  #endpoint: http://oss-cn-shanghai.aliyuncs.com
  #accessKey: 
  #secretKey: 
  # minio
  endpoint: http://192.168.1.1:9000
  accessKey: admin
  secretKey: admin1234
  bucketName: lqs3bucket
  region:
  maxConnections: 100

文件操作

package com.xx.awss3demo.service;

import com.amazonaws.ClientConfiguration;
import com.amazonaws.ClientConfigurationFactory;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.*;
import com.amazonaws.util.IOUtils;
import com.liuqi.awss3demo.config.S3Properties;
import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import java.io.*;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@ConditionalOnClass(S3Properties.class)
@Service
@Log4j2
public class S3FileService {

    @Autowired
    private S3Properties s3Properties;

    private AmazonS3 amazonS3;

    @PostConstruct
    public void init() {
        log.info(s3Properties);
        amazonS3 = AmazonS3ClientBuilder.standard()
                .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(s3Properties.getAccessKey(), s3Properties.getSecretKey())))
                .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(
                        s3Properties.getEndpoint(),
                        s3Properties.getRegion()))
                .withPathStyleAccessEnabled(s3Properties.getPathStyleAccess())
                .withChunkedEncodingDisabled(true)
                .withClientConfiguration(new ClientConfiguration()
                        .withMaxConnections(s3Properties.getMaxConnections())
                        .withMaxErrorRetry(1))
                .build();
    }

    /**
     * 创建bucket
     * 注意:bucket name 不允许有特殊字符及大写字母
     *
     * @param bucketName bucket名称
     * @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CreateBucket">AWS API
     * Documentation</a>
     */
    @SneakyThrows
    public void createBucket(String bucketName) {
        if (!bucketName.toLowerCase().equals(bucketName)) {
            throw new RuntimeException("bucket name not allow upper case");
        }
        if (checkBucketExist(bucketName)) {
            log.info("bucket: {} 已经存在", bucketName);
            return;
        }
        amazonS3.createBucket((bucketName));
    }

    @SneakyThrows
    public boolean checkBucketExist(String bucketName) {
        return amazonS3.doesBucketExistV2(bucketName);
    }

    /**
     * 获取全部bucket
     * <p>
     *
     * @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBuckets">AWS
     * API Documentation</a>
     */

    @SneakyThrows
    public List<Bucket> getAllBuckets() {
        return amazonS3.listBuckets();
    }

    /**
     * 根据bucket获取bucket详情
     *
     * @param bucketName bucket名称
     * @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListBuckets">AWS
     * API Documentation</a>
     */

    @SneakyThrows
    public Optional<Bucket> getBucket(String bucketName) {
        return amazonS3.listBuckets().stream().filter(b -> b.getName().equals(bucketName)).findFirst();
    }

    /**
     * @param bucketName bucket名称
     * @see <a href=
     * "http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteBucket">AWS API
     * Documentation</a>
     */

    @SneakyThrows
    public void removeBucket(String bucketName) {
        amazonS3.deleteBucket(bucketName);
    }

    /**
     * 复制文件
     * @param bucketName
     * @param srcObjectName
     * @param tarObjectName
     */
    public void copyObject(String bucketName, String srcObjectName,String tarObjectName){
        amazonS3.copyObject(bucketName,srcObjectName,bucketName,tarObjectName);
    }

    /**
     * 上传文件,指定文件类型
     *
     * @param bucketName  bucket名称
     * @param objectName  文件名称
     * @param stream      文件流
     * @param contextType 文件类型
     * @throws Exception
     */

    @SneakyThrows
    public void putObject(String bucketName, String objectName, InputStream stream,
                          String contextType) {
        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentLength(stream.available());
        objectMetadata.setContentType(contextType);
        putObject(bucketName, objectName, stream, objectMetadata);
    }

    /**
     * 上传文件
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @param stream     文件流
     * @throws Exception
     */
    @SneakyThrows
    public void putObject(String bucketName, String objectName, InputStream stream) {
        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentLength(stream.available());
        objectMetadata.setContentType("application/octet-stream");
        putObject(bucketName, objectName, stream, objectMetadata);
    }

    /**
     * 上传文件
     *
     * @param bucketName     bucket名称
     * @param objectName     文件名称
     * @param stream         文件流
     * @param objectMetadata 对象元数据
     * @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/PutObject">AWS
     * API Documentation</a>
     */

    @SneakyThrows
    private PutObjectResult putObject(String bucketName, String objectName, InputStream stream,
                                      ObjectMetadata objectMetadata) {
        byte[] bytes = IOUtils.toByteArray(stream);
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        // 上传
        return amazonS3.putObject(bucketName, objectName, byteArrayInputStream, objectMetadata);
    }


    /**
     * 判断object是否存在
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObject">AWS
     * API Documentation</a>
     */
    @SneakyThrows
    public boolean checkObjectExist(String bucketName, String objectName) {
        return amazonS3.doesObjectExist(bucketName, objectName);
    }


    /**
     * 获取文件
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @return 二进制流
     * @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/GetObject">AWS
     * API Documentation</a>
     */

    @SneakyThrows
    public S3Object getObject(String bucketName, String objectName) {
        return amazonS3.getObject(bucketName, objectName);
    }

    /**
     * 删除文件
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @throws Exception
     * @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/DeleteObject">AWS
     * API Documentation</a>
     */

    @SneakyThrows
    public void deleteObject(String bucketName, String objectName) {
        amazonS3.deleteObject(bucketName, objectName);
    }

    /**
     * 大文件分段上传
     *
     * @param file        MultipartFile
     * @param bucketName  bucketName
     * @param objectName  objectName
     * @param minPartSize 每片大小,单位:字节(eg:5242880 <- 5m)
     */

    public void uploadMultipartFileByPart(MultipartFile file, String bucketName, String objectName,
                                          int minPartSize) {
        if (file.isEmpty()) {
            log.error("file is empty");
        }
        // 计算分片大小
        long size = file.getSize();
        // 得到总共的段数,和 分段后,每个段的开始上传的字节位置
        List<Long> positions = Collections.synchronizedList(new ArrayList<>());
        long filePosition = 0;
        while (filePosition < size) {
            positions.add(filePosition);
            filePosition += Math.min(minPartSize, (size - filePosition));
        }
        if (log.isDebugEnabled()) {
            log.debug("总大小:{},分为{}段", size, positions.size());
        }

        // 创建一个列表保存所有分传的 PartETag, 在分段完成后会用到
        List<PartETag> partETags = Collections.synchronizedList(new ArrayList<>());

        // 第一步,初始化,声明下面将有一个 Multipart Upload
        // 设置文件类型
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentType(file.getContentType());

        InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(bucketName,
                objectName, metadata);
        InitiateMultipartUploadResult initResponse = this.initiateMultipartUpload(initRequest);
        if (log.isDebugEnabled()) {
            log.debug("开始上传");
        }
        //声明线程池
        ExecutorService exec = Executors.newFixedThreadPool(3);
        long begin = System.currentTimeMillis();
        try {
            // MultipartFile 转 File
            File toFile = multipartFileToFile(file);
            for (int i = 0; i < positions.size(); i++) {
                int finalI = i;
                exec.execute(() -> {
                    long time1 = System.currentTimeMillis();
                    UploadPartRequest uploadRequest = new UploadPartRequest()
                            .withBucketName(bucketName)
                            .withKey(objectName)
                            .withUploadId(initResponse.getUploadId())
                            .withPartNumber(finalI + 1)
                            .withFileOffset(positions.get(finalI))
                            .withFile(toFile)
                            .withPartSize(Math.min(minPartSize, (size - positions.get(finalI))));
                    // 第二步,上传分段,并把当前段的 PartETag 放到列表中
                    partETags.add(this.uploadPart(uploadRequest).getPartETag());
                    if (log.isDebugEnabled()) {
                        log.debug("第{}段上传耗时:{}", finalI + 1, (System.currentTimeMillis() - time1));
                    }
                });
            }
            //任务结束关闭线程池
            exec.shutdown();
            //判断线程池是否结束,不加会直接结束方法
            while (true) {
                if (exec.isTerminated()) {
                    break;
                }
            }

            // 第三步,完成上传,合并分段
            CompleteMultipartUploadRequest compRequest = new CompleteMultipartUploadRequest(
                    bucketName,
                    objectName,
                    initResponse.getUploadId(), partETags);
            this.completeMultipartUpload(compRequest);

            //删除本地缓存文件
            if (toFile != null && !toFile.delete()) {
                log.error("Failed to delete cache file");
            }
        } catch (Exception e) {
            this.abortMultipartUpload(
                    new AbortMultipartUploadRequest(bucketName, objectName,
                            initResponse.getUploadId()));
            log.error("Failed to upload, " + e.getMessage());
        }
        if (log.isDebugEnabled()) {
            log.debug("总上传耗时:{}", (System.currentTimeMillis() - begin));
        }
    }

    /**
     * 根据文件前置查询文件集合
     *
     * @param bucketName bucket名称
     * @param prefix     前缀
     * @param recursive  是否递归查询
     * @return S3ObjectSummary 列表
     * @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjects">AWS
     * API Documentation</a>
     */

    @SneakyThrows
    public List<S3ObjectSummary> getAllObjectsByPrefix(String bucketName, String prefix,
                                                       boolean recursive) {
        ObjectListing objectListing = amazonS3.listObjects(bucketName, prefix);
        return new ArrayList<>(objectListing.getObjectSummaries());
    }

    /**
     * 查询文件版本
     *
     * @param bucketName bucket名称
     * @return S3ObjectSummary 列表
     * @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/ListObjects">AWS
     * API Documentation</a>
     */

    @SneakyThrows
    public List<S3VersionSummary> getAllObjectsVersionsByPrefixV2(String bucketName,
                                                                  String objectName) {
        VersionListing versionListing = amazonS3.listVersions(bucketName, objectName);
        return new ArrayList<>(versionListing.getVersionSummaries());
    }

    /**
     * 获取文件外链
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @param expires    过期时间 <=7 单位天
     * @return url
     */

    @SneakyThrows
    public String generatePresignedUrl(String bucketName, String objectName, Integer expires) {
        Date date = new Date();
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, expires);
        URL url = amazonS3.generatePresignedUrl(bucketName, objectName, calendar.getTime());
        return url.toString();
    }

    /**
     * 开放链接,默认public没有设置访问权限
     * url 规则:${endPoint}/${bucketName}/${objectName}
     *
     * @param bucketName
     * @param objectName
     * @return
     */
    public String generatePublicUrl(String bucketName, String objectName) {
        return s3Properties.getEndpoint() + "/" + bucketName + "/" + objectName;
    }

    /**
     * 初始化,声明有一个Multipart Upload
     *
     * @param initRequest 初始化请求
     * @return 初始化返回
     */
    private InitiateMultipartUploadResult initiateMultipartUpload(
            InitiateMultipartUploadRequest initRequest) {
        return amazonS3.initiateMultipartUpload(initRequest);
    }

    /**
     * 上传分段
     *
     * @param uploadRequest 上传请求
     * @return 上传分段返回
     * @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/UploadPart">AWS
     * API Documentation</a>
     */
    private UploadPartResult uploadPart(UploadPartRequest uploadRequest) {
        return amazonS3.uploadPart(uploadRequest);
    }

    /**
     * 分段合并
     *
     * @param compRequest 合并请求
     * @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/CompleteMultipartUpload">AWS
     * API Documentation</a>
     */
    private CompleteMultipartUploadResult completeMultipartUpload(
            CompleteMultipartUploadRequest compRequest) {
        return amazonS3.completeMultipartUpload(compRequest);
    }

    /**
     * 中止分片上传
     *
     * @param uploadRequest 中止文件上传请求
     * @see <a href="http://docs.aws.amazon.com/goto/WebAPI/s3-2006-03-01/AbortMultipartUpload">AWS
     * API Documentation</a>
     */
    private void abortMultipartUpload(AbortMultipartUploadRequest uploadRequest) {
        amazonS3.abortMultipartUpload(uploadRequest);
    }

    /**
     * MultipartFile 转 File
     */
    private File multipartFileToFile(MultipartFile file) throws Exception {
        File toFile = null;
        if (file.equals("") || file.getSize() <= 0) {
            file = null;
        } else {
            InputStream ins = null;
            ins = file.getInputStream();
            toFile = new File(file.getOriginalFilename());
            //获取流文件
            OutputStream os = new FileOutputStream(toFile);
            int bytesRead = 0;
            byte[] buffer = new byte[8192];
            while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.close();
            ins.close();
        }
        return toFile;
    }
}

测试方法文章来源地址https://www.toymoban.com/news/detail-640576.html

package com.xx.awss3demo;

import com.amazonaws.services.s3.model.S3Object;
import com.amazonaws.services.s3.model.S3ObjectSummary;
import com.liuqi.awss3demo.service.S3FileService;
import lombok.extern.log4j.Log4j2;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;

@SpringBootTest
@Log4j2
class AwsS3DemoApplicationTests {

    @Autowired
    private S3FileService s3FileService;

    public String bk="lqs3bucket";

    @Test
    void contextLoads() {
    }

    @Test
    public void bucketTest() {
        s3FileService.createBucket(bk);
        s3FileService.getAllBuckets().forEach(b -> System.out.println(b.getName()));
        s3FileService.removeBucket(bk);
    }

    @Test
    public void objectTest() throws IOException {
        s3FileService.createBucket(bk);
        if (s3FileService.checkObjectExist(bk, "d1/ss/1.txt")) {
            log.info("文件已经存在");
        }
        s3FileService.putObject(bk,"d1/ss/1.txt",new ByteArrayInputStream("hello world xxx".getBytes(StandardCharsets.UTF_8)));
        s3FileService.copyObject(bk,"d1/ss/1.txt","d1/ss/1_copy.txt");
        S3Object object = s3FileService.getObject(bk, "d1/ss/1_copy.txt");
        byte[] bytes = object.getObjectContent().readAllBytes();
        log.info("内容是:{}",new String(bytes,StandardCharsets.UTF_8));
        //s3FileService.deleteObject(bk,"1.txt");
    }

    @Test
    public void listTest(){
        List<S3ObjectSummary> objectList = s3FileService.getAllObjectsByPrefix(bk, "/d1", true);
        objectList.forEach(object->{
            log.info(object.getKey());
        });

    }

    @Test
    public void genUrlTest(){
        String s = s3FileService.generatePresignedUrl(bk, "1.txt", 7);
        System.out.println(s);
    }




}

到了这里,关于AWS S3 协议对接 minio/oss 等的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • [ 云计算 | AWS 实践 ] 基于 Amazon S3 协议搭建个人云存储服务

    本文收录于【#云计算入门与实践 - AWS】专栏中,收录 AWS 入门与实践相关博文。 本文同步于个人公众号:【 云计算洞察 】 更多关于云计算技术内容敬请关注:CSDN【#云计算入门与实践 - AWS】专栏。 本系列已更新博文: [ 云计算 | AWS 实践 ] Java 应用中使用 Amazon S3 进行存储桶

    2024年02月05日
    浏览(42)
  • Java AWS S3 文件上传实现

    Amazon S3(Simple Storage Service)是亚马逊云计算平台提供的一种对象存储服务,可以用于存储和检索任意类型的数据。在Java开发中,我们可以通过AWS SDK for Java来实现与Amazon S3的集成。 官方文档 https://docs.aws.amazon.com/zh_cn/sdk-for-java/v1/developer-guide/examples-s3.html 1. 配置maven依赖 2. 配置

    2024年02月21日
    浏览(42)
  • 基于java的 aws s3文件上传

    aws s3 文件上传代码 首先,确保您已经在AWS上创建了一个S3存储桶,并拥有相应的访问密钥和密钥ID。这些凭据将用于在Java代码中进行身份验证。 接下来,需要在Java项目中添加AWS SDK的依赖。可以使用Maven或Gradle进行依赖管理。以下是一个Maven的示例依赖项: 示例代码: 在上述

    2024年01月17日
    浏览(41)
  • [ 云计算 | AWS 实践 ] 使用 Java 列出存储桶中的所有 AWS S3 对象

    本文收录于【#云计算入门与实践 - AWS】专栏中,收录 AWS 入门与实践相关博文。 本文同步于个人公众号:【 云计算洞察 】 更多关于云计算技术内容敬请关注:CSDN【#云计算入门与实践 - AWS】专栏。 本系列已更新博文: [ 云计算 | AWS 实践 ] Java 应用中使用 Amazon S3 进行存储桶

    2024年02月06日
    浏览(49)
  • Java实现AWS S3 V4 Authorization自定义验证

    最近在开发文件存储服务,需要符合s3的协议标准,可以直接接入aws-sdk,本文针对sdk发出请求的鉴权信息进行重新组合再签名验证有效性,sdk版本如下 首先对V4版本签名算法的数据结构及签名流程进行拆解分析,以请求头签名为示例讲解 signature = doSign(waitSignString) waitSignStri

    2024年02月07日
    浏览(43)
  • AWS s3 使用教程,前后端Java+html开发教程

    目录 一、 AWS S3配置说明 1. S3 Bucket配置 1.1 ACL配置 1.2 存储桶策略配置 1.3 跨源资源共享配置 2. IAM配置 2.1 创建S3UploadPolicy策略 2.2 创建S3的Role 3. EC2配置 3.1 EC2添加role 二、S3 HTML+JAVA代码实现 三、AWS cloudfront 及Signed url 四、相关文档 S3 Bucket包括ACL配置、存储桶策略配置及跨源资

    2024年02月03日
    浏览(35)
  • [ 云计算 | AWS 实践 ] 使用 Java 更新现有 Amazon S3 对象

    本文收录于【#云计算入门与实践 - AWS】专栏中,收录 AWS 入门与实践相关博文。 本文同步于个人公众号:【 云计算洞察 】 更多关于云计算技术内容敬请关注:CSDN【#云计算入门与实践 - AWS】专栏。 本系列已更新博文: [ 云计算 | AWS 实践 ] Java 应用中使用 Amazon S3 进行存储桶

    2024年02月05日
    浏览(47)
  • [ 云计算 | AWS 实践 ] Java 如何重命名 Amazon S3 中的文件和文件夹

    本文收录于【#云计算入门与实践 - AWS】专栏中,收录 AWS 入门与实践相关博文。 本文同步于个人公众号:【 云计算洞察 】 更多关于云计算技术内容敬请关注:CSDN【#云计算入门与实践 - AWS】专栏。 本系列已更新博文: [ 云计算 | AWS 实践 ] Java 应用中使用 Amazon S3 进行存储桶

    2024年02月08日
    浏览(57)
  • [ 云计算 | AWS ] Java 应用中使用 Amazon S3 进行存储桶和对象操作完全指南

    本文收录于【#云计算入门与实践 - AWS】专栏中,收录 AWS 入门与实践相关博文。 本文同步于个人公众号:【 云计算洞察 】 更多关于云计算技术内容敬请关注:CSDN【#云计算入门与实践 - AWS】专栏。 本系列已更新博文: [ 云计算 | AWS 实践 ] Java 应用中使用 Amazon S3 进行存储桶

    2024年02月11日
    浏览(45)
  • [ 云计算 | AWS 实践 ] Java 应用中使用 Amazon S3 进行存储桶和对象操作完全指南

    本文收录于【#云计算入门与实践 - AWS】专栏中,收录 AWS 入门与实践相关博文。 本文同步于个人公众号:【 云计算洞察 】 更多关于云计算技术内容敬请关注:CSDN【#云计算入门与实践 - AWS】专栏。 本系列已更新博文: [ 云计算 | AWS 实践 ] Java 应用中使用 Amazon S3 进行存储桶

    2024年02月08日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包