@@ -2,73 +2,115 @@ package org.dromara.common.oss.core;
import cn.hutool.core.io.IoUtil ;
import cn.hutool.core.util.IdUtil ;
import com.amazonaws.ClientConfiguration ;
import com.amazonaws.HttpMethod ;
import com.amazonaws.Protocol ;
import com.amazonaws.auth.AWSCredentials ;
import com.amazonaws.auth.AWSCredentialsProvider ;
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.AmazonS3Client ;
import com.amazonaws.services.s3.AmazonS3ClientBuilder ;
import com.amazonaws.services.s3.model.* ;
import org.dromara.common.core.constant.Constants ;
import org.dromara.common.core.utils.DateUtils ;
import org.dromara.common.core.utils.StringUtils ;
import org.dromara.common.core.utils.file.FileUtils ;
import org.dromara.common.oss.constant.OssConstant ;
import org.dromara.common.oss.entity.UploadResult ;
import org.dromara.common.oss.enumd.AccessPolicyType ;
import org.dromara.common.oss.enumd.PolicyType ;
import org.dromara.common.oss.exception.OssException ;
import org.dromara.common.oss.properties.OssProperties ;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials ;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider ;
import software.amazon.awssdk.core.async.AsyncRequestBody ;
import software.amazon.awssdk.core.async.BlockingInputStreamAsyncRequestBody ;
import software.amazon.awssdk.regions.Region ;
import software.amazon.awssdk.services.s3.S3AsyncClient ;
import software.amazon.awssdk.services.s3.S3Configuration ;
import software.amazon.awssdk.services.s3.model.NoSuchBucketException ;
import software.amazon.awssdk.services.s3.model.S3Exception ;
import software.amazon.awssdk.services.s3.presigner.S3Presigner ;
import software.amazon.awssdk.transfer.s3.S3TransferManager ;
import software.amazon.awssdk.transfer.s3.model.* ;
import software.amazon.awssdk.transfer.s3.progress.LoggingTransferListener ;
import java.io.ByteArrayInputStream ;
import java.io.File ;
import java.io.IOException ;
import java.io.InputStream ;
import java.net.URI ;
import java.net.URL ;
import java.util.Date ;
import java.nio.file.Files ;
import java.nio.file.Path ;
import java.nio.file.Paths ;
import java.time.Duration ;
/**
* S3 存储协议 所有兼容S3协议的云厂商均支持
* 阿里云 腾讯云 七牛云 minio
*
* @author Lion Li
* @author AprilWind
*/
public class OssClient {
/**
* 服务商
*/
private final String configKey ;
/**
* 配置属性
*/
private final OssProperties properties ;
private final AmazonS3 client ;
/**
* Amazon S3 异步客户端
*/
private final S3AsyncClient client ;
/**
* 用于管理 S3 数据传输的高级工具
*/
private final S3TransferManager transferManager ;
/**
* AWS S3 预签名 URL 的生成器
*/
private final S3Presigner presigner ;
/**
* 构造方法
*
* @param configKey 配置键
* @param ossProperties Oss配置属性
*/
public OssClient ( String configKey , OssProperties ossProperties ) {
this . configKey = configKey ;
this . properties = ossProperties ;
try {
AwsClientBuilder . EndpointConfiguration endpointConfig =
new AwsClientBuilder . EndpointConfiguration ( properties . getEndpoint ( ) , properties . getRegion ( ) ) ;
// 创建 AWS 认证信息
StaticCredentialsProvider credentialsProvider = StaticCredentialsProvider . create (
AwsBasicCredentials . create ( properties . getAccessKey ( ) , properties . getSecretKey ( ) ) ) ;
AWSCredentials credentials = new BasicAWSCredentials ( properties . getAccessKey ( ) , properties . getSecretKey ( ) ) ;
AWSCredentialsProvider credentialsProvider = new AWSStaticCredentialsProvider ( credentials ) ;
ClientConfiguration clientConfig = new ClientConfiguration ( ) ;
if ( OssConstant . IS_HTTPS . equals ( properties . getIsHttps ( ) ) ) {
clientConfig . setProtocol ( Protocol . HTTPS ) ;
} else {
clientConfig . setProtocol ( Protocol . HTTP ) ;
}
AmazonS3ClientBuilder build = AmazonS3Client . builder ( )
. withEndpointConfiguration ( endpointConfig )
. withClientConfiguration ( clientConfig )
. withCredentials ( credentialsProvider )
. disableChunkedEncoding ( ) ;
if ( ! StringUtils . containsAny ( properties . getEndpoint ( ) , OssConstant . CLOUD_SERVICE ) ) {
//创建AWS基于 CRT 的 S3 客户端
this . client = S3AsyncClient . crtBuilder ( )
. credentialsProvider ( credentialsProvider )
. endpointOverride ( URI . create ( getEndpoint ( ) ) )
. region ( of ( ) )
. targetThroughputInGbps ( 20 . 0 )
. minimumPartSizeInBytes ( 10 * 1025 * 1024L )
. checksumValidationEnabled ( false )
. build ( ) ;
//AWS基于 CRT 的 S3 AsyncClient 实例用作 S3 传输管理器的底层客户端
this . transferManager = S3TransferManager . builder ( ) . s3Client ( this . client ) . build ( ) ;
// 检查是否连接到 MinIO, MinIO 使用 HTTPS 限制使用域名访问,需要启用路径样式访问
S3Configuration config = S3Configuration . builder ( ) . chunkedEncodingEnabled ( false )
// minio 使用https限制使用域名访问 需要此配置 站点填域名
build . enablePathStyleAccess ( ) ;
}
this . client = build . build ( ) ;
. pathStyleAccessEnabled ( ! StringUtils . containsAny ( properties . getEndpoint ( ) , OssConstant . CLOUD_SERVICE ) ) . build ( ) ;
// 创建 预签名 URL 的生成器 实例,用于生成 S3 预签名 URL
this . presigner = S3Presigner . builder ( )
. region ( of ( ) )
. credentialsProvider ( credentialsProvider )
. endpointOverride ( URI . create ( getDomain ( ) ) )
. serviceConfiguration ( config )
. build ( ) ;
// 创建存储桶
createBucket ( ) ;
} catch ( Exception e ) {
if ( e instanceof OssException ) {
@@ -78,126 +120,161 @@ public class OssClient {
}
}
/**
* 同步创建存储桶
* 如果存储桶不存在,会进行创建;如果存储桶存在,不执行任何操作
*
* @throws OssException 当创建存储桶时发生异常时抛出
*/
public void createBucket ( ) {
String bucketName = properties . getBucketName ( ) ;
try {
String bucketName = properties . getBucketName ( ) ;
if ( client . does BucketExistV2 ( bucketName ) ) {
return ;
// 尝试获取存储桶的信息
client . head Bucket(
x - > x . bucket ( bucketName )
. build ( ) )
. join ( ) ;
} catch ( Exception ex ) {
if ( ex . getCause ( ) instanceof NoSuchBucketException ) {
try {
// 存储桶不存在,尝试创建存储桶
client . createBucket (
x - > x . bucket ( bucketName ) )
. join ( ) ;
// 设置存储桶的访问策略( Bucket Policy)
client . putBucketPolicy (
x - > x . bucket ( bucketName )
. policy ( getPolicy ( bucketName , getAccessPolicy ( ) . getPolicyType ( ) ) ) )
. join ( ) ;
} catch ( S3Exception e ) {
// 存储桶创建或策略设置失败
throw new OssException ( " 创建Bucket失败, 请核对配置信息:[ " + e . getMessage ( ) + " ] " ) ;
}
} else {
throw new OssException ( " 判断Bucket是否存在失败, 请核对配置信息:[ " + ex . getMessage ( ) + " ] " ) ;
}
CreateBucketRequest createBucketRequest = new CreateBucketRequest ( bucketName ) ;
AccessPolicyType accessPolicy = getAccessPolicy ( ) ;
createBucketRequest . setCannedAcl ( accessPolicy . getAcl ( ) ) ;
client . createBucket ( createBucketRequest ) ;
client . setBucketPolicy ( bucketName , getPolicy ( bucketName , accessPolicy . getPolicyType ( ) ) ) ;
} catch ( Exception e ) {
throw new OssException ( " 创建Bucket失败, 请核对配置信息:[ " + e . getMessage ( ) + " ] " ) ;
}
}
public UploadResult upload ( byte [ ] data , String path , String contentType ) {
return upload ( new ByteArrayInputStream ( data ) , path , contentType ) ;
/**
* 上传文件到 Amazon S3, 并返回上传结果
*
* @param filePath 本地文件路径
* @param key 在 Amazon S3 中的对象键
* @param md5Digest 本地文件的 MD5 哈希值(可选)
* @return UploadResult 包含上传后的文件信息
* @throws OssException 如果上传失败,抛出自定义异常
*/
public UploadResult upload ( Path filePath , String key , String md5Digest ) {
try {
// 构建上传请求对象
FileUpload fileUpload = transferManager . uploadFile (
x - > x . putObjectRequest (
y - > y . bucket ( properties . getBucketName ( ) )
. key ( key )
. contentMD5 ( StringUtils . isNotEmpty ( md5Digest ) ? md5Digest : null )
. build ( ) )
. addTransferListener ( LoggingTransferListener . create ( ) )
. source ( filePath ) . build ( ) ) ;
// 等待上传完成并获取上传结果
CompletedFileUpload uploadResult = fileUpload . completionFuture ( ) . join ( ) ;
String eTag = uploadResult . response ( ) . eTag ( ) ;
// 提取上传结果中的 ETag, 并构建一个自定义的 UploadResult 对象
return UploadResult . builder ( ) . url ( getUrl ( ) + StringUtils . SLASH + key ) . filename ( key ) . eTag ( eTag ) . build ( ) ;
} catch ( Exception e ) {
// 捕获异常并抛出自定义异常
throw new OssException ( " 上传文件失败,请检查配置信息:[ " + e . getMessage ( ) + " ] " ) ;
} finally {
// 无论上传是否成功,最终都会删除临时文件
FileUtils . del ( filePath ) ;
}
}
public UploadResult upload ( InputStream inputStream , String path , String contentType ) {
/**
* 上传 InputStream 到 Amazon S3
*
* @param inputStream 要上传的输入流
* @param key 在 Amazon S3 中的对象键
* @param length 输入流的长度
* @return UploadResult 包含上传后的文件信息
* @throws OssException 如果上传失败,抛出自定义异常
*/
public UploadResult upload ( InputStream inputStream , String key , Long length ) {
// 如果输入流不是 ByteArrayInputStream, 则将其读取为字节数组再创建 ByteArrayInputStream
if ( ! ( inputStream instanceof ByteArrayInputStream ) ) {
inputStream = new ByteArrayInputStream ( IoUtil . readBytes ( inputStream ) ) ;
}
try {
ObjectMetadata metadata = new ObjectMetadata ( ) ;
metadata . setContentType ( contentType ) ;
metadata . setContentLength ( inputStream . available ( ) ) ;
PutObjectRequest putObjectRequest = new PutObjectRequest ( properties . getBucketName ( ) , path , inputStream , metadata ) ;
// 设置上传对象的 Acl 为公共读
putObjectRequest . setCannedAcl ( getAccessPolicy ( ) . getAcl ( ) ) ;
client . putObject ( putObjectRequest) ;
// 创建异步请求体( length如果为空会报错)
BlockingInputStreamAsyncRequestBody body = AsyncRequestBody . forBlockingInputStream ( length ) ;
// 使用 transferManager 进行上传
Upload upload = transferManager . upload (
x - > x . requestBody ( body )
. putObjectRequest (
y - > y . bucket ( properties . getBucketName ( ) )
. key ( key )
. build ( ) )
. build ( ) ) ;
// 将输入流写入请求体
body . writeInputStream ( inputStream ) ;
// 等待文件上传操作完成
CompletedUpload uploadResult = upload . completionFuture ( ) . join ( ) ;
String eTag = uploadResult . response ( ) . eTag ( ) ;
// 提取上传结果中的 ETag, 并构建一个自定义的 UploadResult 对象
return UploadResult . builder ( ) . url ( getUrl ( ) + StringUtils . SLASH + key ) . filename ( key ) . eTag ( eTag ) . build ( ) ;
} catch ( Exception e ) {
throw new OssException ( " 上传文件失败,请检查配置信息:[ " + e . getMessage ( ) + " ] " ) ;
}
return UploadResult . builder ( ) . url ( getUrl ( ) + " / " + path ) . filename ( path ) . build ( ) ;
}
public UploadResult upload ( File file , String path ) {
try {
PutObjectRequest putObjectRequest = new PutObjectRequest ( properties . getBucketName ( ) , path , file ) ;
// 设置上传对象的 Acl 为公共读
putObjectRequest . setCannedAcl ( getAccessPolicy ( ) . getAcl ( ) ) ;
client . putObject ( putObjectRequest ) ;
} catch ( Exception e ) {
throw new OssException ( " 上传文件失败,请检查配置信息:[ " + e . getMessage ( ) + " ] " ) ;
}
return UploadResult . builder ( ) . url ( getUrl ( ) + " / " + path ) . filename ( path ) . build ( ) ;
}
public void delete ( String path ) {
path = path . replace ( getUrl ( ) + " / " , " " ) ;
try {
client . deleteObject ( properties . getBucketName ( ) , path ) ;
} catch ( Exception e ) {
throw new OssException ( " 删除文件失败,请检查配置信息:[ " + e . getMessage ( ) + " ] " ) ;
}
}
public UploadResult uploadSuffix ( byte [ ] data , String suffix , String contentType ) {
return upload ( data , getPath ( properties . getPrefix ( ) , suffix ) , contentType ) ;
}
public UploadResult uploadSuffix ( InputStream inputStream , String suffix , String contentType ) {
return upload ( inputStream , getPath ( properties . getPrefix ( ) , suffix ) , contentType ) ;
}
public UploadResult uploadSuffix ( File file , String suffix ) {
return upload ( file , getPath ( properties . getPrefix ( ) , suffix ) ) ;
}
/**
* 获取文件元数据
* 下载文件从 Amazon S3 到临时目录
*
* @param path 完整文件路径
* @param path 文件在 Amazon S3 中的对象键
* @return 下载后的文件在本地的临时路径
* @throws OssException 如果下载失败,抛出自定义异常
*/
public ObjectMetad ata getObjectMetadata ( String path ) {
path = path . replace ( getUrl ( ) + " / " , " " ) ;
S3Object object = client . getObject ( properties . getBucketName ( ) , path ) ;
return object . getObjectMetadata ( ) ;
public P ath fileDownload ( String path ) {
// 从路径中移除 URL 前缀
String url = removeBaseUrl ( path ) ;
// 构建临时文件路径 文件名必须是唯一不存在的,路径必须是存在的
Path tempFilePath = Paths . get ( extractFileName ( url ) ) ;
// 使用 S3TransferManager 下载文件
FileDownload downloadFile = transferManager . downloadFile (
x - > x . getObjectRequest (
y - > y . bucket ( properties . getBucketName ( ) )
. key ( url )
. build ( ) )
. addTransferListener ( LoggingTransferListener . create ( ) )
. destination ( tempFilePath )
. build ( ) ) ;
// 等待文件下载操作完成
downloadFile . completionFuture ( ) . join ( ) ;
return tempFilePath ;
}
public InputStream getObjectContent ( String path ) {
path = path . replace ( getUrl ( ) + " / " , " " ) ;
S3Object object = client . getObject ( properties . getBucketName ( ) , path ) ;
return object . getObjectContent ( ) ;
}
public String getUrl ( ) {
String domain = properties . getDomain ( ) ;
String endpoint = properties . getEndpoint ( ) ;
String header = OssConstant . IS_HTTPS . equals ( properties . getIsHttps ( ) ) ? " https:// " : " http:// " ;
// 云服务商直接返回
if ( StringUtils . containsAny ( endpoint , OssConstant . CLOUD_SERVICE ) ) {
if ( StringUtils . isNotBlank ( domain ) ) {
return header + domain ;
}
return header + properties . getBucketName ( ) + " . " + endpoint ;
/**
* 删除云存储服务中指定路径下文件
*
* @param path 指定路径
*/
public void delete ( String path ) {
try {
client . deleteObject (
x - > x . bucket ( properties. getBucketName ( ) )
. key ( removeBaseUrl ( path ) )
. build ( ) ) ;
} catch ( Exception e ) {
throw new OssException ( " 删除文件失败,请检查配置信息:[ " + e . getMessage ( ) + " ] " ) ;
}
// minio 单独处理
if ( StringUtils . isNotBlank ( domain ) ) {
return header + domain + " / " + properties . getBucketName ( ) ;
}
return header + endpoint + " / " + properties . getBucketName ( ) ;
}
public String getPath ( String prefix , String suffix ) {
// 生成uuid
String uuid = IdUtil . fastSimpleUUID ( ) ;
// 文件路径
String path = DateUtils . datePath ( ) + " / " + uuid ;
if ( StringUtils . isNotBlank ( prefix ) ) {
path = prefix + " / " + path ;
}
return path + suffix ;
}
public String getConfigKey ( ) {
return configKey ;
}
/**
@@ -207,14 +284,199 @@ public class OssClient {
* @param second 授权时间
*/
public String getPrivateUrl ( String objectKey , Integer second ) {
GeneratePresignedUrlRequest generatePresignedUrlRequest =
new GeneratePresignedUrlRequest ( properties . getBucketName ( ) , o bjectKey )
. withMethod ( HttpMethod . GET )
. withExpiration ( new Date ( System . currentTimeMillis ( ) + 1000L * second ) ) ;
URL url = client . generatePresignedUrl ( generatePresignedUrlRequest ) ;
// 使用 AWS S3 预签名 URL 的生成器 获取对象的预签名 URL
URL url = presigner . presignGetO bject (
x - > x . signatureDuration ( Duration . ofSeconds ( second ) )
. getObjectRequest (
y - > y . bucket ( properties . getBucketName ( ) )
. key ( objectKey )
. build ( ) )
. build ( ) )
. url ( ) ;
return url . toString ( ) ;
}
/**
* 上传 byte[] 数据到 Amazon S3, 使用指定的后缀构造对象键。
*
* @param data 要上传的 byte[] 数据
* @param suffix 对象键的后缀
* @return UploadResult 包含上传后的文件信息
* @throws OssException 如果上传失败,抛出自定义异常
*/
public UploadResult uploadSuffix ( byte [ ] data , String suffix ) {
return upload ( new ByteArrayInputStream ( data ) , getPath ( properties . getPrefix ( ) , suffix ) , Long . valueOf ( data . length ) ) ;
}
/**
* 上传 InputStream 到 Amazon S3, 使用指定的后缀构造对象键。
*
* @param inputStream 要上传的输入流
* @param suffix 对象键的后缀
* @param length 输入流的长度
* @return UploadResult 包含上传后的文件信息
* @throws OssException 如果上传失败,抛出自定义异常
*/
public UploadResult uploadSuffix ( InputStream inputStream , String suffix , Long length ) {
return upload ( inputStream , getPath ( properties . getPrefix ( ) , suffix ) , length ) ;
}
/**
* 上传文件到 Amazon S3, 使用指定的后缀构造对象键
*
* @param file 要上传的文件
* @param suffix 对象键的后缀
* @return UploadResult 包含上传后的文件信息
* @throws OssException 如果上传失败,抛出自定义异常
*/
public UploadResult uploadSuffix ( File file , String suffix ) {
return upload ( file . toPath ( ) , getPath ( properties . getPrefix ( ) , suffix ) , null ) ;
}
/**
* 获取文件输入流
*
* @param path 完整文件路径
* @return 输入流
*/
public InputStream getObjectContent ( String path ) throws IOException {
// 下载文件到临时目录
Path tempFilePath = fileDownload ( path ) ;
// 创建输入流
InputStream inputStream = Files . newInputStream ( tempFilePath ) ;
// 删除临时文件
FileUtils . del ( tempFilePath ) ;
// 返回对象内容的输入流
return inputStream ;
}
/**
* 获取 S3 客户端的终端点 URL
*
* @return 终端点 URL
*/
public String getEndpoint ( ) {
// 根据配置文件中的是否使用 HTTPS, 设置协议头部
String header = getIsHttps ( ) ;
// 拼接协议头部和终端点,得到完整的终端点 URL
return header + properties . getEndpoint ( ) ;
}
/**
* 获取 S3 客户端的终端点 URL( 自定义域名)
*
* @return 终端点 URL
*/
public String getDomain ( ) {
// 从配置中获取域名、终端点、是否使用 HTTPS 等信息
String domain = properties . getDomain ( ) ;
String endpoint = properties . getEndpoint ( ) ;
String header = getIsHttps ( ) ;
// 如果是云服务商,直接返回域名或终端点
if ( StringUtils . containsAny ( endpoint , OssConstant . CLOUD_SERVICE ) ) {
return StringUtils . isNotEmpty ( domain ) ? header + domain : header + endpoint ;
}
// 如果是 MinIO, 处理域名并返回
if ( StringUtils . isNotEmpty ( domain ) ) {
return domain . startsWith ( Constants . HTTPS ) | | domain . startsWith ( Constants . HTTP ) ? domain : header + domain ;
}
// 返回终端点
return header + endpoint ;
}
/**
* 根据传入的 region 参数返回相应的 AWS 区域
* 如果 region 参数非空,使用 Region.of 方法创建并返回对应的 AWS 区域对象
* 如果 region 参数为空,返回一个默认的 AWS 区域( 例如, us-east-1) , 作为广泛支持的区域
*
* @return 对应的 AWS 区域对象, 或者默认的广泛支持的区域( us-east-1)
*/
public Region of ( ) {
//AWS 区域字符串
String region = properties . getRegion ( ) ;
// 如果 region 参数非空,使用 Region.of 方法创建对应的 AWS 区域对象,否则返回默认区域
return StringUtils . isNotEmpty ( region ) ? Region . of ( region ) : Region . US_EAST_1 ;
}
/**
* 获取云存储服务的URL
*
* @return 文件路径
*/
public String getUrl ( ) {
String domain = properties . getDomain ( ) ;
String endpoint = properties . getEndpoint ( ) ;
String header = getIsHttps ( ) ;
// 云服务商直接返回
if ( StringUtils . containsAny ( endpoint , OssConstant . CLOUD_SERVICE ) ) {
return header + ( StringUtils . isNotEmpty ( domain ) ? domain : properties . getBucketName ( ) + " . " + endpoint ) ;
}
// MinIO 单独处理
if ( StringUtils . isNotEmpty ( domain ) ) {
// 如果 domain 以 "https://" 或 "http://" 开头
return ( domain . startsWith ( Constants . HTTPS ) | | domain . startsWith ( Constants . HTTP ) ) ?
domain + StringUtils . SLASH + properties . getBucketName ( ) : header + domain + StringUtils . SLASH + properties . getBucketName ( ) ;
}
return header + endpoint + StringUtils . SLASH + properties . getBucketName ( ) ;
}
/**
* 生成一个符合特定规则的、唯一的文件路径。通过使用日期、UUID、前缀和后缀等元素的组合, 确保了文件路径的独一无二性
*
* @param prefix 前缀
* @param suffix 后缀
* @return 文件路径
*/
public String getPath ( String prefix , String suffix ) {
// 生成uuid
String uuid = IdUtil . fastSimpleUUID ( ) ;
// 生成日期路径
String datePath = DateUtils . datePath ( ) ;
// 拼接路径
String path = StringUtils . isNotEmpty ( prefix ) ?
prefix + StringUtils . SLASH + datePath + StringUtils . SLASH + uuid : datePath + StringUtils . SLASH + uuid ;
return path + suffix ;
}
/**
* 移除路径中的基础URL部分, 得到相对路径
*
* @param path 完整的路径, 包括基础URL和相对路径
* @return 去除基础URL后的相对路径
*/
public String removeBaseUrl ( String path ) {
return path . replace ( getUrl ( ) + StringUtils . SLASH , " " ) ;
}
/**
* 从文件路径中提取文件名
*
* @param path 文件路径
* @return 提取的文件名或默认文件名
*/
public String extractFileName ( String path ) {
return FileUtils . getTmpDir ( ) + StringUtils . SLASH + Paths . get ( path ) . getFileName ( ) . toString ( ) ;
}
/**
* 服务商
*/
public String getConfigKey ( ) {
return configKey ;
}
/**
* 获取是否使用 HTTPS 的配置,并返回相应的协议头部。
*
* @return 协议头部,根据是否使用 HTTPS 返回 "https://" 或 "http://"
*/
public String getIsHttps ( ) {
return OssConstant . IS_HTTPS . equals ( properties . getIsHttps ( ) ) ? Constants . HTTPS : Constants . HTTP ;
}
/**
* 检查配置是否相同
*/
@@ -231,6 +493,13 @@ public class OssClient {
return AccessPolicyType . getByType ( properties . getAccessPolicy ( ) ) ;
}
/**
* 生成 AWS S3 存储桶访问策略
*
* @param bucketName 存储桶
* @param policyType 桶策略类型
* @return 符合 AWS S3 存储桶访问策略格式的字符串
*/
private static String getPolicy ( String bucketName , PolicyType policyType ) {
StringBuilder builder = new StringBuilder ( ) ;
builder . append ( " { \ n \" Statement \" : [ \ n{ \ n \" Action \" : [ \ n " ) ;