集成本地图片、云图片存储的思路

一、前言

最近在看一个开源项目,发现集成了本地存储以及云存储。大致看了一下思路,感觉也对面向对象的思想有了更进一步的理解。特来记录一下。

下文的描述不是很严谨,带有自己的理解存在。

如果有错误或者表述不恰当,欢迎指正。

二、思路

请添加图片描述

三、关键性的代码

以实现图片本地存储为例子

yml文件

storage:
  # 当前工作的对象存储模式,分别是local、aliyun、tencent、qiniu
  active: local
  # 本地对象存储配置信息
  local:
    # 存储路径
    storagePath: storage
    # 访问地址
    address: http://localhost:1203/storage/fetch/

读取yaml值的类

@ConfigurationProperties其实就类似于使用多个@Value同时绑定,绑定的对象就是隐式绑定yaml里面的storage里面的值,意味着在配置文件编写的时候需要与对应yaml的字段名称相同

@ConfigurationProperties(prefix = "storage")
@Data
public class StorageProperties {

    private String active;
    private Local local;

    public static class Local {
        private String address;
        private String storagePath;
		// 省略get与set方法
    }
}    

配置类获取绑定配置参数

@Configuration
@EnableConfigurationProperties(StorageProperties.class)
public class StorageAutoConfiguration {

    private final StorageProperties properties;

    public StorageAutoConfiguration(StorageProperties properties) {
        this.properties = properties;
    }

    /**
     * 获取配置参数里面的active值,通过active的不同,基础的存储服务类的中的存储模式也不同
     *
     * @author hanyulin
     * @date 2021/12/4 10:57
     * @return BaseStorageService
     */
    @Bean
    public BaseStorageService baseStorageService() {
        BaseStorageService baseStorageService = new BaseStorageService();
        String active = this.properties.getActive();
        baseStorageService.setActive(active);
        if ("local".equals(active)) {
            baseStorageService.setStorageType(localStorage());
        }
        else {
            throw new RuntimeException("当前存储模式 " + active + " 不支持");
        }
        return baseStorageService;
    }

    /**
     * 存储模式为local,注入LocalStorageImpl需要的属性
     *
     * @author hanyulin
     * @date 2021/12/4 11:11
     * @return com.hanliy.storage.impl.LocalStorageImpl
     */
    @Bean
    public LocalStorageImpl localStorage() {
        LocalStorageImpl localStorage = new LocalStorageImpl();
        StorageProperties.Local local = this.properties.getLocal();
        localStorage.setAddress(local.getAddress());
        localStorage.setStoragePath(local.getStoragePath());
        return localStorage;
    }
}

controller类

controller不做业务逻辑的处理

    @PostMapping("/upload")
    public Result<PicStorageEntity> create(@RequestParam("file") MultipartFile file) throws IOException {
        String originalFilename = file.getOriginalFilename();
        PicStorageEntity picStorage = baseStorageService.store(file.getInputStream(), file.getSize(),
                file.getContentType(), originalFilename);
        return new Result<PicStorageEntity>().ok(picStorage);
    }

基本的文件存储的业务类

负责对图片存储以及图片信息存储的转发

/**
 * @author hanyulin
 * @apiNote 基本的图片存储服务类,负责对图片存储以及图片信息存储的转发
 * @date 2021/12/3 16:27
 */
@Data
public class BaseStorageService {

    private String active;

    private StorageType storageType;

    @Resource
    private StorageService storageService;

    /**
     *  图片存储
     *
     * @param inputStream 图片流
     * @param contentLength 图片大小
     * @param contentType 图片的类型
     * @param fileName 图片原名称
     * @author hanyulin
     * @date 2021/12/4 11:24
     * @return PicStorageEntity
     */
    public PicStorageEntity store(InputStream inputStream, long contentLength, String contentType, String fileName) {
        /*
         * 产生图片唯一标识符号
         */
        String key = generateKey(fileName);
        /*
         * 调用接口StorageType的store实现文件存储
         */
        storageType.store(inputStream, contentLength, contentType, key);
        /*
         * 图片信息的存储
         */
        PicStorageEntity picStorage = new PicStorageEntity();
        picStorage.setName(fileName);
        picStorage.setSize((int) contentLength);
        picStorage.setType(contentType);
        picStorage.setPicKey(key);
        picStorage.setUrl(storageType.generateUrl(key));
        storageService.insert(picStorage);
        return picStorage;
    }

}    

存储服务接口类

提供不同的存储服务类,所有存储服务均由该类对外提供

/**
 * @author hanyulin
 * @apiNote 提供不同的存储服务类,所有存储服务均由该类对外提供
 * @date 2021/12/3 9:49
 */
public interface StorageType {

    /**
     * 存储一个文件对象
     *
     * @param inputStream   文件输入流
     * @param contentLength 文件长度
     * @param contentType   文件类型
     * @param keyName       文件名
     */
    void store(InputStream inputStream, long contentLength, String contentType, String keyName);
    /**
     * 通过唯一标识,产生访问路径
     * 
     * @param keyName 唯一标识名称
     * @return 访问路径
     */
    String generateUrl(String keyName);
}

本地存储实现类

@Data
public class LocalStorageImpl implements StorageType {

    private String storagePath;
    private String address;

    private Path rootLocation;

    /*
     * 创建图片的存储目录
     */
    public void setStoragePath(String storagePath) {
        this.storagePath = storagePath;

        this.rootLocation = Paths.get(storagePath);
        try {
            Files.createDirectories(rootLocation);
        } catch (IOException e) {
            e.getMessage();
        }
    }

    @Override
    public void store(InputStream inputStream, long contentLength, String contentType, String keyName) {
        try {
            Files.copy(inputStream, rootLocation.resolve(keyName), StandardCopyOption.REPLACE_EXISTING);
        } catch (IOException e) {
            throw new RuntimeException("Failed to store file " + keyName, e);
        }
    }
    
    @Override
    public String generateUrl(String keyName) {
        return address + keyName;
    }

四、测试

在这里插入图片描述

Q:在某个公众号看到一道面试题:一道面试题,GET 请求能传图片吗?

图片一般有两种传输方式:base64 和 file对象.

base64 :在客户端,由于浏览器地址栏的限制,只能够上传小图片(Blob、TypedArray、图片压缩方案)。在服务端,可以传任意大小的图片。

file:可以传输的,数据在body里面(GET 请求有 body 体。GET 和 POST 并没有本质上的区别,他们只是 HTTP 协议中两种请求方式,仅仅是报文格式不同(或者说规范不同)。)。

GET 请求能不能带 body 这个事是由 HTTP 协议来定义的。是一种规范。

SpringBootStudyDemos:pic-demo

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值