增加腾讯云 tencent cos 对象存储服务,已经测试
This commit is contained in:
parent
a88298057f
commit
8527b0233d
|
|
@ -139,6 +139,14 @@
|
||||||
<version>[7.7.0, 7.7.99]</version>
|
<version>[7.7.0, 7.7.99]</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!--七牛云文件存储 end -->
|
<!--七牛云文件存储 end -->
|
||||||
|
|
||||||
|
<!--文件服务器7:腾讯云文件存储cos start -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.qcloud</groupId>
|
||||||
|
<artifactId>cos_api</artifactId>
|
||||||
|
<version>5.6.45</version>
|
||||||
|
</dependency>
|
||||||
|
<!--文件服务器7:腾讯云文件存储cos end -->
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<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
|
* @author ruoyi
|
||||||
* @see FastDfsConfig
|
* @see FastDfsConfig
|
||||||
*/
|
*/
|
||||||
@Primary
|
//@Primary
|
||||||
@Service()
|
@Service()
|
||||||
public class FastDfsServiceImpl implements IDfsService
|
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
|
bucket-name: guangdong-oss
|
||||||
domain: http://guangdong-oss.ityun.ltd
|
domain: http://guangdong-oss.ityun.ltd
|
||||||
expiry-duration: 32400
|
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