Merge branch 'master' into feature/icon_management

# Conflicts:
#	oss-common/src/main/java/cn/axzo/oss/common/enums/CodeEnum.java
This commit is contained in:
chenwenjian 2024-04-03 13:40:58 +08:00
commit 53c44e0342
32 changed files with 1185 additions and 63 deletions

View File

@ -7,22 +7,17 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* OSS 启动类
*
* @author zhaoyong
* @see Bootstrap
* @since 2021-07-15 11:34
*/
* @author hucf
* @since 2024/1/16 15:11
**/
@Slf4j
@MapperScan(basePackages = {"cn.axzo.oss.dal.mapper", "cn.axzo.oss.client.icon.mapper"})
@EnableFeignClients(basePackages = {"cn.axzo.log.platform.client"})
@SpringBootApplication(scanBasePackages = {"cn.axzo.oss"})
public class Bootstrap {
public static void main(String[] args) {
log.info("axzo oss begin starting...");
SpringApplication.run(Bootstrap.class, args);
log.info("axzo oss start success");
}
}

View File

@ -8,16 +8,22 @@ import cn.axzo.oss.http.model.*;
import cn.axzo.oss.manager.api.dto.request.FindFileKeyDto;
import cn.axzo.oss.manager.api.dto.request.FindFileUrlDto;
import cn.axzo.oss.manager.api.dto.request.ServerFileDeleteDto;
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.ServerFileDownloadResponse;
import cn.axzo.oss.service.api.FileService;
import cn.azxo.framework.common.model.CommonResponse;
import cn.hutool.json.JSONUtil;
import feign.Response;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
/**

View File

@ -5,13 +5,21 @@ 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.*;
import cn.axzo.oss.common.enums.ChannelTypeEnum;
import cn.axzo.oss.common.enums.FileDownloadTypeEnum;
import cn.axzo.oss.common.enums.FileUploadTypeEnum;
import cn.axzo.oss.common.enums.StorageUnitEnum;
import cn.axzo.oss.common.exception.BizException;
import cn.axzo.oss.common.utils.BeanConvertUtil;
import cn.axzo.oss.http.model.TemporaryUrlAccessRes;
import cn.axzo.oss.http.model.WebFileUploadVo;
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 cn.hutool.json.JSONUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@ -19,8 +27,7 @@ import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.*;
import java.util.List;
import static cn.axzo.oss.common.enums.CodeEnum.FILE_NAME_TOO_LONG;
@ -34,6 +41,7 @@ import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
**/
@RestController
@RequestMapping("/webApi")
@Slf4j
public class WebFileController {
private static int FILE_NAME_MAX_LENGTH = 128;
@ -95,8 +103,9 @@ public class WebFileController {
@SneakyThrows
@PostMapping("/v1/multipart-upload/init")
@CrossOrigin
public CommonResponse<MultipartUploadInitVo> multipartUploadInit(@Valid @RequestBody MultipartUploadInitDto dto) {
MultipartUploadInitResponse response = fileService.multipartUploadInit(dto);
public CommonResponse<MultipartUploadInitVo> multipartUploadInit(@Valid @RequestBody MultipartUploadInitDto dto,
Integer fileUploadType) {
MultipartUploadInitResponse response = fileService.multipartUploadInit(dto, fileUploadType);
return CommonResponse.success(BeanConvertUtil.copyBean(response, MultipartUploadInitVo.class));
}
@ -121,7 +130,7 @@ public class WebFileController {
.partSize(partSize)
.uploadId(uploadId)
.build();
MultipartUploadResponse response = fileService.multipartUpload(dto);
MultipartUploadResponse response = fileService.multipartUpload(dto, ChannelTypeEnum.OSS.getCode());
return CommonResponse.success(BeanConvertUtil.copyBean(response, MultipartUploadVo.class));
}
@ -138,7 +147,7 @@ public class WebFileController {
.fileName(fileName)
.file(file)
.build();
FileInformationResponse response = fileService.multipartUploadFile(dto);
FileInformationResponse response = fileService.multipartUploadFile(dto, ChannelTypeEnum.OSS.getCode());
return CommonResponse.success(BeanConvertUtil.copyBean(response, FileInformationVo.class));
}
@ -147,7 +156,7 @@ public class WebFileController {
@SneakyThrows
//@PreBuildContext
public CommonResponse<FileInformationVo> multipartUploadComplete(@Valid @RequestBody MultipartUploadCompleteDto dto) {
FileInformationResponse response = fileService.multipartUploadComplete(dto);
FileInformationResponse response = fileService.multipartUploadComplete(dto, ChannelTypeEnum.OSS.getCode());
return CommonResponse.success(BeanConvertUtil.copyBean(response, FileInformationVo.class));
}
@ -180,4 +189,167 @@ public class WebFileController {
outputStream.close();
}
}
/**
* OBS文件上传断点续传
*
* @param appCode 应用编码
* @param bizScene 业务场景
* @param file MultipartFile
* @return WebFileUploadVo
*/
@SneakyThrows
@PostMapping(value = "/v1/file2", consumes = MULTIPART_FORM_DATA_VALUE)
@CrossOrigin
public CommonResponse<WebFileUploadVo> uploadObs(@Valid @RequestParam("appCode") String appCode,
@Valid @RequestParam("bizScene") String bizScene,
@Valid @RequestPart MultipartFile file) {
// 获取用户信息
ContextInfo.LiteSaasContext liteSaasContext = null;
ContextInfo contextInfo = ContextInfoHolder.get();
if (contextInfo != null) {
liteSaasContext = contextInfo.lite();
}
// 文件大于100k生成临时文件进行断点续传
int checkPointLengthLimit = StorageUnitEnum.KB.getSize() * 100;
byte[] fileContent = file.getBytes();
int fileLength = fileContent.length;
String filePath = null;
if (fileLength > checkPointLengthLimit) {
filePath = fileService.getFilePath(file);
}
String filename = file.getOriginalFilename();
BizException.error(filename.length() < FILE_NAME_MAX_LENGTH, FILE_NAME_TOO_LONG);
ServerFileUploadDto fileUploadDto = ServerFileUploadDto.builder()
.appCode(appCode)
.bizScene(bizScene)
.fileName(filename)
.fileContent(fileContent)
.filePath(filePath)
.build();
ServerFileUploadResponse response = fileService.uploadObs(fileUploadDto, liteSaasContext,
FileUploadTypeEnum.CHECK_POINT.getCode());
WebFileUploadVo result = BeanConvertUtil.copyBean(response, WebFileUploadVo.class);
return CommonResponse.success(result);
}
/**
* OBS分段上传
*
* @param appCode 应用编码
* @param bizScene 业务场景
* @param file MultipartFile
* @return WebFileUploadVo
*/
@SneakyThrows
@PostMapping(value = "/v1/partUpload", consumes = MULTIPART_FORM_DATA_VALUE)
@CrossOrigin
public CommonResponse<WebFileUploadVo> partUpload(@Valid @RequestParam("appCode") String appCode,
@Valid @RequestParam("bizScene") String bizScene,
@Valid @RequestPart MultipartFile file) {
// 获取用户信息
ContextInfo.LiteSaasContext liteSaasContext = null;
ContextInfo contextInfo = ContextInfoHolder.get();
if (contextInfo != null) {
liteSaasContext = contextInfo.lite();
}
String filename = file.getOriginalFilename();
BizException.error(filename.length() < FILE_NAME_MAX_LENGTH, FILE_NAME_TOO_LONG);
ServerFileUploadDto fileUploadDto = ServerFileUploadDto.builder()
.appCode(appCode)
.bizScene(bizScene)
.fileName(filename)
.fileContent(file.getBytes())
.build();
ServerFileUploadResponse response = fileService.uploadObs(fileUploadDto, liteSaasContext,
FileUploadTypeEnum.MULTI_PART_UPLOAD.getCode());
WebFileUploadVo result = BeanConvertUtil.copyBean(response, WebFileUploadVo.class);
return CommonResponse.success(result);
}
/**
* obs流式下载
*
* @param dto ServerFileDownloadDto
* @param response HttpServletResponse
*/
@SneakyThrows
@GetMapping("/v1/obs/getObject")
@CrossOrigin
public void getObject(@Valid ServerFileDownloadDto dto, HttpServletResponse response) {
ServerFileDownloadResponse result = fileService.getObject(dto, FileDownloadTypeEnum.STREAM_DOWNLOAD.getCode());
try (OutputStream outputStream = response.getOutputStream(); InputStream inputStream = result.getFileStream()) {
response.setContentType("image/jpg");
response.setCharacterEncoding("UTF-8");
response.addHeader("Content-Disposition", "attachment;filename="
+ result.getFileName() + "." + result.getFileFormat());
IOUtils.copy(inputStream, outputStream);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* obs断点续传下载
*
* @param dto ServerFileDownloadDto
* @param response HttpServletResponse
*/
@SneakyThrows
@GetMapping("/v1/obs/downloadFile")
@CrossOrigin
public void downloadFile(@Valid ServerFileDownloadDto dto, HttpServletResponse response) {
ServerFileDownloadResponse result = fileService.getObject(dto, FileDownloadTypeEnum.CHECK_POINT_DOWNLOAD.getCode());
try (OutputStream outputStream = response.getOutputStream(); InputStream inputStream = result.getFileStream()) {
response.setContentType("image/jpg");
response.setCharacterEncoding("UTF-8");
response.addHeader("Content-Disposition", "attachment;filename="
+ result.getFileName() + "." + result.getFileFormat());
IOUtils.copy(inputStream, outputStream);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 远程下载接口
*
* @param fileUuId 文件uuid
* @param response HttpServletResponse
*/
@GetMapping("/v1/obs/downloadFileFromObs")
public void downloadFileFromObs(@RequestParam("fileUuid") String fileUuId, HttpServletResponse response) {
ServerFileDownloadDto dto = new ServerFileDownloadDto();
dto.setFileKey(fileUuId);
ServerFileDownloadResponse result = fileService.getObject(dto, FileDownloadTypeEnum.STREAM_DOWNLOAD.getCode());
try (OutputStream outputStream = response.getOutputStream(); InputStream inputStream = result.getFileStream()) {
response.setHeader("content-type","application/octet-stream");
response.setContentType("application/octet-stream");
response.setCharacterEncoding("UTF-8");
response.addHeader("Content-Disposition", "attachment;filename=" + result.getFileName() + "." + result.getFileFormat());
IOUtils.copy(inputStream, outputStream);
log.info("response设置文件流成功");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 通过临时url访问OBS
*
* @param fileUuId 文件uuid
* @return TemporaryUrlAccessRes
*/
@GetMapping("/v1/obs/temporaryUrlAccess")
public CommonResponse<TemporaryUrlAccessRes> temporaryUrlAccess(@RequestParam("fileUuid") String fileUuId) {
ServerFileDownloadDto dto = new ServerFileDownloadDto();
dto.setFileKey(fileUuId);
ServerFileDownloadResponse response = fileService.getObject(dto, FileDownloadTypeEnum.TEMPORARY_URL_ACCESS.getCode());
TemporaryUrlAccessRes result = BeanConvertUtil.copyBean(response, TemporaryUrlAccessRes.class);
log.info("下载结果, result = {}", JSONUtil.toJsonStr(result));
return CommonResponse.success(result);
}
}

View File

@ -0,0 +1,39 @@
package cn.axzo.oss.common.enums;
import lombok.Getter;
/**
* 渠道类型枚举类
*
* @author hucf
* @since 2024/1/15 10:15
**/
@Getter
public enum ChannelTypeEnum {
OSS(1, "阿里云", "aliyun"),
OBS(2, "华为云", "huaweicloud"),
;
private final Integer code;
private final String message;
private final String channelCode;
ChannelTypeEnum(Integer code, String message, String channelCode) {
this.code = code;
this.message = message;
this.channelCode = channelCode;
}
public static String getChannelCodeByCode(Integer code) {
String channelCode = null;
for (ChannelTypeEnum value : ChannelTypeEnum.values()) {
if (value.getCode().equals(code)) {
channelCode = value.getChannelCode();
break;
}
}
return channelCode;
}
}

View File

@ -48,10 +48,12 @@ public enum CodeEnum implements EnumBase<Integer> {
MULTIPART_UPLOAD_ERROR(114, "文件上传失败"),
MULTIPART_UPLOAD_COMPLETE_ERROR(115, "文件上传失败"),
ICON_GROUP_EXIST(116, "图标组已存在"),
ICON_GROUP_NOT_EXIST(117, "图标组不存在"),
ICON_EXIST(118, "图标已存在"),
FILE_FORMAT_MAY_ERROR(119, "文件格式可能错误")
OBS_CLIENT_NULL(116,"obs client为空"),
ICON_GROUP_EXIST(117, "图标组已存在"),
ICON_GROUP_NOT_EXIST(118, "图标组不存在"),
ICON_EXIST(119, "图标已存在"),
FILE_FORMAT_MAY_ERROR(201, "文件格式可能错误")
;

View File

@ -0,0 +1,24 @@
package cn.axzo.oss.common.enums;
import lombok.Getter;
/**
* 文件下载类型枚举类
*
* @author hucf
* @since 2024/1/23 17:57
**/
@Getter
public enum FileDownloadTypeEnum {
STREAM_DOWNLOAD(1, "流式下载"),
CHECK_POINT_DOWNLOAD(2, "断点续传下载"),
TEMPORARY_URL_ACCESS(3, "通过临时url访问OBs")
;
private final Integer code;
private final String message;
FileDownloadTypeEnum(Integer code, String message) {
this.code = code;
this.message = message;
}
}

View File

@ -0,0 +1,25 @@
package cn.axzo.oss.common.enums;
import lombok.Getter;
/**
* 文件上传方式枚举类
*
* @author hucf
* @since 2024/1/15 16:43
**/
@Getter
public enum FileUploadTypeEnum {
DEFAULT_UPLOAD(1, "默认"),
CHECK_POINT(2, "断点续传"),
MULTI_PART_UPLOAD(3, "分段上传")
;
private final Integer code;
private final String message;
FileUploadTypeEnum(Integer code, String message) {
this.code = code;
this.message = message;
}
}

View File

@ -20,5 +20,5 @@ public interface AppChannelBucketDao extends IService<AppChannelBucket> {
* @param appCode appcode
* @return
*/
List<AppChannelBucket> getByAppCode(String appCode);
List<AppChannelBucket> getByAppCode(String appCode, Integer fileUploadType);
}

View File

@ -1,11 +1,14 @@
package cn.axzo.oss.dal.repository.impl;
import cn.axzo.oss.common.enums.ChannelTypeEnum;
import cn.axzo.oss.common.enums.IsDeleteEnum;
import cn.axzo.oss.dal.entity.AppChannelBucket;
import cn.axzo.oss.dal.mapper.AppChannelBucketMapper;
import cn.axzo.oss.dal.repository.AppChannelBucketDao;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import java.util.List;
import java.util.Objects;
import org.springframework.stereotype.Repository;
/**
@ -27,8 +30,10 @@ public class AppChannelBucketDaoImpl extends
* @return
*/
@Override
public List<AppChannelBucket> getByAppCode(String appCode) {
public List<AppChannelBucket> getByAppCode(String appCode, Integer channelType) {
String channelCodeByCode = ChannelTypeEnum.getChannelCodeByCode(channelType);
return lambdaQuery().eq(AppChannelBucket::getAppCode, appCode)
.eq(Objects.nonNull(channelCodeByCode), AppChannelBucket::getChannelCode, channelCodeByCode)
.eq(AppChannelBucket::getIsDelete, IsDeleteEnum.NO.getCode()).list();
}
}

View File

@ -35,6 +35,10 @@
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,24 @@
package cn.axzo.oss.http.api;
import cn.axzo.oss.http.model.TemporaryUrlAccessRes;
import cn.azxo.framework.common.model.CommonResponse;
import feign.Response;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* @author axzo
* @since 2024/3/7 16:56
**/
@FeignClient(
name = "oss",
url = "http://oss:9123"
)
public interface DownloadFileApi {
@GetMapping(value = "/webApi/v1/obs/downloadFileFromObs")
CommonResponse<Response> downloadFileFromObs(@RequestParam("fileUuid") String fileUuId);
@GetMapping(value = "/webApi/v1/obs/temporaryUrlAccess")
CommonResponse<TemporaryUrlAccessRes> temporaryUrlAccess(@RequestParam("fileUuid") String fileUuId);
}

View File

@ -3,9 +3,13 @@ package cn.axzo.oss.http.api;
import cn.axzo.oss.http.model.*;
import cn.azxo.framework.common.model.CommonResponse;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import feign.Response;
import java.util.List;
/**

View File

@ -0,0 +1,38 @@
package cn.axzo.oss.http.api;
import cn.axzo.oss.http.model.WebFileUploadVo;
import cn.azxo.framework.common.model.CommonResponse;
import feign.Response;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.Valid;
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
/**
* @author wangsiqian
* @since 2024/02/27
*/
@FeignClient(
name = "oss",
url = "http://oss:9123"
)
public interface WebFileServiceApi {
/**
* OBS文件上传断点续传
*
* @param appCode 应用编码
* @param bizScene 业务场景
* @param file MultipartFile
* @return WebFileUploadVo
*/
@PostMapping(value = "/webApi/v1/file2", consumes = MULTIPART_FORM_DATA_VALUE)
CommonResponse<WebFileUploadVo> uploadObs(@Valid @RequestParam("appCode") String appCode,
@Valid @RequestParam("bizScene") String bizScene,
@Valid @RequestPart MultipartFile file);
}

View File

@ -0,0 +1,30 @@
package cn.axzo.oss.http.model;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* @author hucf
* @since 2024/3/6 15:11
**/
@Data
public class DownloadFileFromObsRequest {
/**
* 文件uuid
*/
@NotBlank(message = "文件uuid不能为空")
private String fileKey;
/**
* 图片样式
*/
private String style;
/**
* 下载方式1:流式下载2:断点续传方式下载
*/
@NotNull(message = "下载方式不能为空")
private Integer fileDownloadType;
}

View File

@ -0,0 +1,46 @@
package cn.axzo.oss.http.model;
import lombok.Data;
import java.io.InputStream;
/**
* @author hucf
* @since 2024/3/6 15:15
**/
@Data
public class DownloadFileFromObsResponse {
/**
* 文件 URL
*/
private String url;
/**
* 文件 Key
*/
private String fileKey;
/**
* URL MD5
*/
private String urlMd5;
/**
* 文件名称
*/
private String fileName;
/**
* 文件大小
*/
private Long fileSize;
/**
* 文件格式
*/
private String fileFormat;
/**
* 文件流
*/
private InputStream fileStream;
}

View File

@ -0,0 +1,44 @@
package cn.axzo.oss.http.model;
import lombok.Data;
/**
* @author hucf
* @since 2024/3/11 18:21
**/
@Data
public class TemporaryUrlAccessRes {
/**
* 文件 URL
*/
private String url;
/**
* 文件 Key
*/
private String fileKey;
/**
* URL MD5
*/
private String urlMd5;
/**
* 文件名称
*/
private String fileName;
/**
* 文件大小
*/
private Long fileSize;
/**
* 文件格式
*/
private String fileFormat;
/**
* obs:临时url
*/
private String signedUrl;
}

View File

@ -1,4 +1,4 @@
package cn.axzo.oss.client.vo;
package cn.axzo.oss.http.model;
import lombok.Data;

View File

@ -25,6 +25,10 @@
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
</dependency>
<dependency>
<groupId>com.huaweicloud</groupId>
<artifactId>esdk-obs-java-bundle</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,23 @@
package cn.axzo.oss.integration.s3;
import com.obs.services.model.TemporarySignatureResponse;
import java.io.InputStream;
/**
* 华为云obs
*
* @author hucf
* @since 2024/1/15 11:37
**/
public interface HuaWeiCloudService {
String uploadFile(String bucketName, String fileName, String appCode, InputStream srcStream);
String checkPointUploadFile(String bucketName, String fileName, String appCode, InputStream srcStream, String filePath);
String multipartUpload(String bucketName, String fileName, String appCode, InputStream srcStream);
InputStream getObject(String bucketName, String objectKey, Integer fileDownloadType);
TemporarySignatureResponse createTemporarySignature(String bucketName, String objectKey);
}

View File

@ -0,0 +1,62 @@
package cn.axzo.oss.integration.s3.client;
import cn.axzo.oss.common.enums.CodeEnum;
import cn.axzo.oss.common.exception.S3Exception;
import cn.axzo.oss.common.utils.Utility;
import cn.axzo.oss.integration.s3.base.OssClientBase;
import cn.axzo.oss.integration.s3.config.HuaWeiCloudObsConfig;
import cn.azxo.framework.common.utils.LogUtil;
import com.obs.services.ObsClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
/**
* 华为云obs客户端
*
* @author hucf
* @since 2024/1/15 09:59
**/
@Component
@Slf4j
public class HuaWeiCloudObsClient implements OssClientBase {
private volatile ObsClient instance = null;
@Autowired
private HuaWeiCloudObsConfig huaWeiCloudObsConfig;
@Override
public ObsClient getClient() {
if (Utility.objIsNull(instance)){
throw new S3Exception(CodeEnum.OBS_CLIENT_NULL.getCode(),"oss客户端未初始化");
}
return instance;
}
@PostConstruct
@Override
public void initClient() {
log.info("accessKeyId = {},secretAccessKey = {}, initClient endpoint = {}",
huaWeiCloudObsConfig.getAccessKeyId(),
huaWeiCloudObsConfig.getSecretAccessKey(),
huaWeiCloudObsConfig.getEndPoint());
try {
instance = new ObsClient(
huaWeiCloudObsConfig.getAccessKeyId(),
huaWeiCloudObsConfig.getSecretAccessKey(),
huaWeiCloudObsConfig.getEndPoint()
);
} catch (Exception exception) {
instance = null;
LogUtil.error("initClient error = {}", exception);
}
}
@Override
public String getEndpoint() {
return huaWeiCloudObsConfig.getEndPoint();
}
}

View File

@ -0,0 +1,65 @@
package cn.axzo.oss.integration.s3.config;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;
/**
* 华为云对象存储服务OBS配置
*
* @author hucf
* @since 2024/1/12 15:11
**/
@Configuration
@RefreshScope
@Data
public class HuaWeiCloudObsConfig {
/**
* AK
*/
@Value("${huaweicloud.obs.accessKeyId}")
private String accessKeyId;
/**
* SK
*/
@Value("${huaweicloud.obs.secretAccessKey}")
private String secretAccessKey;
/**
* 终端节点
*/
@Value("${huaweicloud.obs.endpoint}")
private String endPoint;
/**
* 分段上传时的最大并发数
*/
@Value("${huaweicloud.checkpoint.task-num}")
private String taskNum;
/**
* 分段大小
*/
@Value("${huaweicloud.checkpoint.part-size}")
private String partSize;
/**
* 是否开启断点续传模式
*/
@Value("${huaweicloud.checkpoint.enable-check-point}")
private String enableCheckPoint;
/**
* 是否开启请求头域自动编码
*/
@Value("${huaweicloud.checkpoint.encode-headers}")
private String encodeHeaders;
/**
* 是否开启请求头域自动编码
*/
@Value("${huaweicloud.profiles.active}")
private String profilesActive;
}

View File

@ -0,0 +1,323 @@
package cn.axzo.oss.integration.s3.impl;
import cn.axzo.oss.common.enums.FileDownloadTypeEnum;
import cn.axzo.oss.integration.s3.HuaWeiCloudService;
import cn.axzo.oss.integration.s3.client.HuaWeiCloudObsClient;
import cn.axzo.oss.integration.s3.config.HuaWeiCloudObsConfig;
import cn.azxo.framework.common.utils.LogUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.json.JSONUtil;
import com.obs.services.ObsClient;
import com.obs.services.exception.ObsException;
import com.obs.services.model.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* 华为云OBS
*
* @author hucf
* @since 2024/1/15 11:41
**/
@Service
@Slf4j
public class HuaWeiCloudServiceImpl implements HuaWeiCloudService {
private static final String APPCODE_CMS = "cms";
@Autowired
private HuaWeiCloudObsClient huaWeiCloudObsClient;
@Autowired
private HuaWeiCloudObsConfig huaWeiCloudObsConfig;
/**
* 上传文件到OBS普通方式
*
* @param bucketName 桶名称
* @param fileName 文件名
* @param appCode 应用编码
* @param srcStream 文件流
* @return fileUrl
*/
@Override
public String uploadFile(String bucketName, String fileName, String appCode, InputStream srcStream) {
ObsClient obsClient = huaWeiCloudObsClient.getClient();
// 创建文件夹
String objectKey = huaWeiCloudObsConfig.getProfilesActive() + "/" + appCode + "/" + fileName;
try {
if (APPCODE_CMS.equals(appCode)) {
// 普通上传方式
PutObjectRequest request = new PutObjectRequest();
request.setBucketName(bucketName);
request.setObjectKey(objectKey);
request.setInput(srcStream);
request.setIsEncodeHeaders(true);
PutObjectResult putObjectResult = obsClient.putObject(bucketName, objectKey, srcStream);
return putObjectResult.getObjectUrl();
} else {
// 创建上传文件的元信息通过文件云信息设置HTTP Header
ObjectMetadata metadata = new ObjectMetadata();
// 设置内容被下载时的名称
metadata.setContentDisposition("attachment;filename=\"" + URLEncoder.encode(fileName, "utf-8") + "\"");
metadata.setContentEncoding("utf-8");
PutObjectResult putObjectResult = obsClient.putObject(bucketName, objectKey, srcStream, metadata);
return putObjectResult.getObjectUrl();
}
} catch (ObsException exception) {
LogUtil.error("uploadByStream ObsException", exception);
return "";
} catch (Exception e) {
LogUtil.error("uploadByStream ClientException", e);
return "";
}
}
/**
* 上传文件到OBS断点续传
*
* @param bucketName 桶名称
* @param fileName 文件名
* @param appCode 应用编码
* @param srcStream 文件流
* @return fileUrl
*/
@Override
public String checkPointUploadFile(String bucketName, String fileName, String appCode, InputStream srcStream, String filePath) {
ObsClient obsClient = huaWeiCloudObsClient.getClient();
// 创建文件夹
String objectKey = huaWeiCloudObsConfig.getProfilesActive() + "/" + appCode + "/" + fileName;
try {
if (APPCODE_CMS.equals(appCode)) {
// 断点续传
CompleteMultipartUploadResult completeMultipartUploadResult =
this.uploadFile(obsClient, bucketName, objectKey, fileName, null, filePath);
int statusCode = completeMultipartUploadResult.getStatusCode();
log.info("上传文件返回的状态码,{}", statusCode);
log.info("上传文件返回的url,{}", completeMultipartUploadResult.getObjectUrl());
boolean delFlag = FileUtil.del(filePath);
log.info("断点续传成功,删除临时文件:{}", delFlag);
return completeMultipartUploadResult.getObjectUrl();
} else {
// 创建上传文件的元信息通过文件云信息设置HTTP Header
ObjectMetadata metadata = new ObjectMetadata();
// 设置内容被下载时的名称
metadata.setContentDisposition("attachment;filename=\"" + URLEncoder.encode(fileName, "utf-8") + "\"");
metadata.setContentEncoding("utf-8");
CompleteMultipartUploadResult completeMultipartUploadResult =
this.uploadFile(obsClient, bucketName, objectKey, fileName, metadata, filePath);
boolean delFlag = FileUtil.del(filePath);
log.info("断点续传成功,删除临时文件:{}", delFlag);
return completeMultipartUploadResult.getObjectUrl();
}
} catch (ObsException exception) {
LogUtil.error("uploadByStream ObsException", exception);
return "";
} catch (Exception e) {
LogUtil.error("uploadByStream ClientException", e);
return "";
}
}
/**
* 上传文件到OBS分段上传
*
* @param bucketName 桶名称
* @param fileName 文件名
* @param appCode 应用编码
* @param srcStream 文件流
* @return fileUrl
*/
@Override
public String multipartUpload(String bucketName, String fileName, String appCode, InputStream srcStream) {
ObsClient obsClient = huaWeiCloudObsClient.getClient();
// 创建文件夹
String objectKey = huaWeiCloudObsConfig.getProfilesActive() + "/" + appCode + "/" + fileName;
try {
// 初始化分段上传任务
InitiateMultipartUploadResult initiateMultipartUploadResult =
this.initiateMultipartUploadResult(obsClient, bucketName, objectKey);
String uploadId = initiateMultipartUploadResult.getUploadId();
// 上传段
UploadPartResult uploadPartResult = this.uploadPart(obsClient, bucketName, objectKey, uploadId, srcStream);
// 合并段
CompleteMultipartUploadResult completeMultipartUploadResult =
this.completeMultipartUpload(uploadPartResult, obsClient, bucketName, objectKey, uploadId);
return completeMultipartUploadResult.getLocation();
} catch (ObsException exception) {
LogUtil.error("uploadByStream ObsException", exception);
return "";
} catch (Exception e) {
LogUtil.error("uploadByStream ClientException", e);
return "";
}
}
// 初始化分段上传任务
private InitiateMultipartUploadResult initiateMultipartUploadResult(ObsClient obsClient, String bucketName,
String objectKey) {
InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest();
request.setBucketName(bucketName);
request.setObjectKey(objectKey);
return obsClient.initiateMultipartUpload(request);
}
// 上传段
private UploadPartResult uploadPart(ObsClient obsClient, String bucketName, String objectKey, String uploadId,
InputStream srcStream) {
UploadPartRequest uploadPartRequest = new UploadPartRequest();
uploadPartRequest.setBucketName(bucketName);
uploadPartRequest.setObjectKey(objectKey);
// todo:计算段号
uploadPartRequest.setPartNumber(120);
uploadPartRequest.setUploadId(uploadId);
uploadPartRequest.setInput(srcStream);
return obsClient.uploadPart(uploadPartRequest);
}
// 合并段
private CompleteMultipartUploadResult completeMultipartUpload(UploadPartResult uploadPartResult,
ObsClient obsClient,
String bucketName,
String objectKey,
String uploadId) {
// 构建待合并的段列表
List<PartEtag> partEtagList = new ArrayList<>();
PartEtag partEtag = new PartEtag();
partEtag.setEtag(uploadPartResult.getEtag());
partEtag.setPartNumber(uploadPartResult.getPartNumber());
partEtagList.add(partEtag);
CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest();
completeMultipartUploadRequest.setBucketName(bucketName);
completeMultipartUploadRequest.setObjectKey(objectKey);
completeMultipartUploadRequest.setPartEtag(partEtagList);
completeMultipartUploadRequest.setUploadId(uploadId);
return obsClient.completeMultipartUpload(completeMultipartUploadRequest);
}
// 断点续传
private CompleteMultipartUploadResult uploadFile(ObsClient obsClient, String bucketName, String objectKey,
String fileName, ObjectMetadata metadata, String filePath) {
UploadFileRequest request = new UploadFileRequest(bucketName, objectKey, fileName);
// 设置待上传的本地文件fileName为待上传的本地文件路径需要指定到具体带文件后缀的文件名
request.setUploadFile(filePath);
// 设置分段上传时的最大并发数
request.setTaskNum(Integer.parseInt(huaWeiCloudObsConfig.getTaskNum()));
// 设置分段大小为10MB
request.setPartSize(Long.parseLong(huaWeiCloudObsConfig.getPartSize()));
// 开启断点续传模式
request.setEnableCheckpoint(Boolean.parseBoolean(huaWeiCloudObsConfig.getEnableCheckPoint()));
// 开启请求头域自动编码
request.setIsEncodeHeaders(Boolean.parseBoolean(huaWeiCloudObsConfig.getEncodeHeaders()));
// 对象元数据
request.setObjectMetadata(metadata);
return obsClient.uploadFile(request);
}
/**
* obs下载文件流式下载
*
* @param bucketName 桶名称
* @param objectKey 对象名称
* @return InputStream
*/
@Override
public InputStream getObject(String bucketName, String objectKey, Integer fileDownloadType) {
ObsClient obsClient = huaWeiCloudObsClient.getClient();
if (FileDownloadTypeEnum.STREAM_DOWNLOAD.getCode().equals(fileDownloadType)) {
try {
GetObjectRequest request = new GetObjectRequest();
request.setBucketName(bucketName);
request.setObjectKey(objectKey);
ObsObject object = obsClient.getObject(request);
log.info("下载华为云OBS文件成功");
return object.getObjectContent();
} catch (ObsException obsException) {
log.warn("下载华为云OBS文件失败HTTP Code:{}, Error Code:{}, Request ID:{}, Host ID:{}, Error Message:{}",
obsException.getResponseCode(),
obsException.getErrorCode(),
obsException.getErrorRequestId(),
obsException.getErrorHostId(),
obsException.getErrorMessage());
}
} else if (FileDownloadTypeEnum.CHECK_POINT_DOWNLOAD.getCode().equals(fileDownloadType)) {
try {
DownloadFileRequest request = new DownloadFileRequest(bucketName, objectKey);
// 设置下载对象的本地文件全路径当该值为空时默认为当前程序的运行目录
request.setDownloadFile("");
// 设置分段下载时的最大并发数
request.setTaskNum(Integer.parseInt(huaWeiCloudObsConfig.getTaskNum()));
// 设置分段大小为10MB
request.setPartSize(Long.parseLong(huaWeiCloudObsConfig.getPartSize()));
// 是否开启断点续传模式
request.setEnableCheckpoint(Boolean.parseBoolean(huaWeiCloudObsConfig.getEnableCheckPoint()));
// 是否自动解码响应头
request.setIsEncodeHeaders(Boolean.parseBoolean(huaWeiCloudObsConfig.getEncodeHeaders()));
DownloadFileResult downloadFileResult = obsClient.downloadFile(request);
String etag = downloadFileResult.getObjectMetadata().getEtag();
log.info("下载华为云OBS文件成功");
} catch (NumberFormatException e) {
throw new RuntimeException(e);
} catch (ObsException obsException) {
log.warn("下载华为云OBS文件失败HTTP Code:{}, Error Code:{}, Request ID:{}, Host ID:{}, Error Message:{}",
obsException.getResponseCode(),
obsException.getErrorCode(),
obsException.getErrorRequestId(),
obsException.getErrorHostId(),
obsException.getErrorMessage());
}
}
return null;
}
/**
* 获取OBS临时url
*
* @param bucketName 桶名称
* @param objectKey 对象名称
* @return TemporarySignatureResponse
*/
@Override
public TemporarySignatureResponse createTemporarySignature(String bucketName, String objectKey) {
TemporarySignatureRequest request = new TemporarySignatureRequest();
// 桶名称
request.setBucketName(bucketName);
// 对象名称
request.setObjectKey(objectKey);
// HTTP方法类型
request.setMethod(HttpMethodEnum.GET);
// 带授权信息的URL的过期时间300秒
request.setExpires(300L);
// 发起请求的时间
request.setRequestDate(new Date());
try {
ObsClient obsClient = huaWeiCloudObsClient.getClient();
TemporarySignatureResponse response = obsClient.createTemporarySignature(request);
log.info("response = {}", JSONUtil.toJsonStr(response));
return response;
} catch (Exception exception) {
log.warn("获取临时url发生异常, exception = {}", exception.getMessage());
log.warn("异常信息:");
exception.printStackTrace();
return null;
}
}
}

View File

@ -16,5 +16,5 @@ public interface AppChannelBucketManager {
* @param appCode appcode
* @return
*/
AppChannelBucket getByAppCode(String appCode);
AppChannelBucket getByAppCode(String appCode, Integer fileUploadType);
}

View File

@ -33,7 +33,8 @@ public interface FileManager {
* @param fileContent
* @return
*/
String uploadByStream(String bulkName, String keyPath, String fileName, String appCode, byte[] fileContent);
String uploadByStream(String bulkName, String keyPath, String fileName, String appCode, byte[] fileContent,
Integer channelType, Integer fileUploadType, String filePath);
/**
* 下载文件
@ -50,4 +51,8 @@ public interface FileManager {
String multipartUploadComplete(String bucketName, String tgtFileKey, String uploadId, List<PartETag> partETags);
String multipartUploadFile(String bucketName, String tgtFileKey, MultipartFile file);
InputStream downloadObsFile(String bucketName, String objectKey, Integer fileDownloadType);
String getTempUrlFromOns(String bucketName, String objectKey);
}

View File

@ -20,6 +20,7 @@ public class ServerFileUploadDto {
private String bizScene;
private String fileName;
private byte[] fileContent;
private String filePath;
@Override
public String toString() {

View File

@ -45,4 +45,9 @@ public class ServerFileDownloadResponse {
* 文件流
*/
private InputStream fileStream;
/**
* obs:临时url
*/
private String signedUrl;
}

View File

@ -34,8 +34,8 @@ public class AppChannelBucketManagerImpl implements AppChannelBucketManager {
* @return
*/
@Override
public AppChannelBucket getByAppCode(String appCode) {
List<AppChannelBucket> appChannelBuckets = appChannelBucketDao.getByAppCode(appCode);
public AppChannelBucket getByAppCode(String appCode, Integer channelType) {
List<AppChannelBucket> appChannelBuckets = appChannelBucketDao.getByAppCode(appCode, channelType);
BizException.isEmpty(appChannelBuckets, CodeEnum.APP_CHANNEL_BUCKET_NOT_FOUND);
// 找到最优渠道

View File

@ -1,11 +1,15 @@
package cn.axzo.oss.manager.impl;
import cn.axzo.oss.common.enums.ChannelTypeEnum;
import cn.axzo.oss.common.enums.FileUploadTypeEnum;
import cn.axzo.oss.common.enums.StorageUnitEnum;
import cn.axzo.oss.common.utils.BeanConvertUtil;
import cn.axzo.oss.integration.s3.AliOssService;
import cn.axzo.oss.integration.s3.HuaWeiCloudService;
import cn.axzo.oss.manager.api.FileManager;
import cn.axzo.oss.manager.api.dto.PartETag;
import cn.axzo.oss.manager.api.dto.request.MultipartUploadDto;
import cn.axzo.oss.manager.api.dto.request.MultipartUploadFileDto;
import com.obs.services.model.TemporarySignatureResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
@ -30,6 +34,9 @@ public class FileManagerImpl implements FileManager {
@Autowired
private AliOssService aliOssService;
@Autowired
private HuaWeiCloudService huaWeiCloudService;
/**
* 删除文件
*
@ -46,11 +53,35 @@ public class FileManagerImpl implements FileManager {
* @param bulkName 默认的取值为
* @param keyPath key的前置路径
*/
public String uploadByStream(String bulkName, String keyPath, String fileName, String appCode, byte[] fileContent) {
public String uploadByStream(String bulkName, String keyPath, String fileName, String appCode, byte[] fileContent,
Integer channelType, Integer fileUploadType, String filePath) {
InputStream inputStream = new ByteArrayInputStream(fileContent);
return aliOssService.uploadByStream(bulkName, keyPath, fileName, appCode, inputStream);
if (channelType.equals(ChannelTypeEnum.OBS.getCode())) {
// 断点续传长度限制断点续传上传接口传入的文件大小至少要100K以上
if (fileUploadType.equals(FileUploadTypeEnum.CHECK_POINT.getCode())) {
int checkPointLengthLimit = StorageUnitEnum.KB.getSize() * 100;
int fileLength = fileContent.length;
if (fileLength < checkPointLengthLimit) {
fileUploadType = FileUploadTypeEnum.DEFAULT_UPLOAD.getCode();
}
}
// 上传文件到OBS
if (fileUploadType.equals(FileUploadTypeEnum.DEFAULT_UPLOAD.getCode())) {
return huaWeiCloudService.uploadFile(bulkName, fileName, appCode, inputStream);
} else if (fileUploadType.equals(FileUploadTypeEnum.CHECK_POINT.getCode())) {
return huaWeiCloudService.checkPointUploadFile(bulkName, fileName, appCode, inputStream, filePath);
} else {
return huaWeiCloudService.multipartUpload(bulkName, fileName, appCode, inputStream);
}
}
// 上传文件到阿里云
else {
return aliOssService.uploadByStream(bulkName, keyPath, fileName, appCode, inputStream);
}
}
@Override
@ -94,4 +125,13 @@ public class FileManagerImpl implements FileManager {
}
return partETagList;
}
public InputStream downloadObsFile(String bucketName, String objectKey, Integer fileDownloadType) {
return huaWeiCloudService.getObject(bucketName, objectKey, fileDownloadType);
}
public String getTempUrlFromOns(String bucketName, String objectKey) {
TemporarySignatureResponse response = huaWeiCloudService.createTemporarySignature(bucketName, objectKey);
return response.getSignedUrl();
}
}

View File

@ -3,6 +3,7 @@ package cn.axzo.oss.service.api;
import cn.axzo.framework.auth.domain.ContextInfo;
import cn.axzo.oss.manager.api.dto.request.*;
import cn.axzo.oss.manager.api.dto.response.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
@ -38,11 +39,18 @@ public interface FileService {
ServerFileDownloadResponse download(ServerFileDownloadDto dto);
MultipartUploadInitResponse multipartUploadInit(MultipartUploadInitDto multipartUploadInitDto);
MultipartUploadInitResponse multipartUploadInit(MultipartUploadInitDto multipartUploadInitDto, Integer channelType);
MultipartUploadResponse multipartUpload(MultipartUploadDto dto);
MultipartUploadResponse multipartUpload(MultipartUploadDto dto, Integer channelType);
FileInformationResponse multipartUploadComplete(MultipartUploadCompleteDto dto);
FileInformationResponse multipartUploadComplete(MultipartUploadCompleteDto dto, Integer channelType);
FileInformationResponse multipartUploadFile(MultipartUploadFileDto dto);
FileInformationResponse multipartUploadFile(MultipartUploadFileDto dto, Integer channelType);
ServerFileUploadResponse uploadObs(ServerFileUploadDto dto, ContextInfo.LiteSaasContext liteSaasContext,
Integer fileUploadType);
String getFilePath(MultipartFile file);
ServerFileDownloadResponse getObject(ServerFileDownloadDto dto, Integer fileDownloadType);
}

View File

@ -22,6 +22,10 @@
<groupId>cn.axzo.oss</groupId>
<artifactId>oss-manager</artifactId>
</dependency>
<dependency>
<groupId>com.huaweicloud</groupId>
<artifactId>esdk-obs-java-bundle</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -6,15 +6,14 @@ import cn.axzo.log.platform.client.model.OperateLogReq;
import cn.axzo.oss.common.constans.CommonConstants;
import cn.axzo.oss.common.constans.CommonConstants.FileStatus;
import cn.axzo.oss.common.constans.CommonConstants.TableDelete;
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.enums.*;
import cn.axzo.oss.common.exception.BizException;
import cn.axzo.oss.common.utils.JsonUtil;
import cn.axzo.oss.common.utils.Utility;
import cn.axzo.oss.dal.entity.*;
import cn.axzo.oss.dal.repository.FileAppDao;
import cn.axzo.oss.dal.repository.FileDao;
import cn.axzo.oss.integration.s3.config.HuaWeiCloudObsConfig;
import cn.axzo.oss.manager.api.AppChannelBucketManager;
import cn.axzo.oss.manager.api.FileBusinessSceneManager;
import cn.axzo.oss.manager.api.FileManager;
@ -30,9 +29,14 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
@ -50,12 +54,16 @@ import static cn.axzo.oss.common.constans.CommonConstants.APP_PRO_BUCKET_NAME;
public class FileServiceImpl implements FileService {
private static final String FILE_UPLOAD_CODE = "OSS_FILE_UPLOAD";
private static final String OBS_FILE_UPLOAD_CODE = "OBS_FILE_UPLOAD";
private static final String FILE_UPLOAD_NAME = "文件上传";
private static final String IS_URL = "https://";
private static final String HTTP_COM = ".com/";
private static final String SEPARATOR = java.io.File.separator;
@Autowired
private FileManager fileManager;
@ -77,6 +85,9 @@ public class FileServiceImpl implements FileService {
@Autowired
private LogPlatClient logPlatClient;
@Autowired
private HuaWeiCloudObsConfig huaWeiCloudObsConfig;
/**
* 删除文件
*
@ -136,7 +147,8 @@ public class FileServiceImpl implements FileService {
*/
@Override
public ServerFileUploadResponse upload(ServerFileUploadDto dto, ContextInfo.LiteSaasContext liteSaasContext) {
File ossFile = uploadFileAndGetFile(dto);
File ossFile = uploadFileAndGetFile(dto, ChannelTypeEnum.OSS.getCode(),
FileUploadTypeEnum.DEFAULT_UPLOAD.getCode());
//操作日志记录
operateLog(dto.toString(), "", FILE_UPLOAD_CODE, FILE_UPLOAD_NAME, liteSaasContext);
return setResponse(ossFile);
@ -144,15 +156,16 @@ public class FileServiceImpl implements FileService {
@Override
public FileInformationResponse uploadV2(String serviceName, ServerFileUploadDto request, ContextInfo.LiteSaasContext liteSaasContext) {
File ossFile = uploadFileAndGetFile(request);
File ossFile = uploadFileAndGetFile(request, ChannelTypeEnum.OSS.getCode(),
FileUploadTypeEnum.DEFAULT_UPLOAD.getCode());
//操作日志记录
operateLog(request.toString(), serviceName, FILE_UPLOAD_CODE, FILE_UPLOAD_NAME, liteSaasContext);
return setFileInfoResp(ossFile);
}
@Override
public MultipartUploadInitResponse multipartUploadInit(MultipartUploadInitDto dto) {
FileUploadConfig fileUploadConfig = getFileUploadConfig(dto.getAppCode(), dto.getBizScene());
public MultipartUploadInitResponse multipartUploadInit(MultipartUploadInitDto dto, Integer channelType) {
FileUploadConfig fileUploadConfig = getFileUploadConfig(dto.getAppCode(), dto.getBizScene(), channelType);
// 判断容量
String fileConform = isFileConform(fileUploadConfig, 10, dto.getFileName());
String uuid = Utility.getUUID();
@ -167,8 +180,8 @@ public class FileServiceImpl implements FileService {
}
@Override
public MultipartUploadResponse multipartUpload(MultipartUploadDto dto) {
FileUploadConfig fileUploadConfig = getFileUploadConfig(dto.getAppCode(), dto.getBizScene());
public MultipartUploadResponse multipartUpload(MultipartUploadDto dto, Integer channelType) {
FileUploadConfig fileUploadConfig = getFileUploadConfig(dto.getAppCode(), dto.getBizScene(), channelType);
// 判断容量
isFileConform(fileUploadConfig, dto.getFileContent().length, dto.getFileName());
@ -182,13 +195,13 @@ public class FileServiceImpl implements FileService {
}
@Override
public FileInformationResponse multipartUploadFile(MultipartUploadFileDto dto) {
File ossFile = multipartUploadAndGetFile(dto);
public FileInformationResponse multipartUploadFile(MultipartUploadFileDto dto, Integer fileUploadType) {
File ossFile = multipartUploadAndGetFile(dto, fileUploadType);
return setFileInfoResp(dto.getFile().getSize(), ossFile);
}
private File multipartUploadAndGetFile(MultipartUploadFileDto dto) {
FileUploadConfig fileUploadConfig = getFileUploadConfig(dto.getAppCode(), dto.getBizScene());
private File multipartUploadAndGetFile(MultipartUploadFileDto dto, Integer channelType) {
FileUploadConfig fileUploadConfig = getFileUploadConfig(dto.getAppCode(), dto.getBizScene(), channelType);
// 判断容量
String fileConform = isFileConform(fileUploadConfig, (int) dto.getFile().getSize() / 10, dto.getFileName());
@ -206,8 +219,8 @@ public class FileServiceImpl implements FileService {
}
@Override
public FileInformationResponse multipartUploadComplete(MultipartUploadCompleteDto dto) {
FileUploadConfig fileUploadConfig = getFileUploadConfig(dto.getAppCode(), dto.getBizScene());
public FileInformationResponse multipartUploadComplete(MultipartUploadCompleteDto dto, Integer channelType) {
FileUploadConfig fileUploadConfig = getFileUploadConfig(dto.getAppCode(), dto.getBizScene(), channelType);
// 文件合并并生成 file对象
File ossFile = completeFile(fileUploadConfig, dto.getFileName(), dto.getTgtFileKey(),
dto.getUploadId(), dto.getPartETags());
@ -241,12 +254,12 @@ public class FileServiceImpl implements FileService {
return setFileDownloadResponse(file, fileStream);
}
private FileUploadConfig getFileUploadConfig(String appCode, String bizScene) {
private FileUploadConfig getFileUploadConfig(String appCode, String bizScene, Integer channelType) {
// 检查appCode
checkAppCode(appCode);
// 通过appcode获取文件渠道桶信息
AppChannelBucket appChannelBucket = appChannelBucketManager.getByAppCode(appCode);
AppChannelBucket appChannelBucket = appChannelBucketManager.getByAppCode(appCode, channelType);
// 通过渠道桶编码获取到具体文件业务场景
FileBusinessScene scene = fileBusinessSceneManager
@ -335,12 +348,14 @@ public class FileServiceImpl implements FileService {
}
}
private File uploadFileAndGetFile(ServerFileUploadDto dto) {
log.info("update fileName:{},appCode:{},bizScene:{}",
dto.getFileName(), dto.getAppCode(), dto.getBizScene());
FileUploadConfig fileUploadConfig = getFileUploadConfig(dto.getAppCode(), dto.getBizScene());
private File uploadFileAndGetFile(ServerFileUploadDto dto, Integer channelType, Integer fileUploadType) {
log.info("update channelType:{}, fileName:{}, appCode:{}, bizScene:{}",
channelType, dto.getFileName(), dto.getAppCode(), dto.getBizScene());
FileUploadConfig fileUploadConfig = getFileUploadConfig(dto.getAppCode(), dto.getBizScene(), channelType);
// 上传文件并生成file对象
return generateFile(fileUploadConfig, dto);
return generateFile(fileUploadConfig, dto, channelType, fileUploadType);
}
@Override
@ -479,7 +494,7 @@ public class FileServiceImpl implements FileService {
throw new BizException(CodeEnum.APP_CODE_NOT_FOUND);
}
// 通过appcode获取文件渠道桶信息
AppChannelBucket appChannelBucket = appChannelBucketManager.getByAppCode(appCode);
AppChannelBucket appChannelBucket = appChannelBucketManager.getByAppCode(appCode, ChannelTypeEnum.OSS.getCode());
// 通过渠道桶编码获取到具体文件业务场景
FileBusinessScene scene = fileBusinessSceneManager
.getByBucketNoAndScene(appChannelBucket.getAppChannelBucketNo(), bizScene);
@ -563,19 +578,17 @@ public class FileServiceImpl implements FileService {
return fileFormat;
}
private File generateFile(FileUploadConfig fileUploadConfig, ServerFileUploadDto dto) {
private File generateFile(FileUploadConfig fileUploadConfig, ServerFileUploadDto dto, Integer channelType,
Integer fileUploadType) {
// 判断容量
String fileConform = isFileConform(fileUploadConfig, dto.getFileContent().length,
dto.getFileName());
String fileConform = isFileConform(fileUploadConfig, dto.getFileContent().length, dto.getFileName());
String uuid = Utility.getUUID();
// 生成上传文件的唯一key
String tgtFileKey = Utility.generateFileKey(fileUploadConfig.getDirectory(), uuid, fileConform);
// 上传文件
String fileUrl = fileManager.uploadByStream(fileUploadConfig.getBucketName(), tgtFileKey, dto.getFileName(),
dto.getAppCode(), dto.getFileContent());
dto.getAppCode(), dto.getFileContent(), channelType, fileUploadType, dto.getFilePath());
// 保存失败
if (Utility.isBlank(fileUrl)) {
@ -613,4 +626,109 @@ public class FileServiceImpl implements FileService {
return resp;
}
@Override
public ServerFileUploadResponse uploadObs(ServerFileUploadDto dto, ContextInfo.LiteSaasContext liteSaasContext,
Integer fileUploadType) {
File ossFile = uploadFileAndGetFile(dto, ChannelTypeEnum.OBS.getCode(), fileUploadType);
//操作日志记录
operateLog(dto.toString(), "", OBS_FILE_UPLOAD_CODE, FILE_UPLOAD_NAME, liteSaasContext);
return setResponse(ossFile);
}
@Override
public String getFilePath(MultipartFile file) {
// 创建输入流
InputStream input = null;
try {
input = file.getInputStream();
// 指定目标文件路径及文件名
String fileName = file.getOriginalFilename();
// 生成临时文件名称防止中文文件名乱码导致删除失败
assert fileName != null;
String tempFileName = Utility.getUUID() + fileName.substring(fileName.lastIndexOf("."));
// 获取操作系统名称不同操作系统中文件路径有区别
String osName = System.getProperty("os.name");
String rootDir;
// linux操作系统
if (Objects.nonNull(osName) && osName.toLowerCase().startsWith("linux")) {
rootDir = "/mnt/temp/obs";
} else {
// 其它操作系统
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
String classPath = Objects.requireNonNull(contextClassLoader.getResource("")).getPath();
rootDir = classPath.substring(0, classPath.indexOf("/target/classes/"));
}
// 拼接文件路径
String filePath = rootDir + SEPARATOR + "temp_directory";
String absolutePath = filePath + SEPARATOR + tempFileName;
// 创建临时文件夹
java.io.File tempDirectory = new java.io.File(filePath);
if (!tempDirectory.exists()) {
boolean flag = tempDirectory.mkdirs();
if (flag) {
log.info("临时文件夹创建成功,{}", flag);
} else {
log.info("临时文件夹创建失败,{}", flag);
// 兜底
absolutePath = rootDir + SEPARATOR + tempFileName;
}
}
log.info("临时文件绝对路径:{}", absolutePath);
// 创建输出流并写入数据
OutputStream output = Files.newOutputStream(Paths.get(absolutePath));
byte[] buffer = new byte[1024];
int length;
while ((length = input.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
// 关闭流
input.close();
output.close();
return absolutePath;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public ServerFileDownloadResponse getObject(ServerFileDownloadDto dto, Integer fileDownloadType) {
log.info("obs download file = {}", JsonUtil.obj2Str(dto));
File file = null;
String fileKey = dto.getFileKey();
if (fileKey.contains(IS_URL)) {
String urlMd5 = Utility.getMd5(fileKey);
file = fileDao.getByUrlMd5(urlMd5);
} else {
file = fileDao.getByFileUuid(fileKey);
}
if (Utility.objIsNull(file)) {
log.warn("obs download file is null, fileKey = {}", fileKey);
BizException.error(false, CodeEnum.FILE_NOT_FOUND);
}
// 对象名称目录+文件名
String objectKey = file.getDirectory() + SEPARATOR + file.getFileName();
// 桶名称
String bucketName = file.getBucketName();
InputStream fileStream = null;
String tempUrlFromOns = null;
if (FileDownloadTypeEnum.TEMPORARY_URL_ACCESS.getCode().equals(fileDownloadType)) {
tempUrlFromOns = fileManager.getTempUrlFromOns(bucketName, objectKey);
} else {
fileStream = fileManager.downloadObsFile(bucketName, objectKey, fileDownloadType);
if (Objects.isNull(fileStream)) {
log.warn("下载的文件流为空");
}
}
ServerFileDownloadResponse response = setFileDownloadResponse(file, fileStream);
response.setSignedUrl(tempUrlFromOns);
return response;
}
}

View File

@ -21,6 +21,7 @@
<axzo-dependencies.version>2.0.0-SNAPSHOT</axzo-dependencies.version>
<aliyun-oss.version>3.10.2</aliyun-oss.version>
<axzo-log-api.version>1.0.0-SNAPSHOT</axzo-log-api.version>
<huaiweicloud-obs.versiion>3.23.3</huaiweicloud-obs.versiion>
</properties>
<modules>
@ -101,6 +102,11 @@
<artifactId>axzo-log-api</artifactId>
<version>${axzo-log-api.version}</version>
</dependency>
<dependency>
<groupId>com.huaweicloud</groupId>
<artifactId>esdk-obs-java-bundle</artifactId>
<version>${huaiweicloud-obs.versiion}</version>
</dependency>
</dependencies>
</dependencyManagement>