分片上传相关接口

This commit is contained in:
tianliyong 2023-08-21 09:49:41 +08:00
parent 1000f6dfa0
commit 3f17c4233b
20 changed files with 553 additions and 48 deletions

View File

@ -1,3 +1,44 @@
# oss
# oss 对象存储服务
存储系统
## 介绍
- 项目介绍说明地址https://showdoc.axzo.cn/web/#/102?page_id=987
- 项目接入说明地址https://showdoc.axzo.cn/web/#/102?page_id=908
- 项目API说明地址https://yapi.axzo.cn/project/950/interface/api
## 业务支持场景
### 业务服务新接入进行sql语句配置
以前端app有文件上传需求进行接入oss服务进行sql语句配置为例appCode=app
```mysql
INSERT INTO `app_channel_bucket` (`app_channel_bucket_no`, `app_code`, `channel_code`, `bucket_name`, `access_control`, `remark`, `extension`, `create_at`, `update_at`, `create_by`, `update_by`, `is_delete`) VALUES ('app:aliyun:app', 'app', 'aliyun', 'axzo-public', '', NULL, NULL, now(), now(), '', '', 0);
INSERT INTO `file_app` (`app_code`, `app_name`, `status`, `remark`, `extension`, `create_at`, `update_at`, `create_by`, `update_by`, `is_delete`) VALUES ('app', 'app', 1, 'app', NULL, now(), now(), '', '', 0);
INSERT INTO `file_business_scene` (`app_channel_bucket_no`, `app_code`, `channel_code`, `bucket_name`, `business_scene`, `directory`, `create_at`, `update_at`, `create_by`, `update_by`, `is_delete`) VALUES ('app:aliyun:app', 'app', 'aliyun', 'axzo-public', 'app', 'app/app', now(), now(), NULL, NULL, 0);
INSERT INTO `file_upload_config` (`app_channel_bucket_no`, `app_code`, `channel_code`, `bucket_name`, `directory`, `storage_unit`, `storage_size`, `file_format`, `create_at`, `update_at`, `create_by`, `update_by`, `is_delete`) VALUES ('app:aliyun:app', 'app', 'aliyun', 'axzo-public', 'app/app', 'MB', 100, 'png,jpg,xls,xlsx,docx,pdf,zip,dwg,doc,jpeg', now(), now(), NULL, NULL, 0);
```
### 已接入业务服务支持文件格式配置
例如appCode=cms需要支持rar格式文件上传, 支持处理的方式为:
修改file_upload_config表对字段file_format进行调整执行以下语句即可
```mysql
update `file_upload_config` SET `file_format` = 'png,jpg,zip,jpeg,pdf,gif,xls,doc,docx,xlsx,bmp,rar' WHERE `app_code` = 'cms'
```
## 当前提供的能力
- 文件上传功能
- 上传功能对接操作日志记录服务。
- 对接用户授权获取用户信息。
- 根据fileKey获取文件流返回。
- 获取文件url兼容处理传输的为url直接返回。
- 支持app端历史数据不存在进行新增处理。
- 获取文件Url支持返回原文件名。
- 支持图片处理尺寸样式。
- 文件流下载。
- 分片上传。
## 未来可扩展
- oss服务业务支持场景手动配置sql语句可切换为管理界面处理效率提高可追溯。方案
- oss封装提供给表的curd api接口。
- 基础技术管理后台对接调用 oss提供的api接口进行业务接入或者已接入业务服务调整文件格式配置。
- oss服务重构简化流程
- 多子模块架构,调用链路太长,新功能支持开发较繁琐。

2
RELEASE.md Normal file
View File

@ -0,0 +1,2 @@
# 发布记录

View File

@ -4,18 +4,11 @@ import cn.axzo.core.utils.converter.BeanConverter;
import cn.axzo.framework.auth.annotation.PreBuildContext;
import cn.axzo.framework.auth.domain.ContextInfo;
import cn.axzo.framework.auth.domain.ContextInfoHolder;
import cn.axzo.oss.client.vo.FileInformationVo;
import cn.axzo.oss.client.vo.FindFileUrlVo;
import cn.axzo.oss.client.vo.WebFileUploadVo;
import cn.axzo.oss.client.vo.*;
import cn.axzo.oss.common.exception.BizException;
import cn.axzo.oss.common.utils.BeanConvertUtil;
import cn.axzo.oss.manager.api.dto.request.FindFileUrlDto;
import cn.axzo.oss.manager.api.dto.request.ServerFileDownloadDto;
import cn.axzo.oss.manager.api.dto.request.ServerFileUploadDto;
import cn.axzo.oss.manager.api.dto.response.FileInformationResponse;
import cn.axzo.oss.manager.api.dto.response.FindFileUrlResponse;
import cn.axzo.oss.manager.api.dto.response.ServerFileDownloadResponse;
import cn.axzo.oss.manager.api.dto.response.ServerFileUploadResponse;
import cn.axzo.oss.manager.api.dto.request.*;
import cn.axzo.oss.manager.api.dto.response.*;
import cn.axzo.oss.service.api.FileService;
import cn.azxo.framework.common.model.CommonResponse;
import lombok.SneakyThrows;
@ -99,6 +92,48 @@ public class WebFileController {
return CommonResponse.success(result);
}
@SneakyThrows
@PostMapping("/v1/multipart-upload/init")
@CrossOrigin
public CommonResponse<MultipartUploadInitVo> multipartUploadInit(@Valid @RequestBody MultipartUploadInitDto dto) {
MultipartUploadInitResponse response = fileService.multipartUploadInit(dto);
return CommonResponse.success(BeanConvertUtil.copyBean(response, MultipartUploadInitVo.class));
}
@SneakyThrows
@PostMapping(value = "/v1/multipart-upload", consumes = MULTIPART_FORM_DATA_VALUE)
@CrossOrigin
public CommonResponse<MultipartUploadVo> multipartUpload(@Valid @RequestParam("appCode") String appCode,
@Valid @RequestParam("bizScene") String bizScene,
@Valid @RequestParam("fileName") String fileName,
@Valid @RequestParam("tgtFileKey") String tgtFileKey,
@Valid @RequestParam("partNumber") Integer partNumber,
@Valid @RequestParam("partSize") Long partSize,
@Valid @RequestParam("uploadId") String uploadId,
@Valid @RequestPart MultipartFile file) {
MultipartUploadDto dto = MultipartUploadDto.builder()
.appCode(appCode)
.bizScene(bizScene)
.fileName(fileName)
.tgtFileKey(tgtFileKey)
.fileContent(file.getBytes())
.partNumber(partNumber)
.partSize(partSize)
.uploadId(uploadId)
.build();
MultipartUploadResponse response = fileService.multipartUpload(dto);
return CommonResponse.success(BeanConvertUtil.copyBean(response, MultipartUploadVo.class));
}
@PostMapping("/v1/multipart-upload/complete")
@CrossOrigin
@SneakyThrows
//@PreBuildContext
public CommonResponse<FileInformationVo> multipartUploadComplete(@Valid @RequestBody MultipartUploadCompleteDto dto) {
FileInformationResponse response = fileService.multipartUploadComplete(dto);
return CommonResponse.success(BeanConvertUtil.copyBean(response, FileInformationVo.class));
}
@SneakyThrows
@PostMapping("/v1/file/getUrl")
@CrossOrigin

View File

@ -0,0 +1,17 @@
package cn.axzo.oss.client.vo;
import lombok.Builder;
import lombok.Data;
/**
* @Author: liyong.tian
* @Date: 2023/8/15 17:29
* @Description:
*/
@Data
public class MultipartUploadInitVo {
private String uploadId;
private String tgtFileKey;
}

View File

@ -0,0 +1,17 @@
package cn.axzo.oss.client.vo;
import cn.axzo.oss.manager.api.dto.PartETag;
import lombok.Data;
/**
* @Author: liyong.tian
* @Date: 2023/8/15 11:56
* @Description:
*/
@Data
public class MultipartUploadVo {
private String uploadId;
private PartETag partETag;
}

View File

@ -9,7 +9,7 @@ spring:
namespace: ${NACOS_NAMESPACE_ID:35eada10-9574-4db8-9fea-bc6a4960b6c7}
prefix: ${spring.application.name}
profiles:
active: ${NACOS_PROFILES_ACTIVE:dev}
active: ${NACOS_PROFILES_ACTIVE:local}
main:
allow-bean-definition-overriding: true

View File

@ -44,6 +44,9 @@ public enum CodeEnum implements EnumBase<Integer> {
FILE_NAME_TOO_LONG(111, "file name too long max 128"),
FILE_NOT_FOUND(112, "file not found"),
MULTIPART_UPLOAD_INIT_ERROR(113, "file multipart upload init error"),
MULTIPART_UPLOAD_ERROR(114, "file multipart upload error"),
MULTIPART_UPLOAD_COMPLETE_ERROR(115, "file multipart upload complete error")
;

View File

@ -1,9 +1,15 @@
package cn.axzo.oss.common.utils;
import cn.hutool.core.collection.CollUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.BiConsumer;
/**
* @Author admin
* @Description
@ -25,4 +31,34 @@ public class BeanConvertUtil {
}
return target;
}
public static <T> List<T> copyList(Collection<?> list, Class<T> targetCls) {
List<T> result = new ArrayList<T>();
if (list == null || list.size() == 0) {
return result;
}
for (Object obj : list) {
result.add(copyBean(obj, targetCls));
}
return result;
}
public static <S, T> List<T> copyList(Collection<S> list, Class<T> targetCls, BiConsumer<S, T> action) {
List<T> result = new ArrayList<T>();
if (CollUtil.isEmpty(list)) {
return result;
}
for (S obj : list) {
T res = copyBean(obj, targetCls);
if (action != null) {
action.accept(obj, res);
}
result.add(res);
}
return result;
}
}

View File

@ -1,10 +1,12 @@
package cn.axzo.oss.integration.s3.base;
import com.aliyun.oss.model.PartETag;
import org.springframework.http.ResponseEntity;
import org.springframework.web.multipart.MultipartFile;
import java.io.FilterInputStream;
import java.io.InputStream;
import java.util.List;
/**
* @Author admin
@ -54,5 +56,10 @@ public interface BaseS3Service {
FilterInputStream getS3ObjectStream(String tgtFileKey);
String multipartUploadInit(String bucketName, String tgtFileKey);
PartETag multipartUpload(String bucketName, String tgtFileKey, String uploadId, InputStream instream,
Integer partNumber, long partSize);
String multipartUploadComplete(String bucketName, String tgtFileKey, String uploadId, List<PartETag> partETags);
}

View File

@ -1,14 +1,13 @@
package cn.axzo.oss.integration.s3.impl;
import cn.axzo.oss.common.exception.BizException;
import cn.axzo.oss.integration.s3.AliOssService;
import cn.axzo.oss.integration.s3.client.AliOssAppProClient;
import cn.axzo.oss.integration.s3.client.AliOssClient;
import cn.azxo.framework.common.utils.LogUtil;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
@ -19,8 +18,10 @@ import org.springframework.web.multipart.MultipartFile;
import java.io.FilterInputStream;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.List;
import static cn.axzo.oss.common.constans.CommonConstants.APP_PRO_BUCKET_NAME;
import static cn.axzo.oss.common.enums.CodeEnum.*;
/**
* @program: oss
@ -65,6 +66,10 @@ public class AliOssServiceImpl implements AliOssService {
return "";
}
return getUrl(bucketName, tgtFileKey);
}
private String getUrl(String bucketName, String tgtFileKey) {
StringBuilder allBuilder = new StringBuilder();
allBuilder.append("https://");
allBuilder.append(bucketName);
@ -141,4 +146,64 @@ public class AliOssServiceImpl implements AliOssService {
public FilterInputStream getS3ObjectStream(String tgtFileKey) {
return null;
}
@Override
public String multipartUploadInit(String bucketName, String tgtFileKey) {
OSS client = aliOssClient.getClient();
try {
// 创建分片上传对象
InitiateMultipartUploadRequest uploadRequest = new InitiateMultipartUploadRequest(bucketName, tgtFileKey);
// 初始化分片
InitiateMultipartUploadResult result = client.initiateMultipartUpload(uploadRequest);
// 返回uploadId它是分片上传事件的唯一标识您可以根据这个uploadId发起相关的操作如取消分片上传查询分片上传等
return result.getUploadId();
} catch (Exception e) {
e.printStackTrace();
LogUtil.error("ali oss multipart upload init error = {}", e);
throw new BizException(MULTIPART_UPLOAD_INIT_ERROR);
}
}
@Override
public PartETag multipartUpload(String bucketName, String tgtFileKey, String uploadId, InputStream instream,
Integer partNumber, long partSize) {
OSS client = aliOssClient.getClient();
try {
UploadPartRequest partRequest = new UploadPartRequest();
// 阿里云 oss 文件根目录
partRequest.setBucketName(bucketName);
// 文件key
partRequest.setKey(tgtFileKey);
// 分片上传uploadId
partRequest.setUploadId(uploadId);
// 分片文件
instream.skip((partNumber - 1) * partSize);
partRequest.setInputStream(instream);
// 分片大小除了最后一个分片没有大小限制其他的分片最小为100 KB
partRequest.setPartSize(partSize);
// 分片号每一个上传的分片都有一个分片号取值范围是1~10000如果超出这个范围OSS将返回InvalidArgument的错误码
partRequest.setPartNumber(partNumber);
// 每个分片不需要按顺序上传甚至可以在不同客户端上传OSS会按照分片号排序组成完整的文件
UploadPartResult uploadPartResult = client.uploadPart(partRequest);
// 每次上传分片之后OSS的返回结果包含PartETag
return uploadPartResult.getPartETag();
} catch (Exception e) {
e.printStackTrace();
throw new BizException(MULTIPART_UPLOAD_ERROR);
}
}
@Override
public String multipartUploadComplete(String bucketName, String tgtFileKey, String uploadId, List<PartETag> partETags) {
OSS client = aliOssClient.getClient();
try {
CompleteMultipartUploadRequest completeMultipartUploadRequest =
new CompleteMultipartUploadRequest(bucketName, tgtFileKey, uploadId, partETags);
client.completeMultipartUpload(completeMultipartUploadRequest);
return getUrl(bucketName, tgtFileKey);
} catch (Exception e) {
e.printStackTrace();
throw new BizException(MULTIPART_UPLOAD_COMPLETE_ERROR);
}
}
}

View File

@ -1,6 +1,11 @@
package cn.axzo.oss.manager.api;
import cn.axzo.oss.manager.api.dto.request.MultipartUploadDto;
import cn.axzo.oss.manager.api.dto.response.MultipartUploadResponse;
import com.aliyun.oss.model.PartETag;
import java.io.InputStream;
import java.util.List;
/**
* @Author admin
@ -37,4 +42,9 @@ public interface FileManager {
*/
InputStream downloadFile(String bucketName, String tgtFileKey, String style);
String multipartUploadInit(String bucketName, String tgtFileKey);
PartETag multipartUpload(String bucketName, String tgtFileKey, byte[] fileContent, MultipartUploadDto dto);
String multipartUploadComplete(String bucketName, String tgtFileKey, String uploadId, List<PartETag> partETags);
}

View File

@ -0,0 +1,17 @@
package cn.axzo.oss.manager.api.dto;
import lombok.Data;
/**
* @Author: liyong.tian
* @Date: 2023/8/18 16:13
* @Description:
*/
@Data
public class PartETag {
private int partNumber;
private String eTag;
private long partSize;
private Long partCRC;
}

View File

@ -0,0 +1,29 @@
package cn.axzo.oss.manager.api.dto.request;
import cn.axzo.oss.manager.api.dto.PartETag;
import lombok.Builder;
import lombok.Data;
import java.util.List;
/**
* @Author: liyong.tian
* @Date: 2023/8/15 15:03
* @Description:
*/
@Data
@Builder
public class MultipartUploadCompleteDto {
private String appCode;
private String bizScene;
private String fileName;
private String tgtFileKey;
private String uploadId;
private List<PartETag> partETags;
}

View File

@ -0,0 +1,49 @@
package cn.axzo.oss.manager.api.dto.request;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
/**
* @Author: liyong.tian
* @Date: 2023/8/15 11:39
* @Description:
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class MultipartUploadDto {
@NotBlank
private String appCode;
@NotBlank
private String bizScene;
@NotBlank
private String fileName;
@NotBlank
private String tgtFileKey;
private byte[] fileContent;
/**
* 当前为第几分片
*/
private int partNumber;
/**
* 当前分片大小
*/
private long partSize;
/**
* oss上传时的上传id
*/
private String uploadId;
}

View File

@ -0,0 +1,29 @@
package cn.axzo.oss.manager.api.dto.request;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
/**
* @Author: liyong.tian
* @Date: 2023/8/15 10:28
* @Description:
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class MultipartUploadInitDto {
@NotBlank
private String appCode;
@NotBlank
private String bizScene;
@NotBlank
private String fileName;
}

View File

@ -0,0 +1,18 @@
package cn.axzo.oss.manager.api.dto.response;
import lombok.Builder;
import lombok.Data;
/**
* @Author: liyong.tian
* @Date: 2023/8/15 17:28
* @Description:
*/
@Data
@Builder
public class MultipartUploadInitResponse {
private String uploadId;
private String tgtFileKey;
}

View File

@ -0,0 +1,20 @@
package cn.axzo.oss.manager.api.dto.response;
import cn.axzo.oss.manager.api.dto.PartETag;
import lombok.Builder;
import lombok.Data;
/**
* @Author: liyong.tian
* @Date: 2023/8/15 13:39
* @Description:
*/
@Data
@Builder
public class MultipartUploadResponse {
private String uploadId;
private PartETag partETag;
}

View File

@ -2,12 +2,16 @@ package cn.axzo.oss.manager.impl;
import cn.axzo.oss.integration.s3.AliOssService;
import cn.axzo.oss.manager.api.FileManager;
import cn.axzo.oss.manager.api.dto.request.MultipartUploadDto;
import cn.axzo.oss.manager.api.dto.response.MultipartUploadResponse;
import com.aliyun.oss.model.PartETag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.List;
/**
* @Author admin
@ -50,4 +54,21 @@ public class FileManagerImpl implements FileManager {
return aliOssService.downloadFile(bucketName, tgtFileKey, style);
}
@Override
public String multipartUploadInit(String bucketName, String tgtFileKey) {
return aliOssService.multipartUploadInit(bucketName, tgtFileKey);
}
@Override
public PartETag multipartUpload(String bucketName, String tgtFileKey, byte[] fileContent, MultipartUploadDto dto) {
InputStream inputStream = new ByteArrayInputStream(fileContent);
return aliOssService.multipartUpload(bucketName, tgtFileKey, dto.getUploadId(), inputStream,
dto.getPartNumber(), dto.getPartSize());
}
@Override
public String multipartUploadComplete(String bucketName, String tgtFileKey, String uploadId, List<PartETag> partETags) {
return aliOssService.multipartUploadComplete(bucketName, tgtFileKey, uploadId, partETags);
}
}

View File

@ -4,6 +4,7 @@ import cn.axzo.framework.auth.domain.ContextInfo;
import cn.axzo.oss.manager.api.dto.request.*;
import cn.axzo.oss.manager.api.dto.response.*;
import java.io.InputStream;
import java.util.List;
/**
@ -35,4 +36,10 @@ public interface FileService {
FileInformationResponse uploadV2(String serviceName, ServerFileUploadDto request, ContextInfo.LiteSaasContext liteSaasContext);
ServerFileDownloadResponse download(ServerFileDownloadDto dto);
MultipartUploadInitResponse multipartUploadInit(MultipartUploadInitDto multipartUploadInitDto);
MultipartUploadResponse multipartUpload(MultipartUploadDto dto);
FileInformationResponse multipartUploadComplete(MultipartUploadCompleteDto dto);
}

View File

@ -10,6 +10,7 @@ import cn.axzo.oss.common.enums.CodeEnum;
import cn.axzo.oss.common.enums.FileClassEnum;
import cn.axzo.oss.common.enums.FileStatusEnum;
import cn.axzo.oss.common.exception.BizException;
import cn.axzo.oss.common.utils.BeanConvertUtil;
import cn.axzo.oss.common.utils.JsonUtil;
import cn.axzo.oss.common.utils.Utility;
import cn.axzo.oss.dal.entity.*;
@ -23,8 +24,10 @@ import cn.axzo.oss.manager.api.dto.request.*;
import cn.axzo.oss.manager.api.dto.response.*;
import cn.axzo.oss.service.api.FileService;
import cn.hutool.core.collection.CollectionUtil;
import com.aliyun.oss.model.PartETag;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
@ -148,6 +151,47 @@ public class FileServiceImpl implements FileService {
return setFileInfoResp(ossFile);
}
@Override
public MultipartUploadInitResponse multipartUploadInit(MultipartUploadInitDto dto) {
FileUploadConfig fileUploadConfig = getFileUploadConfig(dto.getAppCode(), dto.getBizScene());
// 判断容量
String fileConform = isFileConform(fileUploadConfig, 10, dto.getFileName());
String uuid = Utility.getUUID();
// 生成上传文件的唯一key
String tgtFileKey = Utility.generateFileKey(fileUploadConfig.getDirectory(), uuid, fileConform);
String uploadId = fileManager.multipartUploadInit(fileUploadConfig.getBucketName(), tgtFileKey);
return MultipartUploadInitResponse.builder()
.uploadId(uploadId)
.tgtFileKey(tgtFileKey)
.build();
}
@Override
public MultipartUploadResponse multipartUpload(MultipartUploadDto dto) {
FileUploadConfig fileUploadConfig = getFileUploadConfig(dto.getAppCode(), dto.getBizScene());
// 判断容量
isFileConform(fileUploadConfig, dto.getFileContent().length, dto.getFileName());
PartETag partETag = fileManager.multipartUpload(fileUploadConfig.getBucketName(),
dto.getTgtFileKey(), dto.getFileContent(), dto);
MultipartUploadResponse response = MultipartUploadResponse.builder()
.uploadId(dto.getUploadId())
.partETag(BeanConvertUtil.copyBean(partETag, cn.axzo.oss.manager.api.dto.PartETag.class))
.build();
return response;
}
@Override
public FileInformationResponse multipartUploadComplete(MultipartUploadCompleteDto dto) {
FileUploadConfig fileUploadConfig = getFileUploadConfig(dto.getAppCode(), dto.getBizScene());
List<PartETag> partETags = convertPartETags(dto.getPartETags());
// 文件合并并生成 file对象
File ossFile = completeFile(fileUploadConfig, dto.getFileName(), dto.getTgtFileKey(),
dto.getUploadId(), partETags);
return setFileInfoResp(ossFile);
}
@Override
public ServerFileDownloadResponse download(ServerFileDownloadDto dto) {
log.info("file download dto = {}", JsonUtil.obj2Str(dto));
@ -163,7 +207,6 @@ public class FileServiceImpl implements FileService {
log.warn("file download is null, fileKey = {}", fileKey);
BizException.error(Utility.objIsNotNull(file), CodeEnum.FILE_NOT_FOUND);
}
//String tgtFileKey = Utility.generateFileKey(file.getDirectory(), file.getFileUuid(), file.getFileFormat());
//兼容app端oss历史上传文件的url处理
String tgtFileKey = file.getFileUrl().substring(file.getFileUrl().indexOf(HTTP_COM) + 5);
log.info("file download tgtFileKey = {}", tgtFileKey);
@ -176,6 +219,74 @@ public class FileServiceImpl implements FileService {
return setFileDownloadResponse(file, fileStream);
}
private List<PartETag> convertPartETags(List<cn.axzo.oss.manager.api.dto.PartETag> partETags) {
List<PartETag> partETagList = new ArrayList<>();
if (CollectionUtils.isNotEmpty(partETags)) {
partETags.stream().forEach(partETag -> {
PartETag ossPartETag = new PartETag(partETag.getPartNumber(), partETag.getETag(),
partETag.getPartSize(), partETag.getPartCRC());
partETagList.add(ossPartETag);
});
}
return partETagList;
}
private FileUploadConfig getFileUploadConfig(String appCode, String bizScene) {
// 检查appCode
checkAppCode(appCode);
// 通过appcode获取文件渠道桶信息
AppChannelBucket appChannelBucket = appChannelBucketManager.getByAppCode(appCode);
// 通过渠道桶编码获取到具体文件业务场景
FileBusinessScene scene = fileBusinessSceneManager
.getByBucketNoAndScene(appChannelBucket.getAppChannelBucketNo(), bizScene);
// 通过渠道码和桶名称获取获取指定上传配置
FileUploadConfig fileUploadConfig = fileUploadConfigManager
.getByUploadConfig(scene.getAppChannelBucketNo(), scene.getDirectory());
return fileUploadConfig;
}
private File completeFile(FileUploadConfig fileUploadConfig, String fileName, String tgtFileKey, String uploadId, List<PartETag> partETags) {
// 文件合并
String fileUrl = fileManager.multipartUploadComplete(fileUploadConfig.getBucketName(), tgtFileKey, uploadId, partETags);
// 保存失败
if (Utility.isBlank(fileUrl)) {
log.error("fileUrl is empty");
throw new BizException(CodeEnum.MULTIPART_UPLOAD_COMPLETE_ERROR);
}
int lastIndexOf = tgtFileKey.lastIndexOf(FileClassEnum.SEPARATOR_CHAR.type);
String newFileName = tgtFileKey.substring(lastIndexOf + 1);
int indexOf = newFileName.indexOf(FileClassEnum.DOT.type);
String fileConform = newFileName.substring(indexOf + 1).toLowerCase();
String uuid = newFileName.substring(0, indexOf);
return getOssFile(fileUploadConfig, fileName, fileConform, uuid, fileUrl, Utility.getMd5(uploadId));
}
private File getOssFile(FileUploadConfig fileUploadConfig, String fileName, String fileConform, String uuid,
String fileUrl, String fileMd5) {
File ossFile = new File();
ossFile.setAppChannelBucketNo(fileUploadConfig.getAppChannelBucketNo());
ossFile.setAppCode(fileUploadConfig.getAppCode());
ossFile.setChannelCode(fileUploadConfig.getChannelCode());
ossFile.setBucketName(fileUploadConfig.getBucketName());
ossFile.setDirectory(fileUploadConfig.getDirectory());
ossFile.setStatus(FileStatusEnum.STATUS_UPLOAD_FAIL.getCode());
ossFile.setStorageUnit(fileUploadConfig.getStorageUnit());
ossFile.setStorageSize(fileUploadConfig.getStorageSize());
ossFile.setFileFormat(fileConform);
ossFile.setFileUuid(uuid);
ossFile.setFileUrl(fileUrl);
ossFile.setUrlMd5(Utility.getMd5(fileUrl));
ossFile.setStatus(FileStatusEnum.STATUS_UPLOAD_SUCCESS.getCode());
ossFile.setFileName(fileName);
ossFile.setFileMd5(fileMd5);
fileDao.save(ossFile);
return ossFile;
}
private ServerFileDownloadResponse setFileDownloadResponse(File file, InputStream fileStream) {
ServerFileDownloadResponse resp = new ServerFileDownloadResponse();
resp.setUrl(file.getFileUrl());
@ -217,19 +328,7 @@ public class FileServiceImpl implements FileService {
private File uploadFileAndGetFile(ServerFileUploadDto dto) {
log.info("update fileName:{},appCode:{},bizScene:{}",
dto.getFileName(), dto.getAppCode(), dto.getBizScene());
// 检查appCode
checkAppCode(dto.getAppCode());
// 通过appcode获取文件渠道桶信息
AppChannelBucket appChannelBucket = appChannelBucketManager.getByAppCode(dto.getAppCode());
// 通过渠道桶编码获取到具体文件业务场景
FileBusinessScene scene = fileBusinessSceneManager
.getByBucketNoAndScene(appChannelBucket.getAppChannelBucketNo(), dto.getBizScene());
// 通过渠道码和桶名称获取获取指定上传配置
FileUploadConfig fileUploadConfig = fileUploadConfigManager
.getByUploadConfig(scene.getAppChannelBucketNo(), scene.getDirectory());
FileUploadConfig fileUploadConfig = getFileUploadConfig(dto.getAppCode(), dto.getBizScene());
// 上传文件并生成file对象
return generateFile(fileUploadConfig, dto);
}
@ -474,24 +573,7 @@ public class FileServiceImpl implements FileService {
throw new BizException(CodeEnum.FILE_UPLOAD_FAILED);
}
File ossFile = new File();
ossFile.setAppChannelBucketNo(fileUploadConfig.getAppChannelBucketNo());
ossFile.setAppCode(fileUploadConfig.getAppCode());
ossFile.setChannelCode(fileUploadConfig.getChannelCode());
ossFile.setBucketName(fileUploadConfig.getBucketName());
ossFile.setDirectory(fileUploadConfig.getDirectory());
ossFile.setStatus(FileStatusEnum.STATUS_UPLOAD_FAIL.getCode());
ossFile.setStorageUnit(fileUploadConfig.getStorageUnit());
ossFile.setStorageSize(fileUploadConfig.getStorageSize());
ossFile.setFileFormat(fileConform);
ossFile.setFileUuid(uuid);
ossFile.setFileUrl(fileUrl);
ossFile.setUrlMd5(Utility.getMd5(fileUrl));
ossFile.setStatus(FileStatusEnum.STATUS_UPLOAD_SUCCESS.getCode());
ossFile.setFileName(dto.getFileName());
ossFile.setFileMd5(Utility.getMd5(dto.getFileContent()));
fileDao.save(ossFile);
return ossFile;
return getOssFile(fileUploadConfig, dto.getFileName(), fileConform, uuid, fileUrl, Utility.getMd5(dto.getFileContent()));
}
private ServerFileUploadResponse setResponse(File ossFile) {