调用天翼云的对象存储ZOS,很详细

调用天翼云的对象存储ZOS,很详细

一、前言

最近要用到天翼云的对象存储ZOS,这里做个记录。

二、过程

先查询文档

1、获得 AccessKey 与 SecretKey

注意

如果 SecretKey 忘了或者弄丢了,可以把 AccessKey 删除重新生成时查看,再做保存

2、安装依赖

可以到这里下载

下载下来有五个包,这里安装这三个就行

依赖是本地依赖,可以将 jar 包导入项目,或者使用 maven 命令安装到本地,这里选择后者

解压后的jar包放在

D:\tmp\tianyiyun\zos

所以我的安装命令为

powershell 复制代码
mvn install:install-file -Dfile=D:/tmp/tianyiyun/zos/aws-java-sdk-iam-1.11.998.jar -DgroupId=com.amazonaws -DartifactId=aws-java-sdk-iam -Dversion=1.11.998 -Dpackaging=jar
powershell 复制代码
mvn install:install-file -Dfile=D:/tmp/tianyiyun/zos/zos-java-sdk-s3.jar -DgroupId=com.amazonaws -DartifactId=zos-java-sdk-s3 -Dversion=1.11.998 -Dpackaging=jar
powershell 复制代码
mvn install:install-file -Dfile=D:/tmp/tianyiyun/zos/zos-java-sdk-sts.jar -DgroupId=com.amazonaws -DartifactId=zos-java-sdk-sts -Dversion=1.11.998 -Dpackaging=jar

win + R ,再输入cmd执行

其他两个也是一样

然后在项目中引入依赖

powershell 复制代码
<!--天翼云对象存储ZOS相关依赖,这个是本地依赖-->
<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-java-sdk-iam</artifactId>
    <version>1.11.998</version>
</dependency>

<!--天翼云对象存储ZOS相关依赖,这个是本地依赖-->
<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>zos-java-sdk-s3</artifactId>
    <version>1.11.998</version>
</dependency>

<!--天翼云对象存储ZOS相关依赖,这个是本地依赖-->
<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>zos-java-sdk-sts</artifactId>
    <version>1.11.998</version>
</dependency>

3、查询文档

文档可以在这里下载

文档是这样的

4、测试

需要开发哪个接口查询文档对应内容即可,这里以上传文件为例

这里对官方的案例做了些修改,这里只是片段,完整的代码在工具类那里

三、工具类

1、配置类

java 复制代码
import lombok.Data;

/**
 * 天翼云ZOS相关配置
 *
 * @author: gan
 * @date: 2026-10-15 11:40
 */
@Data
public class TianyiyunZOSConfig {

    /**
     * 访问秘钥AccessKey
     */
    private String accessKey;

    /**
     * 访问秘钥SecretKey
     */
    private String secretKey;

    /**
     * 查询终端节点
     */
    private String endPoint;

    /**
     * 桶
     */
    private String bucket;

    /**
     * 自定义域名
     */
    private String customUrl;

    /**
     * AmazonS3枚举
     */
    private String signerOverride;
}

2、请求参数

java 复制代码
import lombok.Data;

import java.io.File;
import java.io.InputStream;

/**
 * 天翼云ZOS请求参数
 *
 * @author: gan
 * @date: 2026-10-16 08:47
 */
@Data
public class ZOSParam {
    /**
     * bucket名称
     */
    private String bucketName;

    /**
     * 对象名称
     *
     * 对应天翼云的key
     * 天翼云的key就是对象名称,上传到zos的地址:桶 + objectName(key)
     */
    private String objectName;

    /**
     * 文件流
     */
    private InputStream inputStream;

    /**
     * 文件
     */
    private File file;

    /**
     * 文件路径
     */
    private String filePath;

    /**
     * 文件类型
     *
     * 上传文件最好传一下,不然文件不能直接访问
     */
    private String contentType;
}

3、枚举类

(1)、天翼云请求签名格式

java 复制代码
/**
 * 天翼云请求签名格式
 *
 * @author: gan
 * @date: 2026-10-16 09:11
 */
public enum TianyiyunZOSSignerOverrideEnum {
    S3SignerType("S3SignerType", "V2签名"),
    AWSS3V4SignerType("AWSS3V4SignerType", "V4签名");

    private String code;
    private String desc;

    TianyiyunZOSSignerOverrideEnum(String code, String desc) {
        this.code = code;
        this.desc = desc;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getDesc() {
        return desc;
    }

    public static String getDesc(String code) {
        for (TianyiyunZOSSignerOverrideEnum value : values()) {
            if (value.code.equals(code)) {
                return value.desc;
            }
        }
        throw new RuntimeException("未知天翼云请求签名格式:" + code);
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }
}

(2)、文件ContentType

java 复制代码
/**
 * 文件信息contentType枚举类
 *
 * @author:gan
 * @date: 2025-02-27 11:08
 */
public enum FileContentTypeEnum {

    DEFAULT("default","application/octet-stream"),
    PNG("png", "image/png"),
    PDF("pdf", "application/pdf"),
    JPEG("jpeg", "image/jpeg"),
    JPG("jpg", "image/jpeg"),
    GIF("gif", "image/gif"),
    WBMP("wbmp", "image/vnd.wap.wbmp"),
    TIFF("tiff", "image/tiff"),
    JFIF("jfif", "image/jpeg"),
    TIF("tif", "image/tiff"),
    FAX("fax", "image/fax"),
    JPE("jpe", "image/jpeg"),
    NET("net", "image/pnetvue"),
    RP("rp", "image/vnd.rn-realpix"),
    ICO("ico", "image/x-icon");

    private String prefix;  //文件后缀
    private String type;  //文件类型

    FileContentTypeEnum(String prefix, String type) {
        this.prefix = prefix;
        this.type = type;
    }

    public String getPrefix() {
        return prefix;
    }

    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }

    public String getType() {
        return type;
    }

    public static String getType(String prefix) {
        for (FileContentTypeEnum value :values()) {
            if (prefix.equalsIgnoreCase(value.prefix)) {
                return value.type;
            }
        }
        throw new RuntimeException("未知文件后缀:" + prefix);
    }

    public void setType(String type) {
        this.type = type;
    }
}

4、工具类(重要)

java 复制代码
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import cn.hutool.core.io.FileUtil;
import com.alibaba.fastjson.JSONObject;
import com.amazonaws.ClientConfiguration;
import com.amazonaws.HttpMethod;
import com.amazonaws.Protocol;
import com.amazonaws.auth.AWSCredentials;
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.zdky.tpl.common.utils.VerifyUtil;
import com.zdky.tpl.enums.FileContentTypeEnum;
import com.zdky.tpl.tianyiyun.zos.dto.TianyiyunZOSConfig;
import com.zdky.tpl.tianyiyun.zos.dto.ZOSParam;
import com.zdky.tpl.tianyiyun.zos.enums.TianyiyunZOSSignerOverrideEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Instant;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * 天翼云ZOS工具类
 *
 * @author: gan
 * @date: 2026-10-15 09:52
 */
public class TianyiyunZOSUtil {

    private static final Logger log = LoggerFactory.getLogger(TianyiyunZOSUtil.class);

    /**
     * 这部分静态代码块用来降低 org.apache.http、com.amazonaws 包的日志级别,调试时可以将其注释
     */
    static {
        // 获取 Logback 的 LoggerContext
        LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
        // 设置 org.apache.http 包的日志级别为 WARN
        loggerContext.getLogger("org.apache.http").setLevel(Level.WARN);

        // 设置 com.amazonaws 包的日志级别为 ERROR
        loggerContext.getLogger("com.amazonaws").setLevel(Level.ERROR);
    }

    public static void main(String[] args) {

        TianyiyunZOSConfig config = new TianyiyunZOSConfig();
        config.setAccessKey("你的AccessKey");
        config.setSecretKey("你的SecretKey");
        config.setEndPoint("你的EndPoint");
        config.setBucket("你的桶名");
        config.setCustomUrl("你的自定义域名");

//        //============================上传文件 接口测试 start================================
//        config.setCustomUrl(null);  //上传文件时不能传自定义域名,不然可能导致出现增加以桶名为文件名的情况
//        config.setSignerOverride(TianyiyunZOSSignerOverrideEnum.AWSS3V4SignerType.getCode());
//        ZOSParam putObjectZOSParam = new ZOSParam();
//        putObjectZOSParam.setFilePath("/tmp/images/cat.jpg");
//        putObjectZOSParam.setObjectName("other/cat.jpg");
//        putObjectZOSParam.setContentType(""); //文件类型建议自己传
//        TianyiyunZOSUtil.putObject(config, putObjectZOSParam);
//        //============================上传文件 接口测试 end================================

//        //============================查询文件 接口测试 start================================
//        config.setSignerOverride(TianyiyunZOSSignerOverrideEnum.AWSS3V4SignerType.getCode());
//        ZOSParam getObjectZOSParam = new ZOSParam();
//        getObjectZOSParam.setObjectName("other/cat.jpg");
//        ObjectMetadata getObjectMetadata = TianyiyunZOSUtil.getObject(config, getObjectZOSParam);
//        System.out.println(JSONObject.toJSONString(getObjectMetadata));
//        //============================查询文件 接口测试 end================================

//        //============================删除文件 接口测试 start================================
//        config.setSignerOverride(TianyiyunZOSSignerOverrideEnum.AWSS3V4SignerType.getCode());
//        ZOSParam deleteObjectZOSParam = new ZOSParam();
//        deleteObjectZOSParam.setObjectName("other/cat.jpg");
//        TianyiyunZOSUtil.deleteObject(config, deleteObjectZOSParam);
//        //============================删除文件 接口测试 end================================

//        //============================生成访问地址 接口测试 start================================
//        //config.setCustomUrl(null);
//        config.setSignerOverride(TianyiyunZOSSignerOverrideEnum.S3SignerType.getCode());
//        ZOSParam generatePresignedUrlZOSParam = new ZOSParam();
//        generatePresignedUrlZOSParam.setObjectName("other/cat.jpg");
//        String generatePresignedUrl = TianyiyunZOSUtil.generatePresignedUrl(config, generatePresignedUrlZOSParam);
//        System.out.println("generatePresignedUrl:" + generatePresignedUrl);
//        //============================生成访问地址 接口测试 end================================
    }

    /**
     * 初始化AmazonS3客户端
     * @param config ZOS配置
     * @return  AmazonS3客户端
     */
    public static AmazonS3 getS3Client(TianyiyunZOSConfig config) {
        List<String> noEmptyFieldList = Arrays.asList("accessKey", "secretKey",  "endPoint", "bucket", "signerOverride");
        VerifyUtil.checkBeanByNonEmptyFiledList(config, noEmptyFieldList, "天翼云ZOS配置的");

        String endPoint = config.getEndPoint();
        String customUrl = config.getCustomUrl();
        if (VerifyUtil.isNotEmpty(customUrl)) {
            endPoint = customUrl;
        }

        AWSCredentials credentials = new BasicAWSCredentials(config.getAccessKey(), config.getSecretKey());
        ClientConfiguration awsClientConfig = new ClientConfiguration();
        awsClientConfig.setSignerOverride(config.getSignerOverride());
        awsClientConfig.setProtocol(Protocol.HTTP);
        return AmazonS3ClientBuilder.standard()
                //创建上传链接并上传对象
                .withCredentials(new AWSStaticCredentialsProvider(credentials))
                .withClientConfiguration(awsClientConfig)
                .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endPoint, ""))
                .disableChunkedEncoding()
                //.enablePathStyleAccess()  //这个去掉就可以用自定义的域名,且桶名放在子域名部分,即 https://桶名.hubei-41.zos.ctyun.cn,如果不打注释,返回域名就是 https://hubei-41.zos.ctyun.cn/桶名/文件
                .build();
    }

    /**
     * 上传对象
     * @param config 天翼云ZOS配置
     * @param params  ZOS参数
     */
    public static void putObject(TianyiyunZOSConfig config, ZOSParam params) {
        //上传文件
        AmazonS3 s3Client = null;
        String bucket = config.getBucket();
        String filepath = params.getFilePath();
        InputStream inputStream = params.getInputStream();
        String Key = params.getObjectName();
        String contentType = params.getContentType();
        try {
            VerifyUtil.checkParam(Key, "对象名称不能为空!");
            if (Key.startsWith("/")) {
                throw new RuntimeException("对象名称不能以[/]开头");
            }

            s3Client = getS3Client(config);
            log.info("putObject connect success");
            // 上传 Object
            if (VerifyUtil.isNotEmpty(filepath)) {
                Path path = Paths.get(filepath);
                inputStream = Files.newInputStream(path);
            } else if (VerifyUtil.isNotEmpty(inputStream)) {
            }

            if (VerifyUtil.isEmpty(contentType)) {
                if (VerifyUtil.isNotEmpty(filepath)) {
                    contentType = FileUtil.getMimeType(filepath);
                } else if (VerifyUtil.isNotEmpty(inputStream)) {
                    java.lang.String suffix = FileUtil.extName(Key);
                    contentType = FileContentTypeEnum.getType(suffix);
                }
            }

            log.info("putObject bucket: {} , key: {} , content-type: {}", bucket, Key, contentType);

            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentType(contentType);

            PutObjectRequest request = new PutObjectRequest(bucket, Key, inputStream, metadata);
            //request.setCannedAcl(CannedAccessControlList.PublicRead);  //默认是私有,这里设置为公共读

            PutObjectResult result = s3Client.putObject(request);
            log.info("putObject ETag: {}, VersionId: {}", result.getETag(), result.getVersionId());
            log.info("putObject request success");
        } catch (Exception e) {
            e.printStackTrace();

            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 获得对象
     * @param config 天翼云ZOS配置
     * @param params  ZOS参数
     */
    public static ObjectMetadata getObject(TianyiyunZOSConfig config, ZOSParam params) {
        //获得文件
        AmazonS3 s3Client = null;
        String bucket = config.getBucket();
        String Key = params.getObjectName();
        try {
            s3Client = getS3Client(config);
            log.info("getObject connect success");

            GetObjectMetadataRequest var = new GetObjectMetadataRequest(config.getBucket(), Key);
            ObjectMetadata meta = s3Client.getObjectMetadata(var);
            log.info("getObject bucket: {} , content-type: {} , content-length: {}", bucket, meta.getContentType(), meta.getContentLength());
            log.info("getObject request success");
            return meta;
        }catch (Exception e) {
            e.printStackTrace();

            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 删除对象
     * @param config 天翼云ZOS配置
     * @param params  ZOS参数
     */
    public static void deleteObject(TianyiyunZOSConfig config, ZOSParam params) {
        //删除文件
        AmazonS3 s3Client = null;
        String bucket = config.getBucket();
        String Key = params.getObjectName();
        try {
            s3Client = getS3Client(config);
            log.info("deleteObject connect success");

            DeleteObjectRequest var = new DeleteObjectRequest(config.getBucket(), Key);
            s3Client.deleteObject(var);
            log.info("deleteObject bucket: {} , key: {}", bucket, Key);
            log.info("deleteObject request success");
        }catch (Exception e) {
            e.printStackTrace();

            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 获取访问地址
     * @param config 天翼云ZOS配置
     * @param params  ZOS参数
     */
    public static String generatePresignedUrl(TianyiyunZOSConfig config, ZOSParam params) {
        //删除文件
        AmazonS3 s3Client = null;
        String bucket = config.getBucket();
        String endPoint = config.getEndPoint();
        String customUrl = config.getCustomUrl();
        String Key = params.getObjectName();
        try {
            s3Client = getS3Client(config);
            log.info("generatePresignedUrl connect success");

            //获取预签名Url
            GeneratePresignedUrlRequest var = new GeneratePresignedUrlRequest(config.getBucket(), Key);
            Date expiration = new Date();
            long expTimeMillis = Instant.now().toEpochMilli();
            expTimeMillis += 1000 * 60 * 60 * 24 * 7;
            // 设置有效期60分钟
            expiration.setTime(expTimeMillis);
            var.setExpiration(expiration);
            var.setMethod(HttpMethod.GET);
            URL url = s3Client.generatePresignedUrl(var);

            log.info("generatePresignedUrl bucket: {} , key: {}", bucket, Key);
            log.info("generatePresignedUrl request success");

            String temptUrl = url.toString();
            if (VerifyUtil.isNotEmpty(customUrl)) {
                final String slash = "/";
                final String dot = ".";
                customUrl = customUrl.endsWith(slash) ? customUrl.substring(0, customUrl.length() - 1) : customUrl;

                temptUrl = temptUrl.replace(bucket + dot, ""); //去掉url中的桶名
                temptUrl = temptUrl.replace(endPoint, customUrl); //将url的域名换为自定义域名
            }
            return temptUrl;
        }catch (Exception e) {
            e.printStackTrace();

            throw new RuntimeException(e.getMessage());
        }
    }
}
相关推荐
JulyLi20191 小时前
yolo检测适配昇腾Atlas300IDuo笔记
yolo·1024程序员节
遇雪长安1 小时前
MCU 固件启动即崩,bootloader 如何发现
1024程序员节
若亦_1 小时前
数据结构>>优先级队列(堆)
java·数据结构
Zevalin爱灰灰1 小时前
Linux入门第一部分(Ubuntu入门篇) 第二章 浅尝Ubuntu(二)
linux·嵌入式·1024程序员节
泡海椒1 小时前
JQuick-SQL REST API 数据接入:应用层调用接口后注册分析表
数据库·sql·1024程序员节
_MH88881 小时前
2026.10.24|距离上一次写 CSDN,刚好过去了一年
1024程序员节
XIU YUAN1 小时前
ESP32-C6 专业游戏合集系统 - 打造你的掌上游戏机
1024程序员节
程序猿乐锅1 小时前
【从0-1学习Python | 第七篇】Python 面向对象基础
开发语言·笔记·后端·python·学习·1024程序员节