diff --git a/playedu-api/src/main/java/xyz/playedu/api/controller/ExceptionController.java b/playedu-api/src/main/java/xyz/playedu/api/controller/ExceptionController.java index 2e6d173..ad9db5a 100644 --- a/playedu-api/src/main/java/xyz/playedu/api/controller/ExceptionController.java +++ b/playedu-api/src/main/java/xyz/playedu/api/controller/ExceptionController.java @@ -15,6 +15,8 @@ */ package xyz.playedu.api.controller; +import com.amazonaws.services.s3.model.AmazonS3Exception; + import lombok.extern.slf4j.Slf4j; import org.springframework.data.redis.RedisConnectionFailureException; @@ -40,7 +42,7 @@ public class ExceptionController { @ExceptionHandler(Exception.class) public JsonResponse exceptionHandler(Exception e) { - log.error(e.getMessage()); + log.error("{}-{}", e, e.getMessage()); return JsonResponse.error("系统错误", 500); } @@ -95,4 +97,10 @@ public class ExceptionController { public JsonResponse serviceExceptionHandler(LimitException e) { return JsonResponse.error("请稍后再试", 429); } + + @ExceptionHandler(AmazonS3Exception.class) + public JsonResponse serviceExceptionHandler(AmazonS3Exception e) { + log.error("s3错误={}", e.getMessage()); + return JsonResponse.error(e.getMessage(), 500); + } } diff --git a/playedu-api/src/main/java/xyz/playedu/api/controller/backend/ResourceController.java b/playedu-api/src/main/java/xyz/playedu/api/controller/backend/ResourceController.java index 71dd4a0..39f215c 100644 --- a/playedu-api/src/main/java/xyz/playedu/api/controller/backend/ResourceController.java +++ b/playedu-api/src/main/java/xyz/playedu/api/controller/backend/ResourceController.java @@ -34,10 +34,11 @@ import xyz.playedu.common.domain.AdminUser; import xyz.playedu.common.exception.NotFoundException; import xyz.playedu.common.exception.ServiceException; import xyz.playedu.common.service.AdminUserService; -import xyz.playedu.common.service.MinioService; +import xyz.playedu.common.service.AppConfigService; import xyz.playedu.common.types.JsonResponse; import xyz.playedu.common.types.paginate.PaginationResult; import xyz.playedu.common.types.paginate.ResourcePaginateFilter; +import xyz.playedu.common.util.S3Util; import xyz.playedu.resource.domain.Resource; import xyz.playedu.resource.domain.ResourceVideo; import xyz.playedu.resource.service.ResourceService; @@ -56,7 +57,7 @@ public class ResourceController { @Autowired private ResourceVideoService resourceVideoService; - @Autowired private MinioService minioService; + @Autowired private AppConfigService appConfigService; @Autowired private BackendBus backendBus; @@ -134,7 +135,8 @@ public class ResourceController { } // 删除文件 - minioService.removeByPath(resource.getPath()); + S3Util s3Util = new S3Util(appConfigService.getS3Config()); + s3Util.removeByPath(resource.getPath()); // 如果是视频资源文件则删除对应的时长关联记录 if (BackendConstant.RESOURCE_TYPE_VIDEO.equals(resource.getType())) { resourceVideoService.removeByRid(resource.getId()); @@ -157,6 +159,8 @@ public class ResourceController { return JsonResponse.success(); } + S3Util s3Util = new S3Util(appConfigService.getS3Config()); + for (Resource resourceItem : resources) { // 权限校验 if (!backendBus.isSuperAdmin()) { @@ -166,7 +170,7 @@ public class ResourceController { } // 删除资源源文件 - minioService.removeByPath(resourceItem.getPath()); + s3Util.removeByPath(resourceItem.getPath()); // 如果是视频资源的话还需要删除视频的关联资源,如: 封面截图 if (BackendConstant.RESOURCE_TYPE_VIDEO.equals(resourceItem.getType())) { resourceVideoService.removeByRid(resourceItem.getId()); diff --git a/playedu-api/src/main/java/xyz/playedu/api/controller/backend/UploadController.java b/playedu-api/src/main/java/xyz/playedu/api/controller/backend/UploadController.java index baf997a..df589f0 100644 --- a/playedu-api/src/main/java/xyz/playedu/api/controller/backend/UploadController.java +++ b/playedu-api/src/main/java/xyz/playedu/api/controller/backend/UploadController.java @@ -31,9 +31,10 @@ import xyz.playedu.common.constant.BackendConstant; import xyz.playedu.common.constant.BusinessTypeConstant; import xyz.playedu.common.context.BCtx; import xyz.playedu.common.exception.ServiceException; -import xyz.playedu.common.service.MinioService; +import xyz.playedu.common.service.AppConfigService; import xyz.playedu.common.types.JsonResponse; import xyz.playedu.common.util.HelperUtil; +import xyz.playedu.common.util.S3Util; import xyz.playedu.resource.domain.Resource; import xyz.playedu.resource.service.ResourceService; import xyz.playedu.resource.service.UploadService; @@ -44,10 +45,11 @@ import java.util.HashMap; @Slf4j @RequestMapping("/backend/v1/upload") public class UploadController { - @Autowired private MinioService minioService; @Autowired private UploadService uploadService; + @Autowired private AppConfigService appConfigService; + @Autowired private ResourceService resourceService; @BackendPermission(slug = BPermissionConstant.UPLOAD) @@ -74,9 +76,11 @@ public class UploadController { return JsonResponse.error("该格式文件不支持上传"); } + S3Util s3Util = new S3Util(appConfigService.getS3Config()); + String filename = HelperUtil.randomString(32) + "." + extension; // 文件名 String path = BackendConstant.RESOURCE_TYPE_2_DIR.get(type) + filename; // 存储路径 - String uploadId = minioService.uploadId(path); + String uploadId = s3Util.uploadId(path); HashMap data = new HashMap<>(); data.put("resource_type", type); @@ -94,7 +98,9 @@ public class UploadController { Integer partNumber = MapUtils.getInteger(params, "part_number"); String filename = MapUtils.getString(params, "filename"); - String url = minioService.chunkPreSignUrl(filename, partNumber + "", uploadId); + S3Util s3Util = new S3Util(appConfigService.getS3Config()); + + String url = s3Util.generatePartUploadPreSignUrl(filename, partNumber + "", uploadId); HashMap data = new HashMap<>(); data.put("url", url); @@ -115,7 +121,8 @@ public class UploadController { String originalFilename = req.getOriginalFilename().replaceAll("(?i)." + extension, ""); // 合并资源文件 - String url = minioService.merge(req.getFilename(), req.getUploadId()); + S3Util s3Util = new S3Util(appConfigService.getS3Config()); + String url = s3Util.merge(req.getFilename(), req.getUploadId()); // 资源素材保存 Resource videoResource = @@ -162,7 +169,9 @@ public class UploadController { return JsonResponse.error("uploadId必填"); } - String url = minioService.merge(filename, uploadId); + S3Util s3Util = new S3Util(appConfigService.getS3Config()); + + String url = s3Util.merge(filename, uploadId); HashMap data = new HashMap<>(); data.put("url", url); diff --git a/playedu-common/src/main/java/xyz/playedu/common/config/PlayEduMinioClientConfig.java b/playedu-common/src/main/java/xyz/playedu/common/config/PlayEduMinioClientConfig.java deleted file mode 100644 index 4c4e5c2..0000000 --- a/playedu-common/src/main/java/xyz/playedu/common/config/PlayEduMinioClientConfig.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2023 杭州白书科技有限公司 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package xyz.playedu.common.config; - -import io.minio.CreateMultipartUploadResponse; -import io.minio.ListPartsResponse; -import io.minio.MinioAsyncClient; -import io.minio.messages.Part; - -import lombok.SneakyThrows; - -import java.util.List; - -/** - * @Author 杭州白书科技有限公司 - * - * @create 2023/3/6 16:12 - */ -public class PlayEduMinioClientConfig extends MinioAsyncClient { - public PlayEduMinioClientConfig(MinioAsyncClient client) { - super(client); - } - - @SneakyThrows - public String uploadId(String bucket, String filename) { - CreateMultipartUploadResponse response = - super.createMultipartUpload(bucket, null, filename, null, null); - return response.result().uploadId(); - } - - @SneakyThrows - public void merge(String bucketName, String objectName, String uploadId) { - ListPartsResponse listPartsResponse = - super.listParts(bucketName, null, objectName, 10000, 0, uploadId, null, null); - List partList = listPartsResponse.result().partList(); - Part[] parts = new Part[10000]; - int partNumber = 1; - for (Part part : partList) { - parts[partNumber - 1] = new Part(partNumber, part.etag()); - partNumber++; - } - super.completeMultipartUpload(bucketName, null, objectName, uploadId, parts, null, null); - } -} diff --git a/playedu-common/src/main/java/xyz/playedu/common/service/AppConfigService.java b/playedu-common/src/main/java/xyz/playedu/common/service/AppConfigService.java index f36625d..753dfe3 100644 --- a/playedu-common/src/main/java/xyz/playedu/common/service/AppConfigService.java +++ b/playedu-common/src/main/java/xyz/playedu/common/service/AppConfigService.java @@ -19,7 +19,7 @@ import com.baomidou.mybatisplus.extension.service.IService; import xyz.playedu.common.domain.AppConfig; import xyz.playedu.common.types.LdapConfig; -import xyz.playedu.common.types.config.MinioConfig; +import xyz.playedu.common.types.config.S3Config; import java.util.HashMap; import java.util.List; @@ -35,7 +35,7 @@ public interface AppConfigService extends IService { Map keyValues(); - MinioConfig getMinioConfig(); + S3Config getS3Config(); boolean enabledLdapLogin(); diff --git a/playedu-common/src/main/java/xyz/playedu/common/service/MinioService.java b/playedu-common/src/main/java/xyz/playedu/common/service/MinioService.java deleted file mode 100644 index bc196e1..0000000 --- a/playedu-common/src/main/java/xyz/playedu/common/service/MinioService.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2023 杭州白书科技有限公司 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package xyz.playedu.common.service; - -import org.springframework.web.multipart.MultipartFile; - -/** - * @Author 杭州白书科技有限公司 - * - * @create 2023/3/7 13:29 - */ -public interface MinioService { - - String url(String path); - - String saveFile(MultipartFile file, String savePath, String contentType); - - String saveBytes(byte[] file, String savePath, String contentType); - - String uploadId(String path); - - String chunkPreSignUrl(String filename, String partNumber, String uploadId); - - String merge(String filename, String uploadId); - - void removeByPath(String path); -} diff --git a/playedu-common/src/main/java/xyz/playedu/common/service/impl/AppConfigServiceImpl.java b/playedu-common/src/main/java/xyz/playedu/common/service/impl/AppConfigServiceImpl.java index 970feab..2ecc856 100644 --- a/playedu-common/src/main/java/xyz/playedu/common/service/impl/AppConfigServiceImpl.java +++ b/playedu-common/src/main/java/xyz/playedu/common/service/impl/AppConfigServiceImpl.java @@ -17,6 +17,8 @@ package xyz.playedu.common.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.extern.log4j.Log4j2; + import org.springframework.stereotype.Service; import xyz.playedu.common.constant.ConfigConstant; @@ -25,7 +27,8 @@ import xyz.playedu.common.exception.ServiceException; import xyz.playedu.common.mapper.AppConfigMapper; import xyz.playedu.common.service.AppConfigService; import xyz.playedu.common.types.LdapConfig; -import xyz.playedu.common.types.config.MinioConfig; +import xyz.playedu.common.types.config.S3Config; +import xyz.playedu.common.util.StringUtil; import java.util.ArrayList; import java.util.HashMap; @@ -33,12 +36,8 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; -/** - * @author tengteng - * @description 针对表【app_config】的数据库操作Service实现 - * @createDate 2023-03-09 11:13:33 - */ @Service +@Log4j2 public class AppConfigServiceImpl extends ServiceImpl implements AppConfigService { @@ -95,15 +94,30 @@ public class AppConfigServiceImpl extends ServiceImpl config = keyValues(); - minioConfig.setAccessKey(config.get(ConfigConstant.MINIO_ACCESS_KEY)); - minioConfig.setSecretKey(config.get(ConfigConstant.MINIO_SECRET_KEY)); - minioConfig.setBucket(config.get(ConfigConstant.MINIO_BUCKET)); - minioConfig.setEndpoint(config.get(ConfigConstant.MINIO_ENDPOINT)); - minioConfig.setDomain(config.get(ConfigConstant.MINIO_DOMAIN)); - return minioConfig; + s3Config.setAccessKey(config.get(ConfigConstant.MINIO_ACCESS_KEY)); + s3Config.setSecretKey(config.get(ConfigConstant.MINIO_SECRET_KEY)); + s3Config.setBucket(config.get(ConfigConstant.MINIO_BUCKET)); + s3Config.setEndpoint(config.get(ConfigConstant.MINIO_ENDPOINT)); + s3Config.setRegion(null); + s3Config.setService("minio"); + + String domain = config.get(ConfigConstant.MINIO_DOMAIN); + if (s3Config.getService().equals("minio") && StringUtil.isNotEmpty(domain)) { + // 移除 / 后缀 + if (StringUtil.endsWith(domain, "/")) { + domain = domain.substring(0, domain.length() - 1); + } + // 判断是否携带了bucket + if (!StringUtil.endsWith(domain, s3Config.getBucket())) { + domain += "/" + s3Config.getBucket(); + } + s3Config.setDomain(domain); + } + + return s3Config; } @Override diff --git a/playedu-common/src/main/java/xyz/playedu/common/service/impl/MinioServiceImpl.java b/playedu-common/src/main/java/xyz/playedu/common/service/impl/MinioServiceImpl.java deleted file mode 100644 index 99aeea1..0000000 --- a/playedu-common/src/main/java/xyz/playedu/common/service/impl/MinioServiceImpl.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (C) 2023 杭州白书科技有限公司 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package xyz.playedu.common.service.impl; - -import io.minio.*; -import io.minio.http.Method; - -import lombok.SneakyThrows; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.web.multipart.MultipartFile; - -import xyz.playedu.common.config.PlayEduMinioClientConfig; -import xyz.playedu.common.exception.ServiceException; -import xyz.playedu.common.service.AppConfigService; -import xyz.playedu.common.service.MinioService; -import xyz.playedu.common.types.config.MinioConfig; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; - -@Service -public class MinioServiceImpl implements MinioService { - - @Autowired private AppConfigService appConfigService; - - @SneakyThrows - private MinioConfig getMinioConfig() { - MinioConfig c = appConfigService.getMinioConfig(); - if (c.getAccessKey().isBlank() - || c.getSecretKey().isBlank() - || c.getBucket().isBlank() - || c.getDomain().isBlank() - || c.getEndpoint().isBlank()) { - throw new ServiceException("MinIO服务未配置"); - } - return c; - } - - private String bucket() { - return getMinioConfig().getBucket(); - } - - public MinioClient getMinioClient() { - MinioConfig c = getMinioConfig(); - - return MinioClient.builder() - .endpoint(c.getEndpoint()) - .credentials(c.getAccessKey(), c.getSecretKey()) - .build(); - } - - public PlayEduMinioClientConfig getPlayEduMinioClient() { - MinioConfig c = getMinioConfig(); - - MinioAsyncClient client = - PlayEduMinioClientConfig.builder() - .endpoint(c.getEndpoint()) - .credentials(c.getAccessKey(), c.getSecretKey()) - .build(); - - return new PlayEduMinioClientConfig(client); - } - - @Override - public String url(String path) { - MinioConfig c = getMinioConfig(); - - return c.getDomain() - + (c.getDomain().endsWith("/") ? "" : "/") - + c.getBucket() - + "/" - + path; - } - - @Override - @SneakyThrows - public String saveFile(MultipartFile file, String savePath, String contentType) { - PutObjectArgs objectArgs = - PutObjectArgs.builder().bucket(bucket()).object(savePath).stream( - file.getInputStream(), file.getSize(), -1) - .contentType(contentType) - .build(); - getMinioClient().putObject(objectArgs); - - return url(savePath); - } - - @Override - public String uploadId(String path) { - return getPlayEduMinioClient().uploadId(bucket(), path); - } - - @Override - @SneakyThrows - public String chunkPreSignUrl(String filename, String partNumber, String uploadId) { - Map extraQueryParams = new HashMap<>(); - extraQueryParams.put("partNumber", partNumber); - extraQueryParams.put("uploadId", uploadId); - - return getMinioClient() - .getPresignedObjectUrl( - GetPresignedObjectUrlArgs.builder() - .bucket(bucket()) - .object(filename) - .method(Method.PUT) - .expiry(60 * 60 * 24) - .extraQueryParams(extraQueryParams) - .build()); - } - - @Override - public String merge(String filename, String uploadId) { - getPlayEduMinioClient().merge(bucket(), filename, uploadId); - return url(filename); - } - - @Override - @SneakyThrows - public void removeByPath(String path) { - getMinioClient() - .removeObject(RemoveObjectArgs.builder().bucket(bucket()).object(path).build()); - } - - @Override - @SneakyThrows - public String saveBytes(byte[] file, String savePath, String contentType) { - InputStream inputStream = new ByteArrayInputStream(file); - - PutObjectArgs objectArgs = - PutObjectArgs.builder().bucket(bucket()).object(savePath).stream( - inputStream, file.length, -1) - .contentType(contentType) - .build(); - - getMinioClient().putObject(objectArgs); - - return url(savePath); - } -} diff --git a/playedu-common/src/main/java/xyz/playedu/common/types/config/MinioConfig.java b/playedu-common/src/main/java/xyz/playedu/common/types/config/S3Config.java similarity index 91% rename from playedu-common/src/main/java/xyz/playedu/common/types/config/MinioConfig.java rename to playedu-common/src/main/java/xyz/playedu/common/types/config/S3Config.java index 4e9e369..005c4f0 100644 --- a/playedu-common/src/main/java/xyz/playedu/common/types/config/MinioConfig.java +++ b/playedu-common/src/main/java/xyz/playedu/common/types/config/S3Config.java @@ -18,10 +18,12 @@ package xyz.playedu.common.types.config; import lombok.Data; @Data -public class MinioConfig { +public class S3Config { private String accessKey; private String secretKey; private String bucket; private String endpoint; private String domain; + private String region; + private String service; } diff --git a/playedu-common/src/main/java/xyz/playedu/common/util/S3Util.java b/playedu-common/src/main/java/xyz/playedu/common/util/S3Util.java new file mode 100644 index 0000000..c77779c --- /dev/null +++ b/playedu-common/src/main/java/xyz/playedu/common/util/S3Util.java @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2023 杭州白书科技有限公司 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package xyz.playedu.common.util; + +import com.amazonaws.HttpMethod; +import com.amazonaws.auth.AWSCredentials; +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.client.builder.AwsClientBuilder; +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import com.amazonaws.services.s3.model.*; + +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + +import org.springframework.web.multipart.MultipartFile; + +import xyz.playedu.common.exception.ServiceException; +import xyz.playedu.common.types.config.S3Config; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +@Slf4j +public class S3Util { + + private S3Config defaultConfig; + + public S3Config getS3Config() { + return defaultConfig; + } + + public S3Util(S3Config s3Config) { + defaultConfig = s3Config; + } + + public S3Util setConfig(S3Config config) { + defaultConfig = config; + return this; + } + + public boolean configIsEmpty() { + return defaultConfig == null + || StringUtil.isEmpty(defaultConfig.getDomain()) + || StringUtil.isEmpty(defaultConfig.getEndpoint()) + || StringUtil.isEmpty(defaultConfig.getAccessKey()) + || StringUtil.isEmpty(defaultConfig.getSecretKey()); + } + + @SneakyThrows + private AmazonS3 getClient() { + if (defaultConfig == null) { + throw new ServiceException("存储服务未配置"); + } + AWSCredentials credentials = + new BasicAWSCredentials(defaultConfig.getAccessKey(), defaultConfig.getSecretKey()); + + AwsClientBuilder.EndpointConfiguration endpointConfiguration = + new AwsClientBuilder.EndpointConfiguration( + defaultConfig.getEndpoint(), defaultConfig.getRegion()); + + return AmazonS3ClientBuilder.standard() + .withCredentials(new AWSStaticCredentialsProvider(credentials)) + .withEndpointConfiguration(endpointConfiguration) + .build(); + } + + @SneakyThrows + public String saveFile(MultipartFile file, String savePath, String contentType) { + ObjectMetadata objectMetadata = new ObjectMetadata(); + objectMetadata.setContentType(contentType); + objectMetadata.setContentLength(file.getInputStream().available()); + getClient() + .putObject( + defaultConfig.getBucket(), savePath, file.getInputStream(), objectMetadata); + return generateEndpointPreSignUrl(savePath); + } + + @SneakyThrows + public String saveBytes(byte[] file, String savePath, String contentType) { + InputStream inputStream = new ByteArrayInputStream(file); + ObjectMetadata objectMetadata = new ObjectMetadata(); + objectMetadata.setContentType(contentType); + objectMetadata.setContentLength(inputStream.available()); + getClient().putObject(defaultConfig.getBucket(), savePath, inputStream, objectMetadata); + return generateEndpointPreSignUrl(savePath); + } + + public String uploadId(String path) { + InitiateMultipartUploadRequest request = + new InitiateMultipartUploadRequest(defaultConfig.getBucket(), path); + InitiateMultipartUploadResult result = getClient().initiateMultipartUpload(request); + return result.getUploadId(); + } + + public String generatePartUploadPreSignUrl( + String filename, String partNumber, String uploadId) { + GeneratePresignedUrlRequest request = + new GeneratePresignedUrlRequest( + defaultConfig.getBucket(), filename, HttpMethod.PUT); + request.setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000)); // 一个小时有效期 + request.addRequestParameter("partNumber", partNumber); // 分块索引 + request.addRequestParameter("uploadId", uploadId); // uploadId + return getClient().generatePresignedUrl(request).toString(); + } + + @SneakyThrows + public String merge(String filename, String uploadId) { + AmazonS3 client = getClient(); + + ListPartsRequest listPartsRequest = + new ListPartsRequest(defaultConfig.getBucket(), filename, uploadId); + PartListing parts = client.listParts(listPartsRequest); + if (parts.getParts().isEmpty()) { + throw new ServiceException("没有已上传的分片文件"); + } + + List eTags = new ArrayList<>(); + parts.getParts() + .forEach( + item -> { + eTags.add(new PartETag(item.getPartNumber(), item.getETag())); + }); + + CompleteMultipartUploadRequest request = new CompleteMultipartUploadRequest(); + request.setBucketName(defaultConfig.getBucket()); + request.setKey(filename); + request.setUploadId(uploadId); + request.setPartETags(eTags); + + client.completeMultipartUpload(request); + + return generateEndpointPreSignUrl(filename); + } + + public void removeByPath(String path) { + DeleteObjectRequest request = new DeleteObjectRequest(defaultConfig.getBucket(), path); + getClient().deleteObject(request); + } + + public boolean exists(String path) { + return getClient().doesObjectExist(defaultConfig.getBucket(), path); + } + + @SneakyThrows + public String getContent(String path) { + S3Object s3Object = getClient().getObject(defaultConfig.getBucket(), path); + return new String(s3Object.getObjectContent().readAllBytes(), StandardCharsets.UTF_8); + } + + public String generateEndpointPreSignUrl(String path) { + if (defaultConfig.getService().equals("minio")) { + return defaultConfig.getDomain() + "/" + path; + } + return ""; + } +} diff --git a/playedu-resource/src/main/java/xyz/playedu/resource/service/impl/UploadServiceImpl.java b/playedu-resource/src/main/java/xyz/playedu/resource/service/impl/UploadServiceImpl.java index 6f7aff1..0f45269 100644 --- a/playedu-resource/src/main/java/xyz/playedu/resource/service/impl/UploadServiceImpl.java +++ b/playedu-resource/src/main/java/xyz/playedu/resource/service/impl/UploadServiceImpl.java @@ -26,29 +26,25 @@ import xyz.playedu.common.constant.BackendConstant; import xyz.playedu.common.constant.FrontendConstant; import xyz.playedu.common.domain.UserUploadImageLog; import xyz.playedu.common.exception.ServiceException; -import xyz.playedu.common.service.MinioService; +import xyz.playedu.common.service.AppConfigService; import xyz.playedu.common.service.UserUploadImageLogService; import xyz.playedu.common.types.UploadFileInfo; import xyz.playedu.common.util.Base64Util; import xyz.playedu.common.util.HelperUtil; +import xyz.playedu.common.util.S3Util; import xyz.playedu.resource.domain.Resource; import xyz.playedu.resource.service.ResourceService; import xyz.playedu.resource.service.UploadService; import java.util.Date; -/** - * @Author 杭州白书科技有限公司 - * - * @create 2023/3/8 14:02 - */ @Service @Slf4j public class UploadServiceImpl implements UploadService { @Autowired private ResourceService resourceService; - @Autowired private MinioService minioService; + @Autowired private AppConfigService appConfigService; @Autowired private UserUploadImageLogService userUploadImageLogService; @@ -79,13 +75,14 @@ public class UploadServiceImpl implements UploadService { // 自定义新的存储文件名 fileInfo.setSaveName(HelperUtil.randomString(32) + "." + fileInfo.getExtension()); // 生成保存的相对路径 - if (dir == null || dir.length() == 0) { + if (dir == null || dir.isEmpty()) { dir = BackendConstant.RESOURCE_TYPE_2_DIR.get(fileInfo.getResourceType()); } fileInfo.setSavePath(dir + fileInfo.getSaveName()); // 保存文件并生成访问url + S3Util s3Util = new S3Util(appConfigService.getS3Config()); String url = - minioService.saveFile( + s3Util.saveFile( file, fileInfo.getSavePath(), BackendConstant.RESOURCE_EXT_2_CONTENT_TYPE.get(fileInfo.getExtension())); @@ -134,8 +131,9 @@ public class UploadServiceImpl implements UploadService { String savePath = BackendConstant.RESOURCE_TYPE_2_DIR.get(type) + filename; // 保存文件 + S3Util s3Util = new S3Util(appConfigService.getS3Config()); String url = - minioService.saveBytes( + s3Util.saveBytes( binary, savePath, BackendConstant.RESOURCE_EXT_2_CONTENT_TYPE.get(ext)); // 上传记录 return resourceService.create( diff --git a/pom.xml b/pom.xml index 8043af0..cd3c5a8 100644 --- a/pom.xml +++ b/pom.xml @@ -98,9 +98,9 @@ - io.minio - minio - 8.5.2 + com.amazonaws + aws-java-sdk-s3 + 1.12.572