调用天翼云的对象存储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());
}
}
}