SpringBoot使用策略模式实现文件存储【MinIO、阿里云OSS】

引入依赖

<!-- minio -->
<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>8.5.2</version>
</dependency>

<!-- Aliyun OSS SDK -->
<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
    <version>3.17.1</version>
</dependency>

配置

oss:
  type: MINIO
  endpoint: http://192.168.249.132:9001
  accessKey: xxx
  secretKey: xxx
  bucket: test
  prefix:
  nginxHost:

配置属性类

package com.qiangesoft.oss.config;

import com.qiangesoft.oss.constant.FileStoreTypeEnum;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * 文件配置属性类
 *
 * @author qiangesoft
 * @date 2024-05-13
 */
@Data
@Component
@ConfigurationProperties(prefix = "oss")
public class FileStoreProperties {

    /**
     * 存储类型:local/minio/aliyun
     */
    private FileStoreTypeEnum type = FileStoreTypeEnum.LOCAL;

    /**
     * 服务地址
     */
    private String endpoint;

    /**
     * 认证账户
     */
    private String accessKey;

    /**
     * 认证密码
     */
    private String secretKey;

    /**
     * 默认桶
     */
    private String bucket;

    /**
     * 路径前缀【type为local时生效】
     */
    private String prefix;

    /**
     * nginx代理
     */
    private String nginxHost;

}

策略工厂

package com.qiangesoft.oss.config;

import com.qiangesoft.oss.constant.FileStoreTypeEnum;
import com.qiangesoft.oss.strategy.FileStrategy;
import org.springframework.util.ObjectUtils;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 策略工厂
 *
 * @author qiangesoft
 * @date 2024-05-13
 */
public final class StrategyFactory {

    private static final Map<FileStoreTypeEnum, FileStrategy> STRATEGY_MAP = new ConcurrentHashMap<>();

    /**
     * 通过类型获取策略
     *
     * @param type
     * @return
     */
    public static FileStrategy getStrategy(FileStoreTypeEnum type) {
        return STRATEGY_MAP.get(type);
    }

    /**
     * 注册策略
     *
     * @param type
     * @param strategy
     */
    public static void register(FileStoreTypeEnum type, FileStrategy strategy) {
        if (ObjectUtils.isEmpty(type)) {
            return;
        }
        STRATEGY_MAP.put(type, strategy);
    }
}

策略接口

package com.qiangesoft.oss.strategy;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;

/**
 * 文件存储策略
 *
 * @author qiangesoft
 * @date 2023-04-21
 */
public interface FileStrategy extends InitializingBean {

    String POINT = ".";

    String SLASH = "/";

    /**
     * 存在分类
     *
     * @param catalog
     * @return
     * @throws Exception
     */
    boolean existsCatalog(String catalog) throws Exception;

    /**
     * 创建分类
     *
     * @param catalog
     * @throws Exception
     */
    void createCatalog(String catalog) throws Exception;

    /**
     * 获取分类
     *
     * @return
     */
    List<String> listCatalogs() throws Exception;

    /**
     * 删除分类
     *
     * @param catalog
     * @throws Exception
     */
    void removeCatalog(String catalog) throws Exception;

    /**
     * 上传文件
     *
     * @param catalog
     * @param file
     * @return
     * @throws Exception
     */
    String uploadFile(String catalog, MultipartFile file) throws Exception;

    /**
     * 删除文件
     *
     * @param catalog
     * @param fileName
     * @throws Exception
     */
    void removeFile(String catalog, String fileName) throws Exception;

    /**
     * 删除文件
     *
     * @param catalog
     * @param fileNames
     * @throws Exception
     */
    void removeFiles(String catalog, List<String> fileNames) throws Exception;

}

策略实现类

package com.qiangesoft.oss.strategy;

import com.qiangesoft.oss.config.FileStoreProperties;
import com.qiangesoft.oss.config.StrategyFactory;
import com.qiangesoft.oss.constant.FileStoreTypeEnum;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

/**
 * 本地策略实现
 *
 * @author qiangesoft
 * @date 2024-05-13
 */
@Slf4j
@RequiredArgsConstructor
@Service
@Primary
@ConditionalOnProperty(prefix = "oss", name = "type", havingValue = "local")
public class LocalStrategyImpl implements FileStrategy {

    private String prefix;

    public LocalStrategyImpl(FileStoreProperties fileStoreProperties) {
        this.prefix = fileStoreProperties.getPrefix();
    }

    @Override
    public boolean existsCatalog(String catalog) throws Exception {
        File file = new File(prefix + SLASH + catalog);
        return file.exists();
    }

    @Override
    public void createCatalog(String catalog) throws Exception {
        File file = new File(prefix + SLASH + catalog);
        if (!file.exists()) {
            file.mkdirs();
        }
    }

    @Override
    public List<String> listCatalogs() throws Exception {
        File file = new File(prefix);
        File[] files = file.listFiles();
        List<String> list = new ArrayList<>();
        for (File subFile : files) {
            if (subFile.isDirectory()) {
                list.add(subFile.getName());
            }
        }
        return list;
    }

    @Override
    public void removeCatalog(String catalog) throws Exception {
        File file = new File(prefix + SLASH + catalog);
        if (file.exists()) {
            file.delete();
        }
    }

    @Override
    public String uploadFile(String catalog, MultipartFile file) throws Exception {
        return null;
    }

    @Override
    public void removeFile(String catalog, String fileName) throws Exception {

    }

    @Override
    public void removeFiles(String catalog, List<String> fileNames) throws Exception {

    }

    @Override
    public void afterPropertiesSet() throws Exception {
        StrategyFactory.register(FileStoreTypeEnum.LOCAL, this);
    }
}
package com.qiangesoft.oss.strategy;

import com.qiangesoft.oss.config.FileStoreProperties;
import com.qiangesoft.oss.config.StrategyFactory;
import com.qiangesoft.oss.constant.FileStoreTypeEnum;
import io.minio.*;
import io.minio.messages.Bucket;
import io.minio.messages.DeleteError;
import io.minio.messages.DeleteObject;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * minio策略实现
 *
 * @author qiangesoft
 * @date 2024-05-13
 */
@Slf4j
@RequiredArgsConstructor
@Service
@ConditionalOnProperty(prefix = "oss", name = "type", havingValue = "minio")
public class MinioStrategyImpl implements FileStrategy {

    private MinioClient minioClient;

    public MinioStrategyImpl(FileStoreProperties fileStoreProperties) {
        this.minioClient = MinioClient.builder()
                .credentials(fileStoreProperties.getAccessKey(), fileStoreProperties.getSecretKey())
                .endpoint(fileStoreProperties.getEndpoint())
                .build();
    }

    @Override
    public boolean existsCatalog(String catalog) throws Exception {
        BucketExistsArgs args = BucketExistsArgs.builder().bucket(catalog).build();
        return minioClient.bucketExists(args);
    }

    @Override
    public void createCatalog(String catalog) throws Exception {
        if (!this.existsCatalog(catalog)) {
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(catalog).build());
        }
    }

    @Override
    public List<String> listCatalogs() throws Exception {
        return minioClient.listBuckets().stream().map(Bucket::name).collect(Collectors.toList());
    }

    @Override
    public void removeCatalog(String catalog) throws Exception {
        minioClient.removeBucket(RemoveBucketArgs.builder().bucket(catalog).build());
    }

    @Override
    public String uploadFile(String catalog, MultipartFile file) throws Exception {
        // 参数校验
        Assert.notNull(catalog, "bucketName is not blank");
        Assert.notNull(file, "file is not null");

        // 判断存储桶是否存在
        createCatalog(catalog);

        // 文件名
        String filename = file.getOriginalFilename();

        // 上传
        minioClient.putObject(PutObjectArgs.builder()
                .bucket(catalog)
                .object(filename)
                .stream(file.getInputStream(), file.getSize(), -1)
                .contentType(file.getContentType())
                .build());
        return catalog + SLASH + filename;
    }

    @Override
    public void removeFile(String catalog, String fileName) throws Exception {
        minioClient.removeObject(RemoveObjectArgs.builder().bucket(catalog).object(fileName).build());
    }

    @Override
    public void removeFiles(String catalog, 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(catalog).objects(deleteObjectList).build());
        for (Result<DeleteError> result : results) {
            DeleteError error = result.get();
            log.error("Error in deleting object " + error.objectName() + "; " + error.message());
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        StrategyFactory.register(FileStoreTypeEnum.MINIO, this);
    }
}
package com.qiangesoft.oss.strategy;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.Bucket;
import com.aliyun.oss.model.DeleteObjectsRequest;
import com.aliyun.oss.model.DeleteObjectsResult;
import com.qiangesoft.oss.config.FileStoreProperties;
import com.qiangesoft.oss.config.StrategyFactory;
import com.qiangesoft.oss.constant.FileStoreTypeEnum;
import io.minio.messages.DeleteObject;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 阿里云策略实现
 *
 * @author qiangesoft
 * @date 2024-05-13
 */
@Slf4j
@RequiredArgsConstructor
@Service
@ConditionalOnProperty(prefix = "oss", name = "type", havingValue = "aliyun")
public class AliyunStrategyImpl implements FileStrategy {

    private OSS ossClient;

    public AliyunStrategyImpl(FileStoreProperties fileStoreProperties) {
        this.ossClient = new OSSClientBuilder().build(fileStoreProperties.getEndpoint(),
                fileStoreProperties.getAccessKey(), fileStoreProperties.getSecretKey());
    }

    @Override
    public boolean existsCatalog(String catalog) throws Exception {
        return ossClient.doesBucketExist(catalog);
    }

    @Override
    public void createCatalog(String catalog) throws Exception {
        if (!this.existsCatalog(catalog)) {
            ossClient.createBucket(catalog);
        }
    }

    @Override
    public List<String> listCatalogs() throws Exception {
        return ossClient.listBuckets().stream().map(Bucket::getName).collect(Collectors.toList());
    }

    @Override
    public void removeCatalog(String catalog) throws Exception {
        ossClient.deleteBucket(catalog);
    }

    @Override
    public String uploadFile(String catalog, MultipartFile file) throws Exception {
        // 参数校验
        Assert.notNull(catalog, "bucketName is not blank");
        Assert.notNull(file, "file is not null");

        // 判断存储桶是否存在
        createCatalog(catalog);

        // 文件名
        String filename = file.getOriginalFilename();

        // 上传
        ossClient.putObject(catalog, filename, file.getInputStream());
        return catalog + SLASH + filename;
    }

    @Override
    public void removeFile(String catalog, String fileName) throws Exception {
        ossClient.deleteObject(catalog, fileName);
    }

    @Override
    public void removeFiles(String catalog, List<String> fileNames) throws Exception {
        List<DeleteObject> deleteObjectList = new ArrayList<>();
        for (String fileName : fileNames) {
            DeleteObject deleteObject = new DeleteObject(fileName);
            deleteObjectList.add(deleteObject);
        }

        DeleteObjectsResult result = ossClient.deleteObjects(new DeleteObjectsRequest(catalog).withKeys(fileNames));
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        StrategyFactory.register(FileStoreTypeEnum.ALI_OSS, this);
    }
}

文件服务类

package com.qiangesoft.oss.service;

import org.springframework.web.multipart.MultipartFile;

import java.util.List;

/**
 * 文件服务接口
 *
 * @author qiangesoft
 * @date 2024-05-13
 */
public interface IFileService {

    /**
     * 创建分类
     *
     * @param catalog
     * @throws Exception
     */
    void createCatalog(String catalog) throws Exception;

    /**
     * 获取分类
     *
     * @return
     */
    List<String> listCatalogs() throws Exception;

    /**
     * 删除分类
     *
     * @param catalog
     * @throws Exception
     */
    void removeCatalog(String catalog) throws Exception;

    /**
     * 上传文件
     *
     * @param catalog
     * @param file
     * @return
     * @throws Exception
     */
    String uploadFile(String catalog, MultipartFile file) throws Exception;

    /**
     * 删除文件
     *
     * @param catalog
     * @param fileName
     * @throws Exception
     */
    void removeFile(String catalog, String fileName) throws Exception;

    /**
     * 删除文件
     *
     * @param catalog
     * @param fileNames
     * @throws Exception
     */
    void removeFiles(String catalog, List<String> fileNames) throws Exception;

}

package com.qiangesoft.oss.service;

import com.qiangesoft.oss.config.FileStoreProperties;
import com.qiangesoft.oss.config.StrategyFactory;
import com.qiangesoft.oss.strategy.FileStrategy;
import org.springframework.beans.BeansException;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;

/**
 * 文件服务实现类
 *
 * @author qiangesoft
 * @date 2024-05-13
 */
@Service
public class FileServiceImpl implements IFileService, ApplicationContextAware, CommandLineRunner {

    private ApplicationContext applicationContext;

    private FileStrategy fileStrategy;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public void run(String... args) throws Exception {
        FileStoreProperties fileStoreProperties = this.applicationContext.getBean(FileStoreProperties.class);
        fileStrategy = StrategyFactory.getStrategy(fileStoreProperties.getType());
    }

    @Override
    public void createCatalog(String catalog) throws Exception {
        fileStrategy.createCatalog(catalog);
    }

    @Override
    public List<String> listCatalogs() throws Exception {
        return fileStrategy.listCatalogs();
    }

    @Override
    public void removeCatalog(String catalog) throws Exception {
        fileStrategy.removeCatalog(catalog);
    }

    @Override
    public String uploadFile(String catalog, MultipartFile file) throws Exception {
        return fileStrategy.uploadFile(catalog, file);
    }

    @Override
    public void removeFile(String catalog, String fileName) throws Exception {
        fileStrategy.removeFile(catalog, fileName);
    }

    @Override
    public void removeFiles(String catalog, List<String> fileNames) throws Exception {
        fileStrategy.removeFiles(catalog, fileNames);
    }

}

  • 19
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

PG_强哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值