什么是对象存储
对象存储是一种将数据作为对象进行管理的计算机数据存储体系结构,与其他存储体系结构(例如将数据作为文件层级管理的文件系统)以及将数据作为块和扇区内的块进行管理的块存储相对。每个对象通常包括数据本身,可变数量的元数据和全局唯一标识符。
对象存储可以在多个级别实现,包括设备级别(对象存储设备),系统级别和接口级别。在每种情况下,对象存储都试图实现其他存储架构无法解决的功能,例如可以由应用程序直接编程的接口,可以跨越多个物理硬件实例的命名空间,以及数据管理功能,如数据复制和数据分发在对象级粒度。
相比于数据库这种面向结构化数据存储的技术,对象存储主要面向存储大量的非结构化数据,通俗来说,我们日常生活中生成的照片、视频、音频、文档等都属于非结构化数据。这些日常产生的数据都适合存储在对象存储中。
现在几乎所有公有云服务商都提供对象存储服务,如果要在企业内部使用,也可以采用元核云、紫光西数这类专业存储公司提供的企业级对象存储产品。
1.创建桶
这里使用的腾讯云对象存储
创建桶的链接https://console.cloud.tencent.com/cos
2.查看桶相关信息
可知桶名为
获取密钥https://console.cloud.tencent.com/cam/capi
访问域名在点击桶更多配置可见
3.代码实现api调用
依赖
<!--腾讯云COS-->
<dependency>
<groupId>com.qcloud</groupId>
<artifactId>cos_api</artifactId>
<version>5.6.89</version>
</dependency>
yaml配置
tencent:
yun:
#腾讯云api的APPID
APPID:
#腾讯云api秘钥id
secretid:
#腾讯云api秘钥key
secretkey:
#COS地域
region:
#COS路径-访问域名
url:
#COS储存桶名称
bucketName:
COS客户端实现位于TCCOSConfig配置类中
参考文档: https://cloud.tencent.com/document/product/436/10199#.E5.88.9B.E5.BB.BA.E5.AD.98.E5.82.A8.E6.A1.B6
通用参考文档: https://cloud.tencent.com/document/product/436/10199#.E5.88.9B.E5.BB.BA.E5.AD.98.E5.82.A8.E6.A1.B6
文件下载,参考文档:https://cloud.tencent.com/document/product/436/65937#.E4.B8.8B.E8.BD.BD.E5.AF.B9.E8.B1.A12 参考文档最后之处
demo
1.yaml
其数据库连接操作没有用到
server:
port: 9004
#优雅关停
shutdown: graceful
spring:
lifecycle:
#强制关停时间(配合优雅关停)
timeout-per-shutdown-phase: 60s
application:
name: COSdemo-boot-project
aop:
auto: true
proxy-target-class: true
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://xxxx:3306/xxxx?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
username: xxxxx
password: xxxxx
#以下配置参考:
#https://github.com/alibaba/druid/wiki
#https://github.com/alibaba/druid/wiki/DruidDataSource%E9%85%8D%E7%BD%AE%E5%B1%9E%E6%80%A7%E5%88%97%E8%A1%A8
#https://www.cnblogs.com/halberd-lee/p/11304790.html
#https://blog.csdn.net/weixin_41926301/article/details/92835070
druid:
#启动程序时,在连接池中初始化多少个连接
#计算方法可参考:https://qgstu.com/article/20.htm
initialSize: 1
#回收空闲连接时,将保证至少有minIdle个连接
minIdle: 1
#连接池中最多支持多少个活动会话
#计算方法可参考:https://www.cnblogs.com/phpper/p/9570792.html
maxActive: 100
#获取连接时最大等待时间,单位毫秒。
#配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。
maxWait: 3000
#建议配置为true,不影响性能,并且保证安全性。
#当应用向连接池申请连接时检测时,如果这个连接的空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
#而testOnBorrow是不管空闲时间,都执行validationQuery
#参考:https://www.jianshu.com/p/bdf96b3fd743
testWhileIdle: true
#申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
testOnBorrow: false
#归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能
testOnReturn: false
#打开KeepAlive之后的效果:
#1. 初始化连接池时会填充到minIdle数量。
#2. 连接池中的minIdle数量以内的连接,空闲时间超过minEvictableIdleTimeMillis,则会执行keepAlive操作(validationQuery)。
#3. 当网络断开等原因产生的由ExceptionSorter检测出来的死连接被清除后,自动补充连接到minIdle数量。
keepAlive: false
#检查池中的连接是否仍可用的 SQL 语句,druid会连接到数据库执行该SQL,
#如果正常返回,则表示连接可用,否则表示连接不可用
validationQuery: SELECT 1
#注意:minEvictableIdleTimeMillis、maxEvictableIdleTimeMillis、timeBetweenEvictionRunsMillis的配置
#参考:https://www.jianshu.com/p/be9dbe640daf?ivk_sa=1024320u
#根据 https://blog.csdn.net/xingor/article/details/106698055 总结如下(对参考链接做了一定的优化):
#1. 明确我们业务连接的数据库对空闲链接的保留时长上限,例如MySQL的wait_time参数,其会终止掉sleep线程
#2. 配置timeBetweenEvictionRunsMillis、minEvictableIdleTimeMillis和maxEvictableIdleTimeMillis时
# 需要保证在两个清理周期之内超时(空闲时长>数据库wait_time)链接一定会被清理掉
#3. timeBetweenEvictionRunsMillis一定要小于:数据库wait_time-minEvictableIdleTimeMillis
# 和数据库wait_time-maxEvictableIdleTimeMillis 的最小值
#minEvictableIdleTimeMillis:连接空闲时间大于该值并且池中空闲连接大于minIdle
#如果没配置keepalive,则关闭该连接。如果配置了,关闭超出minIdle的连接之后,执行keepalive
minEvictableIdleTimeMillis: 160000
#maxEvictableIdleTimeMillis:连接空闲时间大于该值,不管minIdle都关闭该连接
#如果打开了keepAlive,keepAlive会不断的刷新,所以这个配置就用不上了
maxEvictableIdleTimeMillis: 230000
#有两个含义:
#1) Destroy线程会检测连接的间隔时间
#如果连接空闲时间大于等于minEvictableIdleTimeMillis则执行minEvictableIdleTimeMillis里的操作。
#如果连接空闲时间大于等于maxEvictableIdleTimeMillis则执行maxEvictableIdleTimeMillis里的操作。
#2) testWhileIdle的判断依据,详细看testWhileIdle属性的说明
timeBetweenEvictionRunsMillis: 60000
#配置插件
filters: stat,wall,slf4j
#连接池预编译Sql
poolPreparedStatements: true
#预编译Sql语句
maxPoolPreparedStatementPerConnectionSize: 20
mybatis:
mapper-locations: classpath:mapper/**/*.xml
# type-aliases-package: com.truezir.talesstreet
management:
endpoints:
web:
exposure:
include: '*'
tencent:
yun:
#腾讯云api的APPID
APPID:
#腾讯云api秘钥id
secretid:
#腾讯云api秘钥key
secretkey:
#COS地域
region:
#COS路径-访问域名
url: https://
#COS储存桶名称
bucketName:
2.配置类
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 lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 腾讯云COS配置
* 参考文档: https://cloud.tencent.com/document/product/436/10199#.E5.88.9B.E5.BB.BA.E5.AD.98.E5.82.A8.E6.A1.B6
*
* @author xn
* @date 2022/6/20 15:41
*/
@Configuration
@Data
public class TCCOSConfig {
@Value("${tencent.yun.secretid}")
private String secretId;
@Value("${tencent.yun.secretkey}")
private String secretKey;
@Value("${tencent.yun.region}")
private String region;
@Bean
public COSClient cosClient() {
// 1 初始化用户身份信息(secretId, secretKey)。
// SECRETID和SECRETKEY请登录访问管理控制台 https://console.cloud.tencent.com/cam/capi 进行查看和管理
COSCredentials cred = new BasicCOSCredentials(this.secretId, this.secretKey);
// 2 设置 bucket 的地域, COS 地域的简称请参照 https://cloud.tencent.com/document/product/436/6224
// clientConfig 中包含了设置 region, https(默认 http), 超时, 代理等 set 方法, 使用可参见源码或者常见问题 Java SDK 部分。
Region region = new Region(this.region);
ClientConfig clientConfig = new ClientConfig(region);
// 这里建议设置使用 https 协议
// 从 5.6.54 版本开始,默认使用了 https
clientConfig.setHttpProtocol(HttpProtocol.https);
// 3 生成 cos 客户端。
COSClient cosClient = new COSClient(cred, clientConfig);
return cosClient;
}
}
controller
import com.xunan.boot.service.COSFilesService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
/**
* 腾讯云cos接口的基础操作
* 参考文档: https://cloud.tencent.com/document/product/436/10199#.E5.88.9B.E5.BB.BA.E5.AD.98.E5.82.A8.E6.A1.B6
*
* @author xn
* @date 2022/6/20 15:23
*/
@RestController
public class FileController {
@Resource
private COSFilesService cosFilesService;
/**
* 上传文件到腾讯云
*
* @param file 文件
* @return 该文件位于COS上的路径
*/
@PostMapping("cos/file/fileUpload")
public String fileUpload(MultipartFile file) {
//该文件位于COS上的路径
String url = cosFilesService.fileUpload(file);
return url;
}
/**
* 查询存储桶中对象列表
*
* @param PrefixPath 腾讯云COS对应桶下某个文件夹
*/
@GetMapping("cos/file/selectFiles")
public void selectFiles(String PrefixPath) {
cosFilesService.selectFiles(PrefixPath);
}
/**
* 下载文件
* 参考文档:https://cloud.tencent.com/document/product/436/65937#.E4.B8.8B.E8.BD.BD.E5.AF.B9.E8.B1.A12 的最后
*
* @param COSKey 指定文件在 COS 上的路径,即对象键。例如对象键为folder/picture.jpg,则表示下载的文件 picture.jpg 在 folder 路径下
* @return 下载链接
*/
@PostMapping("cos/file/downloadFile")
public String downloadFile(String COSKey) {
String downloadUrl = cosFilesService.downloadFile(COSKey);
return downloadUrl;
}
/**
* 删除文件
*
* @param COSKey 指定文件在 COS 上的路径,即对象键。例如对象键为folder/picture.jpg,则表示下载的文件 picture.jpg 在 folder 路径下
* @return 是否成功
*/
@PostMapping("cos/file/deleteFile")
public Boolean deleteFile(String COSKey) {
Boolean result = cosFilesService.deleteFile(COSKey);
return result;
}
}
service
import cn.hutool.core.util.IdUtil;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.exception.CosServiceException;
import com.qcloud.cos.model.*;
import com.qcloud.cos.utils.IOUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.*;
import java.net.URI;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
/**
* 腾讯云COS操作
*
* @author xn
* @date 2022/6/20 15:56
*/
@Service
@Slf4j
public class COSFilesService {
/**
* 指定文件将要存放的存储桶
*/
@Value("${tencent.yun.bucketName}")
private String bucketName;
/**
* COS路径-访问域名
*/
@Value("${tencent.yun.url}")
private String COSUrl;
/**
* COS客户端
*/
@Resource
COSClient cosClient;
/**
* 上传文件到COS
*
* @param file 上传文件
* @return 该文件位于COS上的路径
*/
public String fileUpload(MultipartFile file) {
//文件名称 为了保证文件名称唯一,此处使用uuid来设置文件名称
String filename = IdUtil.fastSimpleUUID() + "_" + file.getOriginalFilename();
//目录的生成 当前日期
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
String date = dateFormat.format(new Date());
// 指定文件上传到 COS 上的路径,即对象键。例如对象键为folder/picture.jpg,则表示将文件 picture.jpg 上传到 folder 路径下
//此处目录规则为:当前日期/文件名称
String key = date + "/" + filename;
//将multipartFile转为file
File toFile = multipartFileToFile(file);
//COS上传操作
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, toFile);
PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);
log.info("putObjectResult:" + putObjectResult);
//删除本地上传资源
deleteTempFile(multipartFileToFile(file));
//下载链接
String fileDownloadLink = COSUrl + "/" + key;
System.out.println("fileDownloadLink: " + fileDownloadLink);
/*
//为文件设置一个过期时间
Date expiration = new Date(new Date().getTime() + 5 * 60 * 10000);
GeneratePresignedUrlRequest req =
new GeneratePresignedUrlRequest(bucketName, key, HttpMethodName.GET);
// 设置签名过期时间(可选), 若未进行设置, 则默认使用 ClientConfig 中的签名过期时间(1小时)
// 可以设置任意一个未来的时间,推荐是设置 10 分钟到 3 天的过期时间
req.setExpiration(expiration);
URL url = cosClient.generatePresignedUrl(req);
//关闭客户端
cosClient.shutdown();
//拼接文件地址
StringBuffer stringBuffer = new StringBuffer()
.append(url.getProtocol())
.append("://")
.append(url.getHost())
.append(url.getPath());*/
//该文件位于COS上的路径
//putObjectResult.toString() == key
return putObjectResult.toString();
}
/**
* 查询存储桶中对象列表
*
* @param PrefixPath 腾讯云COS对应桶下某个文件夹
*/
public void selectFiles(String PrefixPath) {
// Bucket的命名格式为 BucketName-APPID ,此处填写的存储桶名称必须为此格式
//String bucketName = "examplebucket-1250000000";
ListObjectsRequest listObjectsRequest = new ListObjectsRequest();
// 设置bucket名称
listObjectsRequest.setBucketName(bucketName);
// prefix表示列出的object的key以prefix开始
listObjectsRequest.setPrefix(PrefixPath);
// deliter表示分隔符
// 设置为/表示列出当前目录下的object, 设置为空表示列出所有的object
listObjectsRequest.setDelimiter("");
// 设置最大遍历出多少个对象, 一次listobject最大支持1000
listObjectsRequest.setMaxKeys(1000);
ObjectListing objectListing = null;
log.info("");
do {
try {
objectListing = cosClient.listObjects(listObjectsRequest);
} catch (CosServiceException e) {
e.printStackTrace();
return;
} catch (CosClientException e) {
e.printStackTrace();
return;
}
// common prefix表示表示被delimiter截断的路径, 如delimter设置为/, common prefix则表示所有子目录的路径
List<String> commonPrefixs = objectListing.getCommonPrefixes();
for (String commonPrefix : commonPrefixs) {
log.info("commonPrefix: " + commonPrefix);
}
// 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();
log.info("key: " + key);
log.info("fileSize: " + fileSize);
log.info("");
}
String nextMarker = objectListing.getNextMarker();
log.info("nextMarker: " + nextMarker);
listObjectsRequest.setMarker(nextMarker);
log.info("listObjectsRequest: " + listObjectsRequest);
log.info("");
} while (objectListing.isTruncated());
}
/**
* 下载文件
* 参考文档:https://cloud.tencent.com/document/product/436/65937#.E4.B8.8B.E8.BD.BD.E5.AF.B9.E8.B1.A12 的最后
*
* @param COSKey 指定文件在 COS 上的路径,即对象键。例如对象键为folder/picture.jpg,则表示下载的文件 picture.jpg 在 folder 路径下
* @return 下载链接
*/
public String downloadFile(String COSKey) {
// Bucket的命名格式为 BucketName-APPID ,此处填写的存储桶名称必须为此格式
//String bucketName = "examplebucket-1250000000";
// 指定文件在 COS 上的路径,即对象键。例如对象键为folder/picture.jpg,则表示下载的文件 picture.jpg 在 folder 路径下
//String COSKey = "exampleobject";
GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, COSKey);
COSObjectInputStream cosObjectInput = null;
String downloadLink = null;
try {
COSObject cosObject = cosClient.getObject(getObjectRequest);
cosObjectInput = cosObject.getObjectContent();
System.out.println(cosObjectInput.getHttpRequest());//GET https://xxxxx HTTP/1.1
URI downloadUri = cosObjectInput.getHttpRequest().getURI();
downloadLink = String.valueOf(downloadUri);
System.out.println(downloadLink);
} catch (CosServiceException e) {
e.printStackTrace();
} catch (CosClientException e) {
e.printStackTrace();
}
// 处理下载到的流
// 这里是直接读取,按实际情况来处理
byte[] bytes = null;
try {
bytes = IOUtils.toByteArray(cosObjectInput);
} catch (IOException e) {
e.printStackTrace();
} finally {
// 用完流之后一定要调用 close()
try {
cosObjectInput.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// 在流没有处理完之前,不能关闭 cosClient
// 确认本进程不再使用 cosClient 实例之后,关闭之
cosClient.shutdown();
return downloadLink;
}
/**
* 删除文件
*
* @param COSKey 指定文件在 COS 上的路径,即对象键。例如对象键为folder/picture.jpg,则表示下载的文件 picture.jpg 在 folder 路径下
* @return 是否成功
*/
public Boolean deleteFile(String COSKey) {
// Bucket的命名格式为 BucketName-APPID ,此处填写的存储桶名称必须为此格式
//String bucketName = "examplebucket-1250000000";
// 指定被删除的文件在 COS 上的路径,即对象键。例如对象键为folder/picture.jpg,则表示删除位于 folder 路径下的文件 picture.jpg
//String COSKey = "exampleobject";
cosClient.deleteObject(bucketName, COSKey);
return true;
}
/**
* 将multipartFile转为file
*
* @param file
* @return java.io.File
**/
private File multipartFileToFile(MultipartFile file) {
File toFile = null;
if (file.equals("") || file.getSize() <= 0) {
file = null;
} else {
try {
InputStream ins = null;
ins = file.getInputStream();
toFile = new File(file.getOriginalFilename());
//获取流文件
inputStreamToFile(ins, toFile);
ins.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return toFile;
}
/**
* 获取流文件
*
* @param ins
* @param file
*/
private static void inputStreamToFile(InputStream ins, File file) {
try {
OutputStream os = new FileOutputStream(file);
int bytesRead = 0;
byte[] buffer = new byte[8192];
while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
os.write(buffer, 0, bytesRead);
}
os.close();
ins.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 删除本地临时文件
*
* @param file
*/
public static void deleteTempFile(File file) {
if (file != null) {
File del = new File(file.toURI());
del.delete();
}
}
}
测试类
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.StrUtil;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.exception.CosServiceException;
import com.qcloud.cos.model.CannedAccessControlList;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.model.PutObjectResult;
import com.xunan.boot.Application;
import com.xunan.boot.service.COSFilesService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import java.io.File;
/**
* @author xn
* @date 2022/6/20 16:20
*/
@SpringBootTest(classes = Application.class)
public class COSTest {
@Value("${tencent.yun.bucketName}")
private String bucketName;
@Value("${tencent.yun.url}")
private String url;
/**
* COS客户端
*/
@Resource
COSClient cosClient;
@Resource
COSFilesService cosFilesService;
//上传的文件路径
String filePath = "C:\\Users\\23537\\Desktop\\基础教育热点问题研究.doc";
/**
* 上传文件
*/
@Test
public void upLoad() {
try {
// 指定要上传的文件
File localFile = new File(filePath);
// 指定要上传到 COS 上对象键
String key = getFileKey(filePath);
System.out.println("key---------: " + key);
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, localFile);
//putObjectResult == key
PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);
System.out.println("putObjectResult---------: " + key);
//下载链接
System.out.println("url---------: " + url + "/" + key);
//删除本地临时文件
COSFilesService.deleteTempFile(localFile);
System.out.println("----END----");
} catch (CosServiceException serverException) {
serverException.printStackTrace();
} catch (CosClientException clientException) {
clientException.printStackTrace();
}
}
/**
* 生成文件路径
*
* @return 文件路径
*/
private String getFileKey(String originalfileName) {
String filePath = "test/";
//1.获取后缀名 2.去除文件后缀 替换所有特殊字符
String fileType = originalfileName.substring(originalfileName.lastIndexOf("."));
String fileStr = StrUtil.removeSuffix(originalfileName, fileType).replaceAll("[^0-9a-zA-Z\\u4e00-\\u9fa5]", "_");
filePath += new DateTime().toString("yyyyMMddHHmmss") + "_" + fileStr + fileType;
return filePath;
}
/**
* 查询存储桶中对象列表
*/
@Test
public void selectFilesTest() {
//腾讯云COS对应桶下某个文件夹
String PrefixPath = "test/";
//String PrefixPath = "20220620163625_C__Users_23537_Desktop_基础教育热点问题研究.doc"; //也是查不到的
//String PrefixPath = "test/20220620f/";
//String PrefixPath = "20220620f/"; //这样写是查不到的,因为没有这个目录,只有上面样子的目录
cosFilesService.selectFiles(PrefixPath);
}
/**
* 下载文件
*/
@Test
public void downloadFileTest() {
//腾讯云COS对应桶下某个文件夹
String COSKey = "test/20220620173232_C__Users_23537_Desktop_基础教育热点问题研究.doc";
cosFilesService.downloadFile(COSKey);
}
/**
* 删除文件
*/
@Test
public void deleteFileTest() {
//腾讯云COS对应桶下某个文件夹
String COSKey = "test/20220620163625_C__Users_23537_Desktop_基础教育热点问题研究.doc";
cosFilesService.deleteFile(COSKey);
}
}
完整项目依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>COSdemo-boot-project</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<artifactId>spring-boot-dependencies</artifactId>
<groupId>org.springframework.boot</groupId>
<version>2.3.12.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--腾讯云COS-->
<dependency>
<groupId>com.qcloud</groupId>
<artifactId>cos_api</artifactId>
<version>5.6.89</version>
</dependency>
<!--MyBaits-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<!--MySQL 连接组件-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--Druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
<!-- Druid Spring Boot 组件-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
<!--Spring Boot Aop-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!--Spring Validation-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!--Spring Boot 测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--Junit-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<!--LomBok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--Hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.16</version>
</dependency>
<!--Spring Boot Web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--Spring Boot Actuator-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--Fast Json-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.78</version>
</dependency>
</dependencies>
</project>