增加腾讯云 tencent cos 对象存储服务,已经测试
This commit is contained in:
parent
a88298057f
commit
8527b0233d
|
|
@ -139,6 +139,14 @@
|
|||
<version>[7.7.0, 7.7.99]</version>
|
||||
</dependency>
|
||||
<!--七牛云文件存储 end -->
|
||||
|
||||
<!--文件服务器7:腾讯云文件存储cos start -->
|
||||
<dependency>
|
||||
<groupId>com.qcloud</groupId>
|
||||
<artifactId>cos_api</artifactId>
|
||||
<version>5.6.45</version>
|
||||
</dependency>
|
||||
<!--文件服务器7:腾讯云文件存储cos end -->
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,161 @@
|
|||
package com.ruoyi.file.config;
|
||||
|
||||
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.http.HttpProtocol;
|
||||
import com.qcloud.cos.region.Region;
|
||||
import io.minio.MinioClient;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 腾讯云文件存储 cos 配置
|
||||
* 对象存储文档api地址:https://cloud.tencent.com/document/product/436/6474
|
||||
* 控制台地址:https://console.cloud.tencent.com/cos5
|
||||
* API密钥获取地址:https://console.cloud.tencent.com/cam/capi
|
||||
* Region | endpoint, bucket 的地域, COS 地域的简称请参照 https://cloud.tencent.com/document/product/436/6224
|
||||
* 历史版本地域列表 https://cloud.tencent.com/document/product/436/7777
|
||||
*
|
||||
* @author yabo
|
||||
*/
|
||||
@RefreshScope
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = TencentCosConfig.PREFIX)
|
||||
public class TencentCosConfig {
|
||||
public static final String PREFIX = "tencent-cos";
|
||||
|
||||
@Bean
|
||||
public COSClient getCosClient() {
|
||||
//初始化用户身份信息(secretId, secretKey)。
|
||||
// SECRETID和SECRETKEY请登录访问管理控制台进行查看和管理
|
||||
String secretId = this.getAccessKey();
|
||||
String secretKey = this.getSecretKey();
|
||||
String endpoint = this.getEndpoint();
|
||||
COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
|
||||
// 2 设置 bucket 的地域, COS 地域的简称请参照 https://cloud.tencent.com/document/product/436/6224
|
||||
// clientConfig 中包含了设置 region, https(默认 http), 超时, 代理等 set 方法, 使用可参见源码或者常见问题 Java SDK 部分。
|
||||
Region region = new Region(endpoint);
|
||||
ClientConfig clientConfig = new ClientConfig(region);
|
||||
// 这里建议设置使用 https 协议
|
||||
clientConfig.setHttpProtocol(HttpProtocol.https);
|
||||
// 设置最大重试次数为 1 次
|
||||
clientConfig.setMaxErrorRetry(1);
|
||||
// 3 生成 cos 客户端。
|
||||
return new COSClient(cred, clientConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* ak,同其他 平台
|
||||
*
|
||||
* @see AliyunOssConfig#getAccessKey()
|
||||
* @see QiniuKodoConfig#getAccessKey()
|
||||
* @see MinioConfig#getAccessKey()
|
||||
* eg: AKIDX9hNAzpdUI0XyRpASj098xa7uYzOekmh
|
||||
* 别名:SecretId
|
||||
*/
|
||||
private String accessKey = "";
|
||||
/**
|
||||
* sk, 同其他 平台
|
||||
*
|
||||
* @see AliyunOssConfig#getSecretKey()
|
||||
* @see QiniuKodoConfig#getSecretKey()
|
||||
* @see MinioConfig#getSecretKey()
|
||||
* eg: sW5VgkdHlDYqy01xiGbkjV5TghUEvYEw
|
||||
* 别名:SecretKey
|
||||
*/
|
||||
private String secretKey = "";
|
||||
/**
|
||||
* bucket,同其他平台 桶概念
|
||||
*
|
||||
* @see AliyunOssConfig#getBucketName()
|
||||
* @see QiniuKodoConfig#getBucketName()
|
||||
* @see MinioConfig#getBucketName()
|
||||
*/
|
||||
private String bucketName = "";
|
||||
/**
|
||||
* endpoint,同其他平台 概念;
|
||||
* 别名:Region
|
||||
*
|
||||
* @see AliyunOssConfig#getEndpoint()
|
||||
* @see QiniuKodoConfig 有,Region 目前使用的是自动获取存储区域;暂不启用
|
||||
* @see MinioConfig 目前私有部署,不存在endpoint
|
||||
* eg: ap-chengdu 地域和访问域名 https://cloud.tencent.com/document/product/436/6224
|
||||
*/
|
||||
private String endpoint = "";
|
||||
/**
|
||||
* <p>
|
||||
* 上传地址和访问地址经常是不一样的
|
||||
* 1、上传地址是内网;访问地址是外网;
|
||||
* 2、上传地址是ip; 访问地址域名;
|
||||
* 3、上传地址是http; 访问地址是https
|
||||
* 4: eg: https://image.jl-media.cn
|
||||
*/
|
||||
private String domain = null;
|
||||
/**
|
||||
* 过期时间,单位秒;
|
||||
* 如:1小时就写:3600L
|
||||
* 如:9小时就写:32400L
|
||||
* 如:12小时就写:43200L, 【不支持】,最大是 32400(9小时), 最小 1(1秒钟)
|
||||
* 如:-1: 就永不过期,原样返回url
|
||||
* 签名URL的默认过期时间为3600秒,最大值为32400秒
|
||||
* 文档:对象存储 授权访问 https://cloud.tencent.com/document/product/436/10199
|
||||
* <p>
|
||||
* 注意!!:tencent cos 设置Bucket ACL
|
||||
* 1、私有 【必须要加签之后才能访问】
|
||||
* 2、公共读
|
||||
* 3、公共读写
|
||||
*/
|
||||
private Long expiryDuration = 32400L;
|
||||
|
||||
public String getAccessKey() {
|
||||
return accessKey;
|
||||
}
|
||||
|
||||
public void setAccessKey(String accessKey) {
|
||||
this.accessKey = accessKey;
|
||||
}
|
||||
|
||||
public String getSecretKey() {
|
||||
return secretKey;
|
||||
}
|
||||
|
||||
public void setSecretKey(String secretKey) {
|
||||
this.secretKey = secretKey;
|
||||
}
|
||||
|
||||
public String getBucketName() {
|
||||
return bucketName;
|
||||
}
|
||||
|
||||
public void setBucketName(String bucketName) {
|
||||
this.bucketName = bucketName;
|
||||
}
|
||||
|
||||
public String getEndpoint() {
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
public void setEndpoint(String endpoint) {
|
||||
this.endpoint = endpoint;
|
||||
}
|
||||
|
||||
public String getDomain() {
|
||||
return domain;
|
||||
}
|
||||
|
||||
public void setDomain(String domain) {
|
||||
this.domain = domain;
|
||||
}
|
||||
|
||||
public Long getExpiryDuration() {
|
||||
return expiryDuration;
|
||||
}
|
||||
|
||||
public void setExpiryDuration(Long expiryDuration) {
|
||||
this.expiryDuration = expiryDuration;
|
||||
}
|
||||
}
|
||||
|
|
@ -21,7 +21,7 @@ import com.github.tobato.fastdfs.service.FastFileStorageClient;
|
|||
* @author ruoyi
|
||||
* @see FastDfsConfig
|
||||
*/
|
||||
@Primary
|
||||
//@Primary
|
||||
@Service()
|
||||
public class FastDfsServiceImpl implements IDfsService
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,198 @@
|
|||
package com.ruoyi.file.service;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import com.qcloud.cos.COSClient;
|
||||
import com.qcloud.cos.exception.CosClientException;
|
||||
import com.qcloud.cos.http.HttpMethodName;
|
||||
import com.qcloud.cos.model.*;
|
||||
import com.ruoyi.common.core.exception.CustomException;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
import com.ruoyi.file.config.TencentCosConfig;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 腾讯云cos 文件服务器实现
|
||||
*
|
||||
* @author yabo
|
||||
* @see TencentCosConfig
|
||||
*/
|
||||
@Primary
|
||||
@Service()
|
||||
public class TencentCosServiceImpl implements IDfsService {
|
||||
private final COSClient cosClient;
|
||||
private final TencentCosConfig config;
|
||||
|
||||
public TencentCosServiceImpl(COSClient cosClient, TencentCosConfig config) {
|
||||
this.cosClient = cosClient;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String uploadFile(MultipartFile file) throws Exception {
|
||||
return this.uploadFile(file, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 腾讯云文档中心==》对象存储==》JAVA SDK===> 上传对象
|
||||
* https://cloud.tencent.com/document/product/436/10199#.E4.B8.8A.E4.BC.A0.E5.AF.B9.E8.B1.A1
|
||||
* 上传成功示例:https://cos.ityun.ltd/dev/upload/default/20210729-2be9b217-22ef-45a2-bfda-e793ffe33f55.jpeg
|
||||
*/
|
||||
@Override
|
||||
public String uploadFile(MultipartFile file, String modules) throws Exception {
|
||||
//key: 这里不能以/开头
|
||||
validateModule(file, null);
|
||||
String newName = extractFileNameSimple(file);
|
||||
//key: 这里不能以/开头
|
||||
String requestKey = "upload/" + StringUtils.defaultString(modules, "default") + "/" + newName;
|
||||
//这里增加一个前缀区分一下是测试环境还是正式环境
|
||||
boolean isProd = "prod".equalsIgnoreCase(SpringUtil.getActiveProfile());
|
||||
if (!isProd) {
|
||||
requestKey = SpringUtil.getActiveProfile() + "/" + requestKey;
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(config.getBucketName())) {
|
||||
throw new CustomException("tencent cos bucket name 不能为空,请检查!");
|
||||
}
|
||||
if (StringUtils.isBlank(config.getEndpoint())) {
|
||||
throw new CustomException("tencent cos endpoint(Region) 不能为空,请检查!");
|
||||
}
|
||||
ObjectMetadata objectMetadata = new ObjectMetadata();
|
||||
|
||||
// 指定文件将要存放的存储桶
|
||||
String bucketName = config.getBucketName();
|
||||
// 指定文件上传到 COS 上的路径,即对象键。例如对象键为folder/picture.jpg,则表示将文件 picture.jpg 上传到 folder 路径下
|
||||
String key = requestKey;
|
||||
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, file.getInputStream(), objectMetadata);
|
||||
try {
|
||||
PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);
|
||||
return (config.getDomain() + "/" + key);
|
||||
} catch (CosClientException e) {
|
||||
e.printStackTrace();
|
||||
throw new CustomException("tencent cos upload 失败;错误代码:" + e.getErrorCode() + ";错误原因:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 腾讯云文档中心==》对象存储==》JAVA SDK===> 删除对象
|
||||
* https://cloud.tencent.com/document/product/436/10199#.E5.88.A0.E9.99.A4.E5.AF.B9.E8.B1.A1
|
||||
*/
|
||||
@Override
|
||||
public boolean deleteFile(String fileUrl) {
|
||||
if (StringUtils.isBlank(config.getBucketName())) {
|
||||
throw new CustomException("tencent cos bucket name 不能为空,请检查!");
|
||||
}
|
||||
|
||||
// 指定被删除的文件在 COS 上的路径,即对象键。例如对象键为folder/picture.jpg,则表示删除位于 folder 路径下的文件 picture.jpg
|
||||
String key = this.getStorePath(fileUrl);
|
||||
try {
|
||||
cosClient.deleteObject(config.getBucketName(), key);
|
||||
} catch (CosClientException e) {
|
||||
e.printStackTrace();
|
||||
throw new CustomException("tencent cos 删除重新异常,请排查...");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 腾讯云文档中心==》对象存储==》JAVA SDK===> 查询对象列表
|
||||
* 无法直接获取所有文件大小
|
||||
* https://cloud.tencent.com/document/product/436/10199#.E6.9F.A5.E8.AF.A2.E5.AF.B9.E8.B1.A1.E5.88.97.E8.A1.A8
|
||||
*/
|
||||
@Override
|
||||
public String objectsCapacityStr() {
|
||||
if (StringUtils.isBlank(config.getBucketName())) {
|
||||
throw new CustomException("tencent cos bucket name 不能为空,请检查!");
|
||||
}
|
||||
|
||||
// Bucket的命名格式为 BucketName-APPID ,此处填写的存储桶名称必须为此格式
|
||||
String bucketName = config.getBucketName();
|
||||
ListObjectsRequest listObjectsRequest = new ListObjectsRequest();
|
||||
// 设置bucket名称
|
||||
listObjectsRequest.setBucketName(bucketName);
|
||||
/// prefix表示列出的object的key以prefix开始
|
||||
///listObjectsRequest.setPrefix("images/");
|
||||
/// deliter表示分隔符, 设置为/表示列出当前目录下的object, 设置为空表示列出所有的object
|
||||
///listObjectsRequest.setDelimiter("/");
|
||||
// 设置最大遍历出多少个对象, 一次listobject最大支持1000
|
||||
listObjectsRequest.setMaxKeys(1000);
|
||||
ObjectListing objectListing = null;
|
||||
long size = 0;
|
||||
do
|
||||
{
|
||||
try {
|
||||
objectListing = cosClient.listObjects(listObjectsRequest);
|
||||
} 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();
|
||||
size += fileSize;
|
||||
}
|
||||
String nextMarker = objectListing.getNextMarker();
|
||||
listObjectsRequest.setMarker(nextMarker);
|
||||
} while (objectListing.isTruncated());
|
||||
return FileUtil.readableFileSize(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求预签名 URL
|
||||
* 腾讯云文档中心==》对象存储==》JAVA SDK===> 预签名URL ===> 获取请求预签名 URL
|
||||
* https://cloud.tencent.com/document/product/436/35217#.E8.8E.B7.E5.8F.96.E8.AF.B7.E6.B1.82.E9.A2.84.E7.AD.BE.E5.90.8D-url
|
||||
* @return 返回示例:https://cos.ityun.ltd/dev/upload/default/20210729-2be9b217-22ef-45a2-bfda-e793ffe33f55.jpeg?4304-bdfc-e2964b8721bb.jpeg?sign=q-sign-algorithm%3Dsha1%26q-ak%3DAKIDX9hNAzpdUI0XyRpASj098xa7uYzOekmh%26q-sign-time%3D1627542548%3B1627574935%26q-key-time%3D1627542548%3B1627574935%26q-header-list%3Dhost%26q-url-param-list%3D%26q-signature%3D872e77dbca69d6b67d7a0027ab41c374703994f8
|
||||
* https://tencent-cloud-cos-dazer-1253883700.cos.ap-chengdu.myqcloud.com/dev/upload/default/20210729-2be9b217-22ef-45a2-bfda-e793ffe33f55.jpeg?sign=q-sign-algorithm%3Dsha1%26q-ak%3DAKIDX9hNAzpdUI0XyRpASj098xa7uYzOekmh%26q-sign-time%3D1627542872%3B1627575269%26q-key-time%3D1627542872%3B1627575269%26q-header-list%3Dhost%26q-url-param-list%3D%26q-signature%3D21508af6284564532deb935e03c2226d93bc965a
|
||||
*/
|
||||
@Override
|
||||
public String presignedUrl(String fileUrl) {
|
||||
// 存储桶的命名格式为 BucketName-APPID,此处填写的存储桶名称必须为此格式
|
||||
String bucketName = config.getBucketName();
|
||||
if (StringUtils.isBlank(config.getBucketName())) {
|
||||
throw new CustomException("tencent cos bucket name 不能为空,请检查!");
|
||||
}
|
||||
|
||||
// 此处的key为对象键,对象键是对象在存储桶内的唯一标识
|
||||
String key = this.getStorePath(fileUrl);
|
||||
GeneratePresignedUrlRequest req =
|
||||
new GeneratePresignedUrlRequest(bucketName, key, HttpMethodName.GET);
|
||||
// 设置签名过期时间(可选), 若未进行设置, 则默认使用 ClientConfig 中的签名过期时间(1小时)
|
||||
// 这里设置签名在半个小时后过期
|
||||
Date expirationDate = new Date(System.currentTimeMillis() + (config.getExpiryDuration() * 1000));
|
||||
req.setExpiration(expirationDate);
|
||||
URL url = cosClient.generatePresignedUrl(req);
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换url,为原始的key
|
||||
*
|
||||
* @param filePath http://guangdong-oss.ityun.ltd/upload/default/header.jpg
|
||||
* @return upload/default/header.jpg
|
||||
* <p>
|
||||
* http://qwc2geifw.hn-bkt.clouddn.com/upload/default/header.jpg
|
||||
* ==> upload/default/header.jpg
|
||||
*/
|
||||
private String getStorePath(String filePath) {
|
||||
String domain = config.getDomain();
|
||||
String publicPath3 = domain + "/";
|
||||
filePath = filePath.replace(publicPath3, "");
|
||||
return filePath;
|
||||
}
|
||||
}
|
||||
|
|
@ -76,3 +76,12 @@ qiniu:
|
|||
bucket-name: guangdong-oss
|
||||
domain: http://guangdong-oss.ityun.ltd
|
||||
expiry-duration: 32400
|
||||
|
||||
# 文件服务器之7 tencent cos 文件存储
|
||||
tencent-cos:
|
||||
access-key: AKIDX9hNAzpdUI0XyRpASj098xa7uYzOekmh
|
||||
secret-key: sW5VgkdHlDYqy01xiGbkjV5TghUEvYEw
|
||||
endpoint: ap-chengdu
|
||||
bucket-name: tencent-cloud-cos-dazer-1253883700
|
||||
domain: https://cos.ityun.ltd
|
||||
expiry-duration: 32400
|
||||
|
|
|
|||
Loading…
Reference in New Issue