引入依赖
<dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.5.12</version>
</dependency>
<dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId><version>3.17.1</version>
</dependency>
<dependency><groupId>com.qiniu</groupId><artifactId>qiniu-java-sdk</artifactId><version>7.12.1</version>
</dependency>
代码实现
package com.meteor.blog.common.file.config;import com.meteor.blog.common.file.constant.FileStoreTypeEnum;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
@Data
@ConfigurationProperties(prefix = "meteor.file")
public class FileStoreProperties {private FileStoreTypeEnum type = FileStoreTypeEnum.LOCAL;private String baseDir;private String endpoint;private String accessKey;private String secretKey;private String bucket;private String nginxHost;}
package com.meteor.blog.common.file;import com.meteor.blog.common.file.constant.FileStoreTypeEnum;
import com.meteor.blog.common.file.service.FileTemplate;
import com.meteor.blog.common.file.service.FileTemplateImpl;
import com.meteor.blog.common.file.strategy.*;
import com.meteor.blog.common.file.config.FileStoreProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableConfigurationProperties(FileStoreProperties.class)
public class FileAutoConfiguration {@Beanpublic FileStrategy fileStrategy(FileStoreProperties fileStoreProperties) {FileStoreTypeEnum type = fileStoreProperties.getType();switch (type) {case MINIO -> {return new MinioStrategyImpl(fileStoreProperties);}case ALIYUN -> {return new AliyunStrategyImpl(fileStoreProperties);}case QINIU -> {return new QiniuStrategyImpl(fileStoreProperties);}default -> {return new LocalStrategyImpl(fileStoreProperties);}}}@Beanpublic FileTemplate fileService(FileStrategy fileStrategy) {return new FileTemplateImpl(fileStrategy);}}
package com.meteor.blog.common.file.config;import com.meteor.blog.common.file.constant.FileStoreTypeEnum;
import com.meteor.blog.common.file.strategy.FileStrategy;
import org.springframework.util.ObjectUtils;import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public final class StrategyFactory {private static final Map<FileStoreTypeEnum, FileStrategy> STRATEGY_MAP = new ConcurrentHashMap<>();public static FileStrategy getStrategy(FileStoreTypeEnum type) {return STRATEGY_MAP.get(type);}public static void register(FileStoreTypeEnum type, FileStrategy strategy) {if (ObjectUtils.isEmpty(type)) {return;}STRATEGY_MAP.put(type, strategy);}}
package com.meteor.blog.common.file.strategy;import org.springframework.beans.factory.InitializingBean;import java.io.InputStream;
import java.util.List;
public interface FileStrategy extends InitializingBean {boolean directoryExists(String directory) throws Exception;List<String> listDirectories() throws Exception;void createDirectory(String directory) throws Exception;void removeDirectory(String directory) throws Exception;List<String> listFiles() throws Exception;List<String> listFiles(String directory) throws Exception;void uploadFile(String fileName, InputStream inputStream) throws Exception;void uploadFile(String directory, String fileName, InputStream inputStream) throws Exception;void removeFile(String directory, String fileName) throws Exception;void removeFiles(String directory, List<String> fileNames) throws Exception;InputStream downloadFile(String directory, String fileName) throws Exception;}
package com.meteor.blog.common.file.strategy;import cn.hutool.core.util.StrUtil;
import com.meteor.blog.common.base.util.SymbolUtil;
import com.meteor.blog.common.file.constant.FileStoreTypeEnum;
import com.meteor.blog.common.file.config.FileStoreProperties;
import com.meteor.blog.common.file.config.StrategyFactory;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@Slf4j
@RequiredArgsConstructor
public class LocalStrategyImpl implements FileStrategy {private String baseDir;public LocalStrategyImpl(FileStoreProperties fileStoreProperties) {this.baseDir = fileStoreProperties.getBaseDir();}@Overridepublic boolean directoryExists(String directory) throws Exception {return new File(this.baseDir + File.separator + directory).exists();}@Overridepublic List<String> listDirectories() throws Exception {File file = new File(this.baseDir);List<String> list = new ArrayList<>();for (File subFile : Objects.requireNonNull(file.listFiles())) {if (subFile.isDirectory()) {list.add(subFile.getName());}}return list;}@Overridepublic void createDirectory(String directory) throws Exception {File file = new File(this.baseDir + File.separator + directory);if (!file.exists()) {file.mkdirs();}}@Overridepublic void removeDirectory(String directory) throws Exception {File file = new File(this.baseDir + File.separator + directory);if (file.exists()) {file.delete();}}@Overridepublic List<String> listFiles() throws Exception {return this.listFiles(null);}@Overridepublic List<String> listFiles(String directory) throws Exception {File file = new File(this.baseDir + (StrUtil.isBlank(directory) ? "" : File.separator + directory));List<String> list = new ArrayList<>();for (File subFile : Objects.requireNonNull(file.listFiles())) {if (subFile.isFile()) {list.add(subFile.getName());}}return list;}@Overridepublic void uploadFile(String fileName, InputStream inputStream) throws Exception {this.uploadFile(this.baseDir, fileName, inputStream);}@Overridepublic void uploadFile(String directory, String fileName, InputStream inputStream) throws Exception {try (FileOutputStream outputStream = new FileOutputStream(directory + SymbolUtil.SLASH + fileName)) {byte[] buffer = new byte[1024];int bytesRead;while ((bytesRead = inputStream.read(buffer)) != -1) {outputStream.write(buffer, 0, bytesRead);}} catch (IOException e) {throw new RuntimeException("Failed to upload file to local storage", e);}}@Overridepublic void removeFile(String directory, String fileName) throws Exception {File file = new File(directory + File.separator + fileName);if (file.exists()) {file.delete();}}@Overridepublic void removeFiles(String directory, List<String> fileNames) throws Exception {for (String fileName : fileNames) {this.removeFile(directory, fileName);}}@Overridepublic InputStream downloadFile(String directory, String fileName) throws Exception {try {return new FileInputStream(this.baseDir + (StrUtil.isBlank(directory) ? "" : File.separator + directory) + File.separator + fileName);} catch (IOException e) {throw new RuntimeException("Failed to download file from local storage", e);}}@Overridepublic void afterPropertiesSet() throws Exception {StrategyFactory.register(FileStoreTypeEnum.LOCAL, this);}}
package com.meteor.blog.common.file.strategy;import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import com.meteor.blog.common.base.util.SymbolUtil;
import com.meteor.blog.common.file.constant.FileStoreTypeEnum;
import com.meteor.blog.common.file.config.FileStoreProperties;
import com.meteor.blog.common.file.config.StrategyFactory;
import io.minio.*;
import io.minio.messages.Bucket;
import io.minio.messages.DeleteError;
import io.minio.messages.DeleteObject;
import io.minio.messages.Item;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Slf4j
@RequiredArgsConstructor
public class MinioStrategyImpl implements FileStrategy {private MinioClient minioClient;private String bucket;public MinioStrategyImpl(FileStoreProperties fileStoreProperties) {this.minioClient = MinioClient.builder().credentials(fileStoreProperties.getAccessKey(), fileStoreProperties.getSecretKey()).endpoint(fileStoreProperties.getEndpoint()).build();this.bucket = fileStoreProperties.getBucket();}@Overridepublic boolean directoryExists(String directory) throws Exception {return minioClient.bucketExists(BucketExistsArgs.builder().bucket(directory).build());}@Overridepublic List<String> listDirectories() throws Exception {return minioClient.listBuckets().stream().map(Bucket::name).collect(Collectors.toList());}@Overridepublic void createDirectory(String directory) throws Exception {if (!this.directoryExists(directory)) {minioClient.makeBucket(MakeBucketArgs.builder().bucket(directory).build());}}@Overridepublic void removeDirectory(String directory) throws Exception {minioClient.removeBucket(RemoveBucketArgs.builder().bucket(directory).build());}@Overridepublic List<String> listFiles() throws Exception {return this.listFiles(this.bucket);}@Overridepublic List<String> listFiles(String directory) throws Exception {List<String> list = new ArrayList<>();Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder().bucket(directory).build());for (Result<Item> result : results) {list.add(result.get().objectName());}return list;}@Overridepublic void uploadFile(String fileName, InputStream inputStream) throws Exception {this.uploadFile(this.bucket, fileName, inputStream);}@Overridepublic void uploadFile(String directory, String fileName, InputStream inputStream) throws Exception {this.createDirectory(directory);minioClient.putObject(PutObjectArgs.builder().bucket(directory).object(fileName).stream(inputStream, inputStream.available(), -1).contentType("").build());}@Overridepublic void removeFile(String directory, String fileName) throws Exception {minioClient.removeObject(RemoveObjectArgs.builder().bucket(directory).object(fileName).build());}@Overridepublic void removeFiles(String directory, List<String> fileNames) throws Exception {List<DeleteObject> deleteObjectList = new ArrayList<>();for (String fileName : fileNames) {DeleteObject deleteObject = new DeleteObject(fileName);deleteObjectList.add(deleteObject);}Iterable<Result<DeleteError>> results = minioClient.removeObjects(RemoveObjectsArgs.builder().bucket(directory).objects(deleteObjectList).build());for (Result<DeleteError> result : results) {DeleteError error = result.get();log.error("Error in deleting object {}, reason: {}", error.objectName(), error.message());}}@Overridepublic InputStream downloadFile(String directory, String fileName) throws Exception {GetObjectResponse object = minioClient.getObject(GetObjectArgs.builder().bucket(directory).object(fileName).build());String object1 = object.object();return null;}@Overridepublic void afterPropertiesSet() throws Exception {StrategyFactory.register(FileStoreTypeEnum.MINIO, this);}}
package com.meteor.blog.common.file.strategy;import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.*;
import com.meteor.blog.common.file.constant.FileStoreTypeEnum;
import com.meteor.blog.common.file.config.FileStoreProperties;
import com.meteor.blog.common.file.config.StrategyFactory;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;import java.io.InputStream;
import java.util.List;
import java.util.stream.Collectors;
@Slf4j
@RequiredArgsConstructor
public class AliyunStrategyImpl implements FileStrategy {private OSS ossClient;private String bucket;public AliyunStrategyImpl(FileStoreProperties fileStoreProperties) {this.ossClient = new OSSClientBuilder().build(fileStoreProperties.getEndpoint(),fileStoreProperties.getAccessKey(),fileStoreProperties.getSecretKey());this.bucket = fileStoreProperties.getBucket();}@Overridepublic boolean directoryExists(String directory) throws Exception {return ossClient.doesBucketExist(directory);}@Overridepublic List<String> listDirectories() throws Exception {return ossClient.listBuckets().stream().map(Bucket::getName).collect(Collectors.toList());}@Overridepublic void createDirectory(String directory) throws Exception {if (!this.directoryExists(directory)) {ossClient.createBucket(directory);}}@Overridepublic void removeDirectory(String directory) throws Exception {ossClient.deleteBucket(directory);}@Overridepublic List<String> listFiles() throws Exception {return this.listFiles(this.bucket);}@Overridepublic List<String> listFiles(String directory) throws Exception {ObjectListing objectListing = ossClient.listObjects(directory);return objectListing.getObjectSummaries().stream().map(e -> e.getKey()).collect(Collectors.toList());}@Overridepublic void uploadFile(String directory, InputStream inputStream) throws Exception {this.uploadFile(directory, this.bucket, inputStream);}@Overridepublic void uploadFile(String directory, String fileName, InputStream inputStream) throws Exception {this.createDirectory(directory);ossClient.putObject(directory, fileName, inputStream);}@Overridepublic void removeFile(String directory, String fileName) throws Exception {ossClient.deleteObject(directory, fileName);}@Overridepublic void removeFiles(String directory, List<String> fileNames) throws Exception {ossClient.deleteObjects(new DeleteObjectsRequest(directory).withKeys(fileNames));}@Overridepublic InputStream downloadFile(String directory, String fileName) throws Exception {OSSObject object = ossClient.getObject(new GetObjectRequest(directory, fileName));return object.getObjectContent();}@Overridepublic void afterPropertiesSet() throws Exception {StrategyFactory.register(FileStoreTypeEnum.ALIYUN, this);}}
package com.meteor.blog.common.file.strategy;import com.meteor.blog.common.file.constant.FileStoreTypeEnum;
import com.meteor.blog.common.file.config.FileStoreProperties;
import com.meteor.blog.common.file.config.StrategyFactory;
import com.qiniu.http.Response;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.Region;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.FileInfo;
import com.qiniu.storage.model.FileListing;
import com.qiniu.util.Auth;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Slf4j
@RequiredArgsConstructor
public class QiniuStrategyImpl implements FileStrategy {private Auth auth;private String bucket;private BucketManager bucketManager;private UploadManager uploadManager;public QiniuStrategyImpl(FileStoreProperties fileStoreProperties) {Configuration cfg = new Configuration(Region.autoRegion());this.auth = Auth.create(fileStoreProperties.getAccessKey(), fileStoreProperties.getSecretKey());this.bucket = fileStoreProperties.getBucket();this.bucketManager = new BucketManager(this.auth, cfg);this.uploadManager = new UploadManager(cfg);}@Overridepublic boolean directoryExists(String directory) throws Exception {return this.listDirectories().contains(directory);}@Overridepublic List<String> listDirectories() throws Exception {return Arrays.asList(bucketManager.buckets());}@Overridepublic void createDirectory(String directory) throws Exception {if (!this.directoryExists(directory)) {bucketManager.createBucket(directory, null);}}@Overridepublic void removeDirectory(String directory) throws Exception {bucketManager.delete(directory, null);}@Overridepublic List<String> listFiles() throws Exception {return this.listFiles(this.bucket);}@Overridepublic List<String> listFiles(String directory) throws Exception {FileListing fileListing = bucketManager.listFiles(directory, null, null, -1, null);List<String> list = new ArrayList<>();for (FileInfo fileInfo : fileListing.items) {list.add(fileInfo.key);}return list;}@Overridepublic void uploadFile(String fileName, InputStream inputStream) throws Exception {this.uploadFile(this.bucket, fileName, inputStream);}@Overridepublic void uploadFile(String directory, String fileName, InputStream inputStream) throws Exception {String token = auth.uploadToken(directory);uploadManager.put(inputStream, fileName, token, null, null);}@Overridepublic void removeFile(String directory, String fileName) throws Exception {bucketManager.delete(directory, fileName);}@Overridepublic void removeFiles(String directory, List<String> fileNames) throws Exception {BucketManager.BatchOperations batchOperations = new BucketManager.BatchOperations();batchOperations.addDeleteOp(directory, fileNames.toArray(new String[0]));bucketManager.batch(batchOperations);}@Overridepublic InputStream downloadFile(String directory, String fileName) throws Exception {auth.privateDownloadUrl(fileName);return null;}@Overridepublic void afterPropertiesSet() throws Exception {StrategyFactory.register(FileStoreTypeEnum.QINIU, this);}}
package com.meteor.blog.common.file.constant;import com.meteor.blog.common.base.constant.BaseEnum;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
public enum FileStoreTypeEnum implements BaseEnum<String> {ALIYUN("aliyun", "阿里云"),QINIU("qiniu", "七牛云"),MINIO("minio", "minio"),LOCAL("local", "本地");private final String code;private final String message;}
package com.meteor.blog.common.file.service;import org.springframework.web.multipart.MultipartFile;import java.io.InputStream;
import java.util.List;
public interface FileTemplate {boolean directoryExists(String directory) throws Exception;List<String> listDirectories() throws Exception;void createDirectory(String directory) throws Exception;void removeDirectory(String directory) throws Exception;List<String> listFiles() throws Exception;String uploadFile(String fileName, InputStream inputStream) throws Exception;String uploadFile(String directory, String fileName, InputStream inputStream) throws Exception;void removeFile(String directory, String fileName) throws Exception;void removeFiles(String directory, List<String> fileNames) throws Exception;InputStream downloadFile(String directory, String fileName) throws Exception;}
package com.meteor.blog.common.file.service;import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.meteor.blog.common.file.strategy.FileStrategy;
import lombok.RequiredArgsConstructor;
import org.springframework.util.Assert;import java.io.InputStream;
import java.util.List;
@RequiredArgsConstructor
public class FileTemplateImpl implements FileTemplate {private final FileStrategy fileStrategy;@Overridepublic boolean directoryExists(String directory) throws Exception {Assert.isTrue(StrUtil.isNotBlank(directory), "The directory cannot be blank");return fileStrategy.directoryExists(directory);}@Overridepublic List<String> listDirectories() throws Exception {return fileStrategy.listDirectories();}@Overridepublic void createDirectory(String directory) throws Exception {Assert.isTrue(StrUtil.isNotBlank(directory), "The directory cannot be blank");fileStrategy.createDirectory(directory);}@Overridepublic void removeDirectory(String directory) throws Exception {Assert.isTrue(StrUtil.isNotBlank(directory), "The directory cannot be blank");fileStrategy.removeDirectory(directory);}@Overridepublic List<String> listFiles() throws Exception {return fileStrategy.listFiles();}@Overridepublic String uploadFile(String fileName, InputStream inputStream) throws Exception {Assert.isTrue(StrUtil.isNotBlank(fileName), "The fileName cannot be blank");Assert.notNull(inputStream, "The inputStream cannot be null");fileStrategy.uploadFile(fileName, inputStream);return null;}@Overridepublic String uploadFile(String directory, String fileName, InputStream inputStream) throws Exception {fileStrategy.uploadFile(directory, fileName, inputStream);return "";}@Overridepublic void removeFile(String directory, String fileName) throws Exception {Assert.isTrue(StrUtil.isNotBlank(directory), "The directory cannot be blank");Assert.isTrue(StrUtil.isNotBlank(fileName), "The fileName cannot be blank");fileStrategy.removeFile(directory, fileName);}@Overridepublic void removeFiles(String directory, List<String> fileNames) throws Exception {Assert.isTrue(StrUtil.isNotBlank(directory), "The directory cannot be blank");Assert.isTrue(CollUtil.isNotEmpty(fileNames), "The fileNames cannot be empty");fileStrategy.removeFiles(directory, fileNames);}@Overridepublic InputStream downloadFile(String directory, String fileName) throws Exception {Assert.isTrue(StrUtil.isNotBlank(directory), "The directory cannot be blank");Assert.isTrue(StrUtil.isNotBlank(fileName), "The fileName cannot be blank");return fileStrategy.downloadFile(directory, fileName);}}