Compare commits

...

2 Commits

Author SHA1 Message Date
yuanjs@qutke.com 2d1c7934f5 feat: 更新文档 2 weeks ago
yuanjs@qutke.com 518d24b85d feat: 更新文档 3 weeks ago
  1. 33860
      README.md
  2. 12
      src/main/java/org/ycloud/aipan/config/AmazonS3Config.java
  3. 6
      src/main/java/org/ycloud/aipan/enums/BizCodeEnum.java
  4. 64
      src/main/java/org/ycloud/aipan/service/impl/AccountFileServiceImpl.java
  5. 16
      src/main/resources/application.yml
  6. 4
      src/test/java/org/ycloud/aipan/AmazonS3ClientTests.java

33860
README.md

File diff suppressed because it is too large

12
src/main/java/org/ycloud/aipan/config/AmazonS3Config.java

@ -21,10 +21,10 @@ import org.springframework.context.annotation.Configuration;
public class AmazonS3Config { public class AmazonS3Config {
// 注入Minio配置类,用于获取访问密钥和Endpoint等信息 // 注入Minio配置类,用于获取访问密钥和Endpoint等信息
// @Resource
// private MinioConfig minioConfig;
@Resource @Resource
private AliOssConfig aliOssConfig; private MinioConfig minioConfig;
// @Resource
// private AliOssConfig aliOssConfig;
/** /**
* 创建并配置Amazon S3客户端 * 创建并配置Amazon S3客户端
@ -41,16 +41,16 @@ public class AmazonS3Config {
config.setConnectionTimeout(5000); config.setConnectionTimeout(5000);
config.setUseExpectContinue(true); config.setUseExpectContinue(true);
// 使用配置中的访问密钥和秘密密钥创建AWS凭证 // 使用配置中的访问密钥和秘密密钥创建AWS凭证
AWSCredentials credentials = new BasicAWSCredentials(aliOssConfig.getAccessKey(), aliOssConfig.getAccessSecret()); AWSCredentials credentials = new BasicAWSCredentials(minioConfig.getAccessKey(), minioConfig.getAccessSecret());
// 设置Endpoint // 设置Endpoint
AwsClientBuilder.EndpointConfiguration endpointConfiguration = new AwsClientBuilder AwsClientBuilder.EndpointConfiguration endpointConfiguration = new AwsClientBuilder
.EndpointConfiguration(aliOssConfig.getEndpoint(), Regions.US_EAST_1.name()); .EndpointConfiguration(minioConfig.getEndpoint(), Regions.US_EAST_1.name());
// 使用以上配置创建并返回Amazon S3客户端实例 // 使用以上配置创建并返回Amazon S3客户端实例
return AmazonS3ClientBuilder.standard() return AmazonS3ClientBuilder.standard()
.withClientConfiguration(config) .withClientConfiguration(config)
.withCredentials(new AWSStaticCredentialsProvider(credentials)) .withCredentials(new AWSStaticCredentialsProvider(credentials))
.withEndpointConfiguration(endpointConfiguration) .withEndpointConfiguration(endpointConfiguration)
.withPathStyleAccessEnabled(false) // mino设置为true,oss设置为false .withPathStyleAccessEnabled(true) // mino设置为true,oss设置为false
.build(); .build();

6
src/main/java/org/ycloud/aipan/enums/BizCodeEnum.java

@ -31,7 +31,11 @@ public enum BizCodeEnum {
SHARE_CANCEL(260406, "分享已取消"), SHARE_CANCEL(260406, "分享已取消"),
SHARE_EXPIRED(260407, "分享已过期"), SHARE_EXPIRED(260407, "分享已过期"),
SHARE_FILE_ILLEGAL(260408, "分享的文件不合规"), SHARE_FILE_ILLEGAL(260408, "分享的文件不合规"),
FILE_BATCH_UPDATE_ERROR(270101,"文件批量操作错误" ); FILE_BATCH_UPDATE_ERROR(270101,"文件批量操作错误" ),
FILE_DIR_NOT_EXIST(270102,"用户的上级目录不存在" ),
FILE_DIR_ERROR(270103,"用户的上级目录错误" ),
;
private final int code; private final int code;
private final String message; private final String message;

64
src/main/java/org/ycloud/aipan/service/impl/AccountFileServiceImpl.java

@ -58,7 +58,32 @@ public class AccountFileServiceImpl implements AccountFileService {
@Override @Override
public Long createFolder(FolderCreateReq req) { public Long createFolder(FolderCreateReq req) {
AccountFileDTO accountFileDTO = AccountFileDTO.builder().accountId(req.getAccountId()) // 创建文件夹时,父ID必须是该用户下的
if (req.getParentId() != null) {
if (req.getParentId() == 0L) {
// 用户根目录不能操作
throw new BizException(BizCodeEnum.FILE_DIR_NOT_EXIST);
}
// 校验该用户下是否存在该父级id
Long sum = accountFileMapper.selectCount(new QueryWrapper<AccountFileDO>()
.eq("id", req.getParentId()).eq("account_id", req.getAccountId()));
if (sum == 0) {
throw new BizException(BizCodeEnum.FILE_DIR_NOT_EXIST);
}
if (sum > 1) {
throw new BizException(BizCodeEnum.FILE_DIR_ERROR);
}
} else {
AccountFileDO fileUser = accountFileMapper.selectOne(new QueryWrapper<AccountFileDO>()
.eq("parent_id", 0L).eq("account_id", req.getAccountId()));
if (fileUser == null) {
// 用户根目录不存在
throw new BizException(BizCodeEnum.FILE_DIR_ERROR);
}
req.setParentId(fileUser.getId());
}
AccountFileDTO accountFileDTO = AccountFileDTO.builder()
.accountId(req.getAccountId())
.parentId(req.getParentId()) .parentId(req.getParentId())
.fileName(req.getFolderName()) .fileName(req.getFolderName())
.isDir(FolderFlagEnum.YES.getCode()).build(); .isDir(FolderFlagEnum.YES.getCode()).build();
@ -106,7 +131,7 @@ public class AccountFileServiceImpl implements AccountFileService {
.eq("is_dir", FolderFlagEnum.YES.getCode()) .eq("is_dir", FolderFlagEnum.YES.getCode())
); );
if(CollectionUtils.isEmpty(folderList)){ if (CollectionUtils.isEmpty(folderList)) {
return List.of(); return List.of();
} }
//构建一个map, key是文件ID,value是文件对象 相当于一个数据源 //构建一个map, key是文件ID,value是文件对象 相当于一个数据源
@ -123,7 +148,7 @@ public class AccountFileServiceImpl implements AccountFileService {
//构建文件树,遍历数据源,为每个文件夹找到子文件夹 //构建文件树,遍历数据源,为每个文件夹找到子文件夹
for (FolderTreeNodeDTO node : folderMap.values()) { for (FolderTreeNodeDTO node : folderMap.values()) {
Long parentId = node.getParentId(); Long parentId = node.getParentId();
if(parentId!=null && folderMap.containsKey(parentId)){ if (parentId != null && folderMap.containsKey(parentId)) {
//获取父文件 //获取父文件
FolderTreeNodeDTO parentNode = folderMap.get(parentId); FolderTreeNodeDTO parentNode = folderMap.get(parentId);
//获取父文件夹的子节点位置 //获取父文件夹的子节点位置
@ -141,14 +166,16 @@ public class AccountFileServiceImpl implements AccountFileService {
return rootFolderList; return rootFolderList;
} }
/** /**
* 查询文件树接口 非递归方式 * 查询文件树接口 非递归方式
* 1查询用户全部文件夹 * 1查询用户全部文件夹
* 2拼装文件树 * 2拼装文件树
*
* @param accountId * @param accountId
* @return * @return
*/ */
//@Override //@Override
public List<FolderTreeNodeDTO> folderTreeV2(Long accountId) { public List<FolderTreeNodeDTO> folderTreeV2(Long accountId) {
//查询用户全部文件夹 //查询用户全部文件夹
List<AccountFileDO> folderList = accountFileMapper.selectList(new QueryWrapper<AccountFileDO>() List<AccountFileDO> folderList = accountFileMapper.selectList(new QueryWrapper<AccountFileDO>()
@ -156,7 +183,7 @@ public class AccountFileServiceImpl implements AccountFileService {
.eq("is_dir", FolderFlagEnum.YES.getCode()) .eq("is_dir", FolderFlagEnum.YES.getCode())
); );
if(CollectionUtils.isEmpty(folderList)){ if (CollectionUtils.isEmpty(folderList)) {
return List.of(); return List.of();
} }
@ -172,10 +199,10 @@ public class AccountFileServiceImpl implements AccountFileService {
.stream().collect(Collectors.groupingBy(FolderTreeNodeDTO::getParentId)); .stream().collect(Collectors.groupingBy(FolderTreeNodeDTO::getParentId));
//处理拼装文件树 //处理拼装文件树
for(FolderTreeNodeDTO node : folderTreeNodeDTOList){ for (FolderTreeNodeDTO node : folderTreeNodeDTOList) {
List<FolderTreeNodeDTO> children = folderMap.get(node.getId()); List<FolderTreeNodeDTO> children = folderMap.get(node.getId());
//判断是否为空 //判断是否为空
if(!CollectionUtils.isEmpty(children)){ if (!CollectionUtils.isEmpty(children)) {
node.getChildren().addAll(children); node.getChildren().addAll(children);
} }
} }
@ -199,7 +226,7 @@ public class AccountFileServiceImpl implements AccountFileService {
//上传到存储引擎 //上传到存储引擎
String storeFileObjectKey = storeFile(req); String storeFileObjectKey = storeFile(req);
//保存文件关系 + 保存账号和文件的关系 //保存文件关系 + 保存账号和文件的关系
saveFileAndAccountFile( req,storeFileObjectKey); saveFileAndAccountFile(req, storeFileObjectKey);
} }
/** /**
@ -214,7 +241,7 @@ public class AccountFileServiceImpl implements AccountFileService {
public void moveBatch(FileBatchReq req) { public void moveBatch(FileBatchReq req) {
// 检查被移动的文件ID是否合法 // 检查被移动的文件ID是否合法
List<AccountFileDO> accountFileDOList = checkFileIdLegal(req.getFileIds(),req.getAccountId()); List<AccountFileDO> accountFileDOList = checkFileIdLegal(req.getFileIds(), req.getAccountId());
//检查目标文件夹ID是否合法,包括子文件夹 //检查目标文件夹ID是否合法,包括子文件夹
checkTargetParentIdLegal(req); checkTargetParentIdLegal(req);
@ -224,10 +251,10 @@ public class AccountFileServiceImpl implements AccountFileService {
//更新文件或者文件夹的parent_id为目标文件夹的ID //更新文件或者文件夹的parent_id为目标文件夹的ID
UpdateWrapper<AccountFileDO> updateWrapper = new UpdateWrapper<>(); UpdateWrapper<AccountFileDO> updateWrapper = new UpdateWrapper<>();
updateWrapper.in("id",req.getFileIds()) updateWrapper.in("id", req.getFileIds())
.set("parent_id",req.getTargetParentId()); .set("parent_id", req.getTargetParentId());
int updateCount = accountFileMapper.update(null, updateWrapper); int updateCount = accountFileMapper.update(null, updateWrapper);
if(updateCount!=req.getFileIds().size()){ if (updateCount != req.getFileIds().size()) {
throw new BizException(BizCodeEnum.FILE_BATCH_UPDATE_ERROR); throw new BizException(BizCodeEnum.FILE_BATCH_UPDATE_ERROR);
} }
@ -238,6 +265,7 @@ public class AccountFileServiceImpl implements AccountFileService {
* 检查目标文件夹ID是否合法,包括子文件夹 * 检查目标文件夹ID是否合法,包括子文件夹
* 1目标的文件ID不能是文件 * 1目标的文件ID不能是文件
* 2要操作的文件列表不能包括目标文件ID * 2要操作的文件列表不能包括目标文件ID
*
* @param req * @param req
*/ */
private void checkTargetParentIdLegal(FileBatchReq req) { private void checkTargetParentIdLegal(FileBatchReq req) {
@ -251,8 +279,10 @@ public class AccountFileServiceImpl implements AccountFileService {
throw new BizException(BizCodeEnum.FILE_TARGET_PARENT_ILLEGAL); throw new BizException(BizCodeEnum.FILE_TARGET_PARENT_ILLEGAL);
} }
} }
/** /**
* 检查被移动的文件ID是否合法 * 检查被移动的文件ID是否合法
*
* @param fileIds * @param fileIds
* @param accountId * @param accountId
* @return * @return
@ -262,7 +292,7 @@ public class AccountFileServiceImpl implements AccountFileService {
List<AccountFileDO> accountFileDOList = accountFileMapper List<AccountFileDO> accountFileDOList = accountFileMapper
.selectList(new QueryWrapper<AccountFileDO>().in("id", fileIds).eq("account_id", accountId)); .selectList(new QueryWrapper<AccountFileDO>().in("id", fileIds).eq("account_id", accountId));
if(accountFileDOList.size()!=fileIds.size()){ if (accountFileDOList.size() != fileIds.size()) {
log.error("文件ID数量不合法,ids={}", fileIds); log.error("文件ID数量不合法,ids={}", fileIds);
throw new BizException(BizCodeEnum.FILE_BATCH_UPDATE_ERROR); throw new BizException(BizCodeEnum.FILE_BATCH_UPDATE_ERROR);
} }
@ -273,12 +303,13 @@ public class AccountFileServiceImpl implements AccountFileService {
/** /**
* 保存文件和账号文件的关系到数据库 * 保存文件和账号文件的关系到数据库
*
* @param req * @param req
* @param storeFileObjectKey * @param storeFileObjectKey
*/ */
public void saveFileAndAccountFile(FileUploadReq req, String storeFileObjectKey) { public void saveFileAndAccountFile(FileUploadReq req, String storeFileObjectKey) {
//保存文件 //保存文件
FileDO fileDO = saveFile(req,storeFileObjectKey); FileDO fileDO = saveFile(req, storeFileObjectKey);
//保存文件账号关系 //保存文件账号关系
AccountFileDTO accountFileDTO = AccountFileDTO.builder() AccountFileDTO accountFileDTO = AccountFileDTO.builder()
@ -299,7 +330,7 @@ public class AccountFileServiceImpl implements AccountFileService {
FileDO fileDO = new FileDO(); FileDO fileDO = new FileDO();
fileDO.setAccountId(req.getAccountId()); fileDO.setAccountId(req.getAccountId());
fileDO.setFileName(req.getFilename()); fileDO.setFileName(req.getFilename());
fileDO.setFileSize(req.getFile() !=null ? req.getFile().getSize():req.getFileSize()); fileDO.setFileSize(req.getFile() != null ? req.getFile().getSize() : req.getFileSize());
fileDO.setFileSuffix(CommonUtil.getFileSuffix(req.getFilename())); fileDO.setFileSuffix(CommonUtil.getFileSuffix(req.getFilename()));
fileDO.setObjectKey(storeFileObjectKey); fileDO.setObjectKey(storeFileObjectKey);
fileDO.setIdentifier(req.getIdentifier()); fileDO.setIdentifier(req.getIdentifier());
@ -309,15 +340,16 @@ public class AccountFileServiceImpl implements AccountFileService {
/** /**
* 上传文件到存储引擎返回存储的文件路径 * 上传文件到存储引擎返回存储的文件路径
*
* @param req * @param req
* @return * @return
*/ */
private String storeFile(FileUploadReq req) { private String storeFile(FileUploadReq req) {
String objectKey = CommonUtil.getFilePath(req.getFilename()); String objectKey = CommonUtil.getFilePath(req.getFilename());
fileStoreEngine.upload(minioConfig.getBucketName(), objectKey, req.getFile()); fileStoreEngine.upload(minioConfig.getBucketName(), objectKey, req.getFile());
return objectKey; return objectKey;
} }
/** /**
* 处理用户和文件的关系存储文件和文件夹都是可以的 * 处理用户和文件的关系存储文件和文件夹都是可以的
* <p> * <p>

16
src/main/resources/application.yml

@ -4,12 +4,16 @@ server:
spring: spring:
application: application:
name: ycloud-aipan name: ycloud-aipan
servlet:
multipart:
max-file-size: 10MB
max-request-size: 10MB
datasource: datasource:
driver-class-name: com.mysql.cj.jdbc.Driver driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://47.98.137.138:3306/ycloud-aipan?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true url: jdbc:mysql://117.72.43.105:3306/ycloud-aipan?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: root username: root
password: Yuan625621105 password: Yuan625621105.
data: data:
redis: redis:
@ -40,10 +44,12 @@ mybatis-plus:
# minio配置 # minio配置
minio: minio:
endpoint: http://192.168.60.124:9000 endpoint: http://106.75.254.18:9000
access-key: minio_root access-key: yuanjs
access-secret: minio_123456 access-secret: yuanjs625621105
# bucket需要创建,程序启动后不会自动创建
bucket-name: ai-pan bucket-name: ai-pan
# 头像要使返回的url直接可访问,需要再创建bucket后设置访问策略为public
avatar-bucket-name: avatar avatar-bucket-name: avatar

4
src/test/java/org/ycloud/aipan/AmazonS3ClientTests.java

@ -51,7 +51,7 @@ class AmazonS3ClientTests {
*/ */
@Test @Test
public void testDeleteBucket() { public void testDeleteBucket() {
String bucketName = "tjcz-app"; String bucketName = "forward-tech";
amazonS3Client.deleteBucket(bucketName); amazonS3Client.deleteBucket(bucketName);
} }
@ -93,7 +93,7 @@ class AmazonS3ClientTests {
*/ */
@Test @Test
public void testUploadFile2() { public void testUploadFile2() {
amazonS3Client.putObject("ai-pan", "test2.txt", new File("/Users/xdclass/Desktop/dpan.sql")); amazonS3Client.putObject("ai-pan", "test2.txt", new File("D:\\IdeaProjects\\learn\\ycloud-aipan\\doc\\ycloud-pan.sql"));
} }
/** /**

Loading…
Cancel
Save