From d454a6380c3f09a4b320d2dcc742666c87bbd06e Mon Sep 17 00:00:00 2001 From: zhangran Date: Mon, 2 Aug 2021 17:54:23 +0800 Subject: [PATCH] =?UTF-8?q?add-=E5=AE=9E=E7=8E=B0=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E5=B9=B6=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ServerFileController.java | 3 +- oss-client/src/main/resources/bootstrap.yml | 6 +- .../cn/axzo/oss/common/enums/CodeEnum.java | 3 + .../axzo/oss/common/enums/FileStatusEnum.java | 35 +++++++++ .../cn/axzo/oss/common/utils/Utility.java | 9 +++ .../oss/integration/s3/AliOssService.java | 5 ++ .../integration/s3/base/BaseS3Service.java | 5 +- .../integration/s3/base/OssClientBase.java | 2 + .../integration/s3/client/AliOssClient.java | 5 ++ .../s3/impl/AliOssServiceImpl.java | 34 ++++++++- .../cn/axzo/oss/manager/api/FileManager.java | 17 +++++ .../response/ServerFileUploadResponse.java | 28 +++++++ .../oss/manager/impl/FileManagerImpl.java | 28 +++++++ .../cn/axzo/oss/service/api/FileService.java | 3 +- .../oss/service/impl/FileServiceImpl.java | 75 ++++++++++++++++++- .../cn/axzo/oss/test/FileServiceTest.java | 36 ++++++++- 16 files changed, 279 insertions(+), 15 deletions(-) create mode 100644 oss-common/src/main/java/cn/axzo/oss/common/enums/FileStatusEnum.java create mode 100644 oss-manager-api/src/main/java/cn/axzo/oss/manager/api/dto/response/ServerFileUploadResponse.java diff --git a/oss-client/src/main/java/cn/axzo/oss/client/controller/ServerFileController.java b/oss-client/src/main/java/cn/axzo/oss/client/controller/ServerFileController.java index 7e40698..af12048 100644 --- a/oss-client/src/main/java/cn/axzo/oss/client/controller/ServerFileController.java +++ b/oss-client/src/main/java/cn/axzo/oss/client/controller/ServerFileController.java @@ -31,8 +31,7 @@ public class ServerFileController implements ServerFileServiceApi { @Override public CommonResponse upload(@Valid @RequestBody ServerFileUploadRequest request) { ServerFileUploadDto dto = BeanConvertUtil.copyBean(request, ServerFileUploadDto.class); - fileService.upload(dto); - return null; + return CommonResponse.success(fileService.upload(dto)); } /** diff --git a/oss-client/src/main/resources/bootstrap.yml b/oss-client/src/main/resources/bootstrap.yml index 64596a6..4be26cd 100644 --- a/oss-client/src/main/resources/bootstrap.yml +++ b/oss-client/src/main/resources/bootstrap.yml @@ -4,12 +4,12 @@ spring: cloud: nacos: config: - server-addr: ${NACOS_HOST:dev-nacos.axzo.cn}:${NACOS_PORT:80} + server-addr: ${NACOS_HOST:127.0.0.1}:${NACOS_PORT:8848} file-extension: yaml - namespace: ${NACOS_NAMESPACE_ID:f82179f1-81a9-41a1-a489-4f9ab5660a6e} + namespace: ${NACOS_NAMESPACE_ID:8921646d-ff54-4fd4-a258-2f80ce21142d} prefix: ${spring.application.name} profiles: - active: ${NACOS_PROFILES_ACTIVE:local} + active: ${NACOS_PROFILES_ACTIVE:dev} main: allow-bean-definition-overriding: true diff --git a/oss-common/src/main/java/cn/axzo/oss/common/enums/CodeEnum.java b/oss-common/src/main/java/cn/axzo/oss/common/enums/CodeEnum.java index b129aa2..e8323bc 100644 --- a/oss-common/src/main/java/cn/axzo/oss/common/enums/CodeEnum.java +++ b/oss-common/src/main/java/cn/axzo/oss/common/enums/CodeEnum.java @@ -37,6 +37,9 @@ public enum CodeEnum implements EnumBase { NO_CHANNELS_AVAILABLE(105,"no channels available"), NO_UPLOAD_CONFIG(106,"no upload config"), FILE_SIZE_EXCEEDS_LIMIT(107,"file size exceeds limit"), + NOT_FILE_FORMAT(108,"failed to get file format"), + FILE_FORMAT_NOT_SUPPORTED(109,"file format is not supported"), + FILE_UPLOAD_FAILED(109,"file upload failed"), ; diff --git a/oss-common/src/main/java/cn/axzo/oss/common/enums/FileStatusEnum.java b/oss-common/src/main/java/cn/axzo/oss/common/enums/FileStatusEnum.java new file mode 100644 index 0000000..fcf005d --- /dev/null +++ b/oss-common/src/main/java/cn/axzo/oss/common/enums/FileStatusEnum.java @@ -0,0 +1,35 @@ +package cn.axzo.oss.common.enums; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +/** + * @author: zhangran + * @date: 20210802 14:48 + * @description: + **/ +@Getter +@RequiredArgsConstructor +public enum FileStatusEnum implements EnumBase { + /** + * 处理中 + */ + STATUS_PROCESSING(0, "处理中"), + /** + * 上传成功 + */ + STATUS_UPLOAD_SUCCESS(1, "上传成功"), + /** + * 上传失败 + */ + STATUS_UPLOAD_FAIL(2, "上传失败"), + /** + * 已删除 + */ + STATUS_DELETE(3, "已删除"), + ; + + private final Integer code; + + private final String message; +} diff --git a/oss-common/src/main/java/cn/axzo/oss/common/utils/Utility.java b/oss-common/src/main/java/cn/axzo/oss/common/utils/Utility.java index 0253a39..ea650ea 100644 --- a/oss-common/src/main/java/cn/axzo/oss/common/utils/Utility.java +++ b/oss-common/src/main/java/cn/axzo/oss/common/utils/Utility.java @@ -5,6 +5,7 @@ import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Objects; +import java.util.UUID; import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.binary.Hex; @@ -102,4 +103,12 @@ public class Utility { } return storageUnitEnum.getSize() * size; } + + /** + * 生成UUID + * @return + */ + public static String getUUID(){ + return UUID.randomUUID().toString().replaceAll("-",""); + } } diff --git a/oss-integration/src/main/java/cn/axzo/oss/integration/s3/AliOssService.java b/oss-integration/src/main/java/cn/axzo/oss/integration/s3/AliOssService.java index 8808762..836251d 100644 --- a/oss-integration/src/main/java/cn/axzo/oss/integration/s3/AliOssService.java +++ b/oss-integration/src/main/java/cn/axzo/oss/integration/s3/AliOssService.java @@ -10,4 +10,9 @@ import cn.axzo.oss.integration.s3.base.BaseS3Service; **/ public interface AliOssService extends BaseS3Service { + /** + * get endpoint + * @return + */ + String getEndpoint(); } diff --git a/oss-integration/src/main/java/cn/axzo/oss/integration/s3/base/BaseS3Service.java b/oss-integration/src/main/java/cn/axzo/oss/integration/s3/base/BaseS3Service.java index 7ed1484..06639bf 100644 --- a/oss-integration/src/main/java/cn/axzo/oss/integration/s3/base/BaseS3Service.java +++ b/oss-integration/src/main/java/cn/axzo/oss/integration/s3/base/BaseS3Service.java @@ -20,8 +20,7 @@ public interface BaseS3Service { /** * upload file */ - boolean uploadByStream(InputStream srcStream, String tgtFileKey); - + String uploadByStream(String bucketName, String tgtFileKey, InputStream srcStream); /** * upload multi file @@ -51,4 +50,6 @@ public interface BaseS3Service { */ FilterInputStream getS3ObjectStream(String tgtFileKey); + + } diff --git a/oss-integration/src/main/java/cn/axzo/oss/integration/s3/base/OssClientBase.java b/oss-integration/src/main/java/cn/axzo/oss/integration/s3/base/OssClientBase.java index a1e11ee..97b9020 100644 --- a/oss-integration/src/main/java/cn/axzo/oss/integration/s3/base/OssClientBase.java +++ b/oss-integration/src/main/java/cn/axzo/oss/integration/s3/base/OssClientBase.java @@ -12,4 +12,6 @@ public interface OssClientBase { void initClient(); + String getEndpoint(); + } diff --git a/oss-integration/src/main/java/cn/axzo/oss/integration/s3/client/AliOssClient.java b/oss-integration/src/main/java/cn/axzo/oss/integration/s3/client/AliOssClient.java index 92e8944..ce5911a 100644 --- a/oss-integration/src/main/java/cn/axzo/oss/integration/s3/client/AliOssClient.java +++ b/oss-integration/src/main/java/cn/axzo/oss/integration/s3/client/AliOssClient.java @@ -47,4 +47,9 @@ public class AliOssClient implements OssClientBase { } } + @Override + public String getEndpoint(){ + return aliOssConfig.getEndpoint(); + } + } diff --git a/oss-integration/src/main/java/cn/axzo/oss/integration/s3/impl/AliOssServiceImpl.java b/oss-integration/src/main/java/cn/axzo/oss/integration/s3/impl/AliOssServiceImpl.java index 80d5c38..bf5d69a 100644 --- a/oss-integration/src/main/java/cn/axzo/oss/integration/s3/impl/AliOssServiceImpl.java +++ b/oss-integration/src/main/java/cn/axzo/oss/integration/s3/impl/AliOssServiceImpl.java @@ -1,8 +1,11 @@ package cn.axzo.oss.integration.s3.impl; +import cn.axzo.oss.common.enums.CodeEnum; +import cn.axzo.oss.common.exception.BizException; import cn.axzo.oss.integration.s3.AliOssService; import cn.axzo.oss.integration.s3.client.AliOssClient; import com.aliyun.oss.ClientException; +import com.aliyun.oss.OSS; import com.aliyun.oss.OSSException; import java.io.FilterInputStream; import java.io.InputStream; @@ -29,8 +32,28 @@ public class AliOssServiceImpl implements AliOssService { * upload file */ @Override - public boolean uploadByStream(InputStream srcStream, String tgtFileKey) { - return false; + public String uploadByStream(String bucketName, String tgtFileKey, InputStream srcStream) { + OSS client = aliOssClient.getClient(); + try { + client.putObject(bucketName, tgtFileKey, srcStream); + } catch (OSSException e) { + log.error("uploadByStream OSSException", e); + return ""; + } catch (ClientException e) { + log.error("uploadByStream ClientException", e); + return ""; + } finally { + client.shutdown(); + } + + StringBuilder allBuilder = new StringBuilder(); + allBuilder.append("https://"); + allBuilder.append(bucketName); + allBuilder.append("."); + allBuilder.append(aliOssClient.getEndpoint()); + allBuilder.append(tgtFileKey); + + return allBuilder.toString(); } /** @@ -51,7 +74,7 @@ public class AliOssServiceImpl implements AliOssService { aliOssClient.getClient().deleteObject(bucket, tgtFileKey); return Boolean.TRUE; } catch (Exception e) { - log.error("ali oss delFile error = {}",e); + log.error("ali oss delFile error = {}", e); } return Boolean.FALSE; } @@ -81,4 +104,9 @@ public class AliOssServiceImpl implements AliOssService { public FilterInputStream getS3ObjectStream(String tgtFileKey) { return null; } + + @Override + public String getEndpoint() { + return aliOssClient.getEndpoint(); + } } diff --git a/oss-manager-api/src/main/java/cn/axzo/oss/manager/api/FileManager.java b/oss-manager-api/src/main/java/cn/axzo/oss/manager/api/FileManager.java index e005638..11d699e 100644 --- a/oss-manager-api/src/main/java/cn/axzo/oss/manager/api/FileManager.java +++ b/oss-manager-api/src/main/java/cn/axzo/oss/manager/api/FileManager.java @@ -11,4 +11,21 @@ import cn.axzo.oss.dal.entity.File; public interface FileManager { boolean delete(File file); + + /** + * 上传 + * + * @param bulkName + * @param keyPath + * @param fileContent + * @return + */ + String uploadByStream(String bulkName, String keyPath, byte[] fileContent); + + /** + * get endpoint + * + * @return + */ + String getAliOssEndpoint(); } diff --git a/oss-manager-api/src/main/java/cn/axzo/oss/manager/api/dto/response/ServerFileUploadResponse.java b/oss-manager-api/src/main/java/cn/axzo/oss/manager/api/dto/response/ServerFileUploadResponse.java new file mode 100644 index 0000000..3f981ae --- /dev/null +++ b/oss-manager-api/src/main/java/cn/axzo/oss/manager/api/dto/response/ServerFileUploadResponse.java @@ -0,0 +1,28 @@ +package cn.axzo.oss.manager.api.dto.response; + +import lombok.Data; + +/** + * 服务端文件上传响应类 + * + * @author zhaoyong + * @see ServerFileUploadResponse + * @since 2021-07-23 10:37 + */ +@Data +public class ServerFileUploadResponse { + + /** + * 文件 URL + */ + private String url; + /** + * 文件 Key + */ + private String fileKey; + /** + * URL MD5 + */ + private String urlMd5; + +} diff --git a/oss-manager/src/main/java/cn/axzo/oss/manager/impl/FileManagerImpl.java b/oss-manager/src/main/java/cn/axzo/oss/manager/impl/FileManagerImpl.java index af0023e..afc4f55 100644 --- a/oss-manager/src/main/java/cn/axzo/oss/manager/impl/FileManagerImpl.java +++ b/oss-manager/src/main/java/cn/axzo/oss/manager/impl/FileManagerImpl.java @@ -2,8 +2,16 @@ package cn.axzo.oss.manager.impl; import cn.axzo.oss.dal.entity.File; import cn.axzo.oss.integration.s3.AliOssService; +import cn.axzo.oss.integration.s3.config.AliOssConfig; import cn.axzo.oss.manager.api.FileManager; +import com.aliyun.oss.OSS; +import com.aliyun.oss.OSSClientBuilder; +import java.io.ByteArrayInputStream; +import java.io.FileInputStream; +import java.io.InputStream; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.util.Strings; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -24,4 +32,24 @@ public class FileManagerImpl implements FileManager { public boolean delete(File file) { return aliOssService.delFile(file.getBucketName(), file.getFileUuid()); } + + /** + * @param bulkName 默认的取值为 + * @param keyPath key的前置路径 + */ + public String uploadByStream(String bulkName, String keyPath, byte[] fileContent) { + + InputStream inputStream = new ByteArrayInputStream(fileContent); + + return aliOssService.uploadByStream(bulkName, keyPath, inputStream); + } + + /** + * get endpoint + * + * @return + */ + public String getAliOssEndpoint() { + return aliOssService.getEndpoint(); + } } diff --git a/oss-service-api/src/main/java/cn/axzo/oss/service/api/FileService.java b/oss-service-api/src/main/java/cn/axzo/oss/service/api/FileService.java index 47a822e..fafed85 100644 --- a/oss-service-api/src/main/java/cn/axzo/oss/service/api/FileService.java +++ b/oss-service-api/src/main/java/cn/axzo/oss/service/api/FileService.java @@ -2,6 +2,7 @@ package cn.axzo.oss.service.api; import cn.axzo.oss.manager.api.dto.request.ServerFileDeleteDto; import cn.axzo.oss.manager.api.dto.request.ServerFileUploadDto; +import cn.axzo.oss.manager.api.dto.response.ServerFileUploadResponse; /** * @Author admin @@ -23,5 +24,5 @@ public interface FileService { * * @param request */ - void upload(ServerFileUploadDto request); + ServerFileUploadResponse upload(ServerFileUploadDto request); } diff --git a/oss-service/src/main/java/cn/axzo/oss/service/impl/FileServiceImpl.java b/oss-service/src/main/java/cn/axzo/oss/service/impl/FileServiceImpl.java index 62f1a42..7aafd7d 100644 --- a/oss-service/src/main/java/cn/axzo/oss/service/impl/FileServiceImpl.java +++ b/oss-service/src/main/java/cn/axzo/oss/service/impl/FileServiceImpl.java @@ -3,6 +3,7 @@ package cn.axzo.oss.service.impl; 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.FileStatusEnum; import cn.axzo.oss.common.exception.BizException; import cn.axzo.oss.common.utils.JsonUtil; import cn.axzo.oss.common.utils.Utility; @@ -22,9 +23,11 @@ import cn.axzo.oss.manager.api.FileManager; import cn.axzo.oss.manager.api.dto.request.ServerFileDeleteDto; import cn.axzo.oss.manager.api.dto.request.ServerFileUploadDto; import cn.axzo.oss.service.api.FileService; +import cn.axzo.oss.manager.api.dto.response.ServerFileUploadResponse; import com.alibaba.fastjson.JSON; import com.google.common.collect.Lists; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -58,6 +61,7 @@ public class FileServiceImpl implements FileService { @Autowired private FileUploadConfigDao fileUploadConfigDao; + /** * 删除文件 * @@ -94,8 +98,9 @@ public class FileServiceImpl implements FileService { * @param dto */ @Override - public void upload(ServerFileUploadDto dto) { - log.info("update dto:{}", JSON.toJSONString(dto)); + public ServerFileUploadResponse upload(ServerFileUploadDto dto) { + log.info("update fileName:{},appCode:{},bizScene:{}", + dto.getFileName(), dto.getAppCode(), dto.getBizScene()); /** * 1.检查app * 2.渠道 @@ -133,6 +138,10 @@ public class FileServiceImpl implements FileService { AppChannelBucket appChannelBucket = appChannelBuckets.stream().filter(bucket -> bucket.getChannelCode().equals(fileChannel.getChannelCode())) .findFirst().orElse(null); + if (appChannelBucket == null) { + log.error("upload 最优渠道为空 channels:{}", channels); + throw new BizException(CodeEnum.APP_CHANNEL_NOT_FOUND); + } // 通过渠道桶编码获取到具体文件业务场景 FileBusinessScene scene = fileBusinessSceneDao @@ -158,7 +167,67 @@ public class FileServiceImpl implements FileService { , size); throw new BizException(CodeEnum.FILE_SIZE_EXCEEDS_LIMIT); } - // todo 文件格式判断 + // 文件格式判断 + String[] formats = fileUploadConfig.getFileFormat().split(","); + int lastIndexOf = dto.getFileName().lastIndexOf("."); + if (lastIndexOf == -1) { + log.error("获取文件格式失败:{}", dto.getFileName()); + throw new BizException(CodeEnum.NOT_FILE_FORMAT); + } + + String fileFormats = dto.getFileName().substring(lastIndexOf + 1).toLowerCase(); + boolean contains = Arrays.asList(formats).contains(fileFormats); + if (!contains) { + log.error("不支持此格式文件fileName:{},formats:{}", dto.getFileName(), formats); + throw new BizException(CodeEnum.FILE_FORMAT_NOT_SUPPORTED); + } + String md5 = Utility.getMd5(dto.getFileContent()); + + 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.setFileMd5(md5); + ossFile.setStatus(FileStatusEnum.STATUS_PROCESSING.getCode()); + ossFile.setFileFormat(fileFormats); + ossFile.setFileName(dto.getFileName()); + ossFile.setStorageUnit(fileUploadConfig.getStorageUnit()); + ossFile.setStorageSize(fileUploadConfig.getStorageSize()); + + String uuid = Utility.getUUID(); + + // 上传文件 + StringBuilder builder = new StringBuilder(); + builder.append(fileUploadConfig.getDirectory()); + builder.append("/"); + builder.append(uuid); + builder.append("."); + builder.append(fileFormats); + + String fileUrl = fileManager.uploadByStream( + fileUploadConfig.getBucketName(), builder.toString(), dto.getFileContent()); + if (Utility.isBlank(fileUrl)) { + ossFile.setStatus(FileStatusEnum.STATUS_UPLOAD_FAIL.getCode()); + fileDao.save(ossFile); + throw new BizException(CodeEnum.FILE_UPLOAD_FAILED); + } + + ossFile.setFileUuid(uuid); + ossFile.setFileUrl(fileUrl); + ossFile.setUrlMd5(Utility.getMd5(fileUrl)); + ossFile.setStatus(FileStatusEnum.STATUS_UPLOAD_SUCCESS.getCode()); + fileDao.save(ossFile); + + ServerFileUploadResponse response = new ServerFileUploadResponse(); + response.setUrl(ossFile.getFileUrl()); + response.setUrlMd5(ossFile.getUrlMd5()); + response.setFileKey(ossFile.getFileUuid()); + + return response; } + + } diff --git a/oss-test/src/test/java/cn/axzo/oss/test/FileServiceTest.java b/oss-test/src/test/java/cn/axzo/oss/test/FileServiceTest.java index d1d4395..b48909d 100644 --- a/oss-test/src/test/java/cn/axzo/oss/test/FileServiceTest.java +++ b/oss-test/src/test/java/cn/axzo/oss/test/FileServiceTest.java @@ -1,8 +1,15 @@ package cn.axzo.oss.test; import cn.axzo.oss.manager.api.dto.request.ServerFileDeleteDto; +import cn.axzo.oss.manager.api.dto.request.ServerFileUploadDto; import cn.axzo.oss.service.api.FileService; import cn.axzo.oss.test.base.SpringTestBase; +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -18,11 +25,38 @@ public class FileServiceTest extends SpringTestBase { private FileService fileService; @Test - public void deleteTest(){ + public void deleteTest() { ServerFileDeleteDto dto = new ServerFileDeleteDto(); dto.setUrl("https://axzo-pro.oss-cn-hangzhou.aliyuncs.com/stable/face/19700101080046_6296.jpg"); dto.setOperator("zhangsan"); fileService.delete(dto); } + + @Test + public void upload() { + ServerFileUploadDto dto = new ServerFileUploadDto(); + dto.setAppCode("test"); + dto.setBizScene("1"); + dto.setFileName("一个新的文件.jpg"); + + File file = new File("/Users/zhangran/Desktop/xx/IMG_20210728_162815.jpg"); + + FileInputStream fileInputStream = null; + + byte[] bytes = new byte[(int) file.length()]; + try { + fileInputStream = new FileInputStream(file); + fileInputStream.read(bytes); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + dto.setFileContent(bytes); + + fileService.upload(dto); + } + + }