package com.ard.oss.service.impl; import com.ard.common.config.OssConfiguration; import com.ard.common.exception.file.FileNameLengthLimitExceededException; import com.ard.common.exception.file.FileSizeLimitExceededException; import com.ard.common.exception.file.InvalidExtensionException; import com.ard.common.utils.file.FileUploadUtils; import com.ard.common.utils.file.MimeTypeUtils; import com.ard.oss.model.CredentialsDTO; import com.ard.oss.model.enums.OssTypeEnum; import com.ard.oss.service.IOssService; import io.minio.PutObjectArgs; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.Arrays; import java.util.List; import static com.ard.common.utils.file.FileUploadUtils.assertAllowed; import static com.ard.common.utils.file.FileUploadUtils.extractFilename; /** * @author sean * @version 1.0 * @date 2022/5/30 */ @Service public class OssServiceContext { private IOssService ossService; @Autowired public OssServiceContext(List ossServices, OssConfiguration configuration) { if (!OssConfiguration.enable) { return; } this.ossService = ossServices.stream() .filter(ossService -> ossService.getOssType().equals(OssConfiguration.provider)) .findFirst() .orElseThrow(() -> new IllegalArgumentException("Oss provider is illegal. Optional: " + Arrays.toString(Arrays.stream(OssTypeEnum.values()).map(OssTypeEnum::getType).toArray()))); } IOssService getOssService() { return this.ossService; } public CredentialsDTO getCredentials() { return this.ossService.getCredentials(); } public URL getObjectUrl(String bucket, String objectKey) { if (!StringUtils.hasText(bucket) || !StringUtils.hasText(objectKey)) { throw new IllegalArgumentException(); } return this.ossService.getObjectUrl(bucket, objectKey); } public Boolean deleteObject(String bucket, String objectKey) { return this.ossService.deleteObject(bucket, objectKey); } public InputStream getObject(String bucket, String objectKey) { return this.ossService.getObject(bucket, objectKey); } public void putObject(String bucket, String objectKey, InputStream stream) { this.ossService.putObject(bucket, objectKey, stream); } void createClient() { this.ossService.createClient(); } /** * 以默认BucketName配置上传到Minio服务器 * * @param file 上传的文件 * @return 文件名称 * @throws Exception */ public String upload(MultipartFile file) throws IOException { try { return upload(OssConfiguration.bucket, null, file); } catch (Exception e) { throw new IOException(e.getMessage(), e); } } /** * 自定义bucketName配置上传到Minio服务器 * * @param file 上传的文件 * @return 文件名称 * @throws Exception */ public String upload(String bucket, MultipartFile file) throws IOException { try { return upload(bucket, null, file); } catch (Exception e) { throw new IOException(e.getMessage(), e); } } /** * ✅ 通用上传方法: * - bucket 必传 * - object 可选(为空则自动生成) * - 返回永久访问 URL */ public String upload(String bucket, String object, MultipartFile file) throws IOException { try { // 校验文件名长度 int fileNameLength = file.getOriginalFilename().length(); if (fileNameLength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) { throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH); } // 检查文件扩展名是否合法 assertAllowed(file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); // ✅ 如果 object 为空,则自动生成文件名 String objectName = (object == null || object.isEmpty()) ? extractFilename(file) : object; // 上传文件到 Minio this.ossService.putObject(bucket, objectName, file.getInputStream()); // ✅ 拼接永久 URL(不带 presigned 过期参数) String baseUrl = OssConfiguration.endpoint; if (!baseUrl.endsWith("/")) { baseUrl += "/"; } return baseUrl + bucket + "/" + objectName; } catch (Exception e) { throw new IOException("Upload failed: " + e.getMessage(), e); } } public String upload(String bucket, String objectKey, InputStream input) { try { // 上传文件 this.ossService.putObject(bucket, objectKey, input); // ✅ 构建永久访问 URL String baseUrl = OssConfiguration.endpoint; if (!baseUrl.endsWith("/")) { baseUrl += "/"; } return baseUrl + bucket + "/" + objectKey; } catch (Exception e) { throw new RuntimeException("Upload failed: " + e.getMessage(), e); } } }