oss

工作中需要用到文件上传,之前使用的是本地文件系统存储方式,后来重构为支持多个存储源的方式,目前支持三种方式:local、seaweedfs、minio

存储介质

seaweedfs

seaweedfs是一款go语言开发的轻量级、高性能的存储服务器。

https://github.com/chrislusf/seaweedfs

# 启动 master
docker run -d \
-p 9333:9333 \
-p 19333:19333 \
-v /home/mining/report-cloud/docker/seaweedfs/master/data:/data \
--name seaweedfs-master \
chrislusf/seaweedfs:1.53 \
master -ip=master # 启动 volume
docker run -d \
-p 8080:8080 \
-p 18080:18080 \
-v /home/mining/report-cloud/docker/seaweedfs/volume01/data:/data \
--name seaweedfs-volume \
--link seaweedfs-master:master \
chrislusf/seaweedfs:1.53 \
volume -max=5 -mserver="master:9333" -port=8080

访问web地址:http://localhost:9333/

简单使用:

# 申请空间
curl http://localhost:9333/dir/assign
#
{"count":1,"fid":"4,017f52110b","url":"127.0.0.1:8080","publicUrl":"localhost:80
80"}
# 推送文件,4,017f52110b表示第4个volume,017f52110b表示文件的唯一标识
curl -F file=@/home/seaweedfs/balance.png http://127.0.0.1:8080/4,017f52110b

minio

MinIO是与Amazon S3 API兼容的高性能对象存储服务器,提供了人性化的管理页面

https://github.com/minio/minio

docker run --name report-minio \
-p 19000:9000 \
-e "MINIO_ACCESS_KEY=qweasdzxc" \
-e "MINIO_SECRET_KEY=1234567890" \
-v /home/mining/report-cloud/docker/minio:/data \
-d minio/minio:latest server /data # web 管理页面
http://localhost:19000/minio/login
# 创建一个 bucket 为 report
# 通过URL直接访问文件需要设置权限,参考下面博客
# https://blog.csdn.net/iKaChu/article/details/105809957
# 访问格式为
http://localhost:19000/bucket名/对象名

Java代码

maven依赖

<!-- oss 存储的依赖 -->
<!-- seaweedfs 依赖 -->
<dependency>
<groupId>org.lokra.seaweedfs</groupId>
<artifactId>seaweedfs-client</artifactId>
<version>0.7.3.RELEASE</version>
</dependency> <!-- minio 依赖 -->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>3.0.10</version>
</dependency>

代码

配置类

FileTag 枚举类

用来标记使用哪种存储介质

/**
* 文件上传的tag
*/
public enum FileTag {
TYPE_LOCAL,
TYPE_MINIO ,
TYPE_SEAWEEDFS;
}

FileUploadConfigLocal

本地存储配置类

public class FileUploadConfigLocal {
private String parentPath;
// 省略 get set
}

FileUploadConfigSeaweedfs

seaweedfs存储配置类

public class FileUploadConfigSeaweedfs {
private String host;
private int port = 9333;
private String publicUrl;
private int connectTimeout = 60; // 60 s
// 省略 get set
}

FileUploadConfigMinio

minio存储配置类

public class FileUploadConfigMinio {
private String domain; // url 前缀
private String accesKey;
private String secretKey;
private String bucket; // 必须事先创建好
// 省略 get set
}

FileUploadConfig

spring application.yaml 配置类

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties( prefix = "oss-config")
public class FileUploadConfig {
FileTag tag;
FileUploadConfigLocal local;
FileUploadConfigSeaweedfs seaweedfs;
FileUploadConfigMinio minio;
// 省略 get set
}

配置文件

application.yaml

# 对象存储配置
oss-config:
tag: TYPE_LOCAL # 使用哪种存储介质
local:
parent-path: D:\dev\2019-06-19\upload
minio:
domain: http://localhost:19000
bucket: report
acces-key: qweasdzxc
secret-key: 1234567890
seaweedfs:
host: localhost
port: 9333
publicUrl: http://localhost:8080
connectTimeout: 3000 # 5min

FileUploadInfoVO文件上传类

public class FileUploadInfoVO {

    private String fileName; // 文件名
private String suffix; // 文件后缀
private String contentType; // 文件类型
private Long size; // 文件大小
private String fid; // 文件唯一ID,同时也是保存在服务器上的文件名
private boolean delete; // 是否删除,默认false
private String description;
private String url; // 完整的url
private String tag; // 标签,比如
private String uploadTime;
private String deleteTime;
// 省略 get set
}

业务逻辑类

FileStorageService 文件存储接口

/**
* 文件存储的接口
*/
public interface FileStorageService {
FileUploadInfoVO upload(InputStream in, FileUploadInfoVO fileUploadInfoVO) throws Exception ;
FileUploadInfoVO upload(byte[] bytes, FileUploadInfoVO fileUploadInfoVO) throws Exception ;
FileUploadInfoVO delete(FileUploadInfoVO fileUploadInfoVO) throws Exception ;
}

本地存储实现

@Service("FileStorageServiceLocal")
public class FileStorageServiceLocal implements FileStorageService { @Autowired
FileUploadConfig fileUploadConfig; @PostConstruct
public void init() {
FileUtils.checkAndCreateDir(fileUploadConfig.getLocal().getParentPath());
} @Override
public FileUploadInfoVO upload(InputStream in, FileUploadInfoVO fileUploadInfoVO) throws Exception {
String filePath = fileUploadConfig.getLocal().getParentPath() + File.separator + fileUploadInfoVO.getFid();
FileUtils.copyFileFromInputStream(in, filePath);
fileUploadInfoVO.setUrl(filePath+"."+fileUploadInfoVO.getSuffix());
return fileUploadInfoVO;
} @Override
public FileUploadInfoVO upload(byte[] bytes, FileUploadInfoVO fileUploadInfoVO) throws Exception {
String filePath = fileUploadConfig.getLocal().getParentPath() + File.separator + fileUploadInfoVO.getFid();
FileUtils.copyFileFromBytes(bytes, filePath);
fileUploadInfoVO.setUrl(filePath);
return fileUploadInfoVO;
} @Override
public FileUploadInfoVO delete(FileUploadInfoVO fileUploadInfoVO) throws Exception {
File file = new File(fileUploadInfoVO.getUrl());
if(file.exists()) {
file.delete();
}
return fileUploadInfoVO;
}
}

Seaweedfs存储实现

@Service("FileStorageServiceSeaweedfs")
public class FileStorageServiceSeaweedfs implements FileStorageService { @Autowired
FileUploadConfig fileUploadConfig; FileTemplate fileTemplate; @PostConstruct
public void init() {
FileUploadConfigSeaweedfs seaweedfs = fileUploadConfig.getSeaweedfs();
FileSource fileSource = new FileSource();
fileSource.setHost(seaweedfs.getHost());
fileSource.setPort(seaweedfs.getPort());
fileSource.setConnectionTimeout(seaweedfs.getConnectTimeout());//5min
try {
fileSource.startup();
} catch (IOException e) {
throw new RuntimeException("创建seaweedfs连接失败,原因是:" + e.getMessage());
}
fileTemplate = new FileTemplate(fileSource.getConnection(), seaweedfs.getPublicUrl());
} @Override
public FileUploadInfoVO upload(InputStream in, FileUploadInfoVO fileUploadInfoVO) throws Exception {
FileHandleStatus fileHandleStatus = fileTemplate.saveFileByStream(fileUploadInfoVO.getFileName(), in, ContentType.create(fileUploadInfoVO.getContentType(), "utf-8"));
fileUploadInfoVO.setFid(fileHandleStatus.getFileId());
fileUploadInfoVO.setUrl(String.format("%s/%s", fileUploadConfig.getSeaweedfs().getPublicUrl(), fileHandleStatus.getFileId()));
return fileUploadInfoVO;
} @Override
public FileUploadInfoVO upload(byte[] bytes, FileUploadInfoVO fileUploadInfoVO) throws Exception {
return upload(new ByteArrayInputStream(bytes), fileUploadInfoVO);
} @Override
public FileUploadInfoVO delete(FileUploadInfoVO fileUploadInfoVO) throws Exception {
fileTemplate.deleteFile(fileUploadInfoVO.getFid());
return fileUploadInfoVO;
}
}

Minio存储实现

@Service("FileStorageServiceMinio")
public class FileStorageServiceMinio implements FileStorageService { @Autowired
FileUploadConfig fileUploadConfig; @Override
public FileUploadInfoVO upload(InputStream in, FileUploadInfoVO fileUploadInfoVO) throws Exception {
FileUploadConfigMinio minio = fileUploadConfig.getMinio();
String domain = minio.getDomain();
String bucket = minio.getBucket();
String fileName = fileUploadInfoVO.getFileName();
MinioClient minioClient = new MinioClient(domain, minio.getAccesKey(), minio.getSecretKey());
minioClient.putObject("report", fileName, in, fileUploadInfoVO.getSize(), fileUploadInfoVO.getContentType());
fileUploadInfoVO.setUrl(String.format("%s/%s/%s", domain, bucket, fileName));
return fileUploadInfoVO;
} @Override
public FileUploadInfoVO upload(byte[] bytes, FileUploadInfoVO fileUploadInfoVO) throws Exception {
return upload(new ByteArrayInputStream(bytes), fileUploadInfoVO);
} @Override
public FileUploadInfoVO delete(FileUploadInfoVO fileUploadInfoVO) throws Exception {
FileUploadConfigMinio minio = fileUploadConfig.getMinio();
MinioClient minioClient = new MinioClient(minio.getDomain(), minio.getAccesKey(), minio.getSecretKey());
minioClient.removeObject(minio.getBucket(), fileUploadInfoVO.getFileName());
return fileUploadInfoVO;
}
}

存储工厂类实现

用来根据 FileTag 枚举类获得对应的具体实现

@Service
public class FileStorageFactory { Map<FileTag, FileStorageService> fileStorageServiceMap; @Qualifier("FileStorageServiceLocal")
@Autowired
FileStorageService fileStorageServiceLocal; @Qualifier("FileStorageServiceSeaweedfs")
@Autowired
FileStorageService fileStorageServiceSeaweedfs; @Qualifier("FileStorageServiceMinio")
@Autowired
FileStorageService fileStorageServiceMinio; @PostConstruct
public void init() {
fileStorageServiceMap = new HashMap<>();
fileStorageServiceMap.put(FileTag.TYPE_LOCAL, fileStorageServiceLocal);
fileStorageServiceMap.put(FileTag.TYPE_SEAWEEDFS, fileStorageServiceSeaweedfs);
fileStorageServiceMap.put(FileTag.TYPE_MINIO, fileStorageServiceMinio);
} public FileStorageService get(FileTag type) {
FileStorageService fileStorageService = fileStorageServiceMap.get(type);
return fileStorageService == null ? fileStorageServiceMap.get(FileTag.TYPE_LOCAL) : fileStorageService;
}
}

业务中实现

这里根据具体的业务,来选择具体的实现逻辑

eg:

@Autowired
private FileStorageFactory fileStorageFactory;
public FileUploadInfoVO put(MultipartFile multipartFile) throws Exception {
FileUploadInfoVO vo = new FileUploadInfoVO();
// 填充一些信息(省略)
// 获得文件上传处理器
FileStorageService fileStorageService = fileStorageFactory.get(FileTag.TYPE_LOCAL);
fileUploadInfoVO = fileStorageService.upload(multipartFile.getInputStream(), vo);
// ... 业务逻辑
}

这样,配置文件中可以使用FileTag来控制文件存储的介质,从而实现一个简单的对象存储服务器。

java实现简单的oss存储的更多相关文章

  1. Java使用阿里云OSS对象存储上传图片

    原 Java使用阿里云OSS对象存储上传图片 2017年03月27日 10:47:28 陌上桑花开花 阅读数 26804更多 分类专栏: 工作案例总结 版权声明:本文为博主原创文章,遵循CC 4.0 ...

  2. Java项目接入阿里云OSS存储

    需求背景 目前公司内部项目所支持的文件云存储方式还是公司内部项目组提供的方案,但在时间的考验之下,弊端显现,尤其是灾备切换过程中需要切换访问地址,这种操作不方便,更可能因为中间过程的失误导致资源不可用 ...

  3. java实现简单的单点登录

    java实现简单的单点登录 摘要:单点登录(SSO)的技术被越来越广泛地运用到各个领域的软件系统当中.本文从业务的角度分析了单点登录的需求和应用领域:从技术本身的角度分析了单点登录技术的内部机制和实现 ...

  4. 编写你的第一个 Java 版 Raft 分布式 KV 存储

    前言 本文旨在讲述如何使用 Java 语言实现基于 Raft 算法的,分布式的,KV 结构的存储项目.该项目的背景是为了深入理解 Raft 算法,从而深刻理解分布式环境下数据强一致性该如何实现:该项目 ...

  5. BerkeleyDB java的简单使用

    关于BerkeleyDB的有点和优点,列在以下 JE offers the following major features: Large database support. JE databases ...

  6. java实现简单窗体小游戏----球球大作战

    java实现简单窗体小游戏----球球大作战需求分析1.分析小球的属性: ​ 坐标.大小.颜色.方向.速度 2.抽象类:Ball ​ 设计类:BallMain—创建窗体 ​ BallJPanel—画小 ...

  7. 用Java实现简单的区块链

    用 Java 实现简单的区块链 1. 概述 本文中,我们将学习区块链技术的基本概念.也将根据概念使用 Java 来实现一个基本的应用程序. 进一步,我们将讨论一些先进的概念以及该技术的实际应用. 2. ...

  8. Java集合简单介绍

    再最前面分享一下我再学习集合时的方法: 1.首先了解各集合的定义和特点 2.集合的构造方法和常用方法(增删改查等) 3.了解集合使用的场景,再什么情况下使用什么类型的集合(关键是集合的特性) 4.了解 ...

  9. 谷粒 | 10 | 阿里云OSS存储对象服务

    阿里云OSS对象存储服务 准备工作 1.在service模块新建子模块service_oss 2.引入pom.xml文件中引入oss服务依赖 <dependencies> <!--a ...

随机推荐

  1. 转帖 支撑4.5亿活跃用户的WhatsApp架构概览

    http://www.csdn.net/article/2014-02-27/2818559-an-overview-at-whatsapp's-19b-architecture/2 写的很好,确实牛 ...

  2. Django之ORM执行原生sql语句

    django中的ORM提供的操作功能有限,在模型提供的查询API不能满足实际工作需要时,可以在ORM中直接执行原生sql语句. Django 提供两种方法使用原生SQL进行查询:一种是使用raw()方 ...

  3. shipyard的安装与一般维护

    #一.安装前的准备: docker pull alpine docker pull library/rethinkdb docker pull microbox/etcd docker pull sh ...

  4. 201771010128王玉兰《面向对象程序设计(Java)》第十周学习总结

    第一部分:理论知识部分总结: (1) 定义简单泛型类: A:泛型:也称参数化类型(parameterizedtype),就是在定义类.接口和方法时,通过类型参数指 示将要处理的对象类型. B:泛型程序 ...

  5. iOS [AFHTTPSessionManager GET:parameters:progress:success:failure:]: unrecognized selector sent to

    AFN更新到4.0.1后,崩溃[AFHTTPSessionManager GET:parameters:progress:success:failure:]: unrecognized selecto ...

  6. 【python爬虫】scrapy实战1--百万微博任性采集

    原文: https://blog.csdn.net/qq_36936730/article/details/105132550

  7. SpringMVC中使用@Valid和BindingResult进行参数验证

    我们知道,后端Controller层一般是第一层被调用,它用来接收参数以及转发,那么参数的校验也就在这一层,例如非空和格式校验等等. 手动验证 public String validPhone(Str ...

  8. webpack-dev-server 使用 react-router 启用 browserhistory 采坑记

    问题的产生 今天下午请假,忙完手头事之后,在家实在无聊,想着从0开始搭建一个 react 的项目.webpack 基本配置之前研究过,没什么大问题.谁想,在 react-router 的配置时出现了个 ...

  9. Vue 百度地图显示规划路线

    Vue 百度地图显示规划路线 1.首选引入相应的文件(建议单页面引入)(如有问题找上一篇博客园) 2.区别就是需要多引入几根不同的文件 import { BaiduMap, BmScale, BmGe ...

  10. Map.Entry的作用

    一般情况下,要输出Map中的key 和 value 是先得到key的集合,然后再迭代(循环)由每个key得到每个value 而Entry可以一次性获得这两个值 Set set = map.keySet ...