大家好,我是孙嵓,最近又居家办公了,今天给大家安利一波文件存储的集中解决方案。
不会吧,不会吧,不会还有人把文件存储到本地文件夹吧(额,突然一想好像所有的文件存储都是存储在文件夹里即使你是云服务器也一样,你把云服务器的文件夹删了文件也得没。。。)?但是嗯啊。。。这不是重点,重点是我们要对存储的文件进行合理的分类归纳管控。
孙嵓: 不知大家可否听闻对象存储这个概念?
小弟: 没听过。。。
孙嵓: low逼,对象存储都不知道?赶紧去工厂打螺丝去吧。
小弟: 大哥教教我吧,我给你生猴子
孙嵓: 看你那么诚恳的份上那我就给你讲讲。
对象存储是用来描述解决和处理离散单元的方法的通用术语。对象在一个层结构中不会再有层级结构,是以扩展元数据为特征的,这些离散单元被称作为对象。
小弟:这tm是啥啊?
孙嵓:确实挺难理解的,简单来说就是可以把层级看成是一个桶(这是个智能的桶),我们对每个桶都做了标识每一个桶都是独一无二的,对象看成是球(带型号的),我们需要把不同类型的球放进不同的桶里,放进去的球会有个标识,当你想用的某个球的时候拿这个球的表示让智能桶扫一下就会给你弹出来,这个桶里边不会套桶也就是上述说的层结构不会再有层结构。
小弟:嗯说的什么狗屎!!!
好了概念捋清楚了,我们来讲讲今天的重头戏minio对象存储,让我们做个简单的了解。
MinIO 是一款高性能、分布式的对象存储系统. 它是一款软件产品, 可以100%的运行在标准硬件。即X86等低成本机器也能够很好的运行MinIO。
MinIO与传统的存储和其他的对象存储不同的是:它一开始就针对性能要求更高的私有云标准进行软件架构设计。因为MinIO一开始就只为对象存储而设计。所以他采用了更易用的方式进行设计,它能实现对象存储所需要的全部功能,在性能上也更加强劲,它不会为了更多的业务功能而妥协,失去MinIO的易用性、高效性。 这样的结果所带来的好处是:它能够更简单的实现局有弹性伸缩能力的原生对象存储服务。
MinIO在传统对象存储用例(例如辅助存储,灾难恢复和归档)方面表现出色。同时,它在机器学习、大数据、私有云、混合云等方面的存储技术上也独树一帜。当然,也不排除数据分析、高性能应用负载、原生云的支持。
在中国:阿里巴巴、腾讯、百度、中国联通、华为、中国移动等等9000多家企业也都在使用MinIO产品
http://www.minio.org.cn/overview.shtml#
嗯,看起来很牛逼,那我们部署一下,我这边就先用windows简单搞一下吧,这是官网链接,支持Docker,Kubernetes,Windows,Mac,选择自己合适的版本下载。
http://www.minio.org.cn/index.shtml
<dependency>
<groupId>io.miniogroupId>
<artifactId>minioartifactId>
<version>8.0.0version>
dependency>
配置文件
# minio
minio:
url: http://127.0.0.1:9000
accessKey: minioadmin
secretKey: minioadmin
bucketName: test
Configuration
@Configuration
@ConfigurationProperties(prefix = "minio")
public class MinIoConfig {
private static String url;
private String accessKey;
private String secretKey;
private String bucketName;
@Bean
public MinioClient getMinisClient() {
return MinioClient.builder().endpoint(url)
.credentials(accessKey, secretKey)
.build();
}
如果你想区分文件类型,可以加个参,这里先给个通用的
public String upload(MultipartFile file, String bucket) throws Exception {
//文件大小校验
int fileNamelength = file.getOriginalFilename().length();
if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) {
throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
}
//后缀名校验
FileUploadUtils.assertAllowed(file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
//转成File临时文件
File template = FileUploadUtils.multipartFileToFile(file);
//文件头校验
FileUploadUtils.getType(template);
//源文件md5校验
String original = Md5Utils.md5(template);
//文件重命名
String filename = FileUploadUtils.extractFilename(file);
//上传至minio
PutObjectArgs args = PutObjectArgs.builder()
.bucket(bucket)
.object(filename)
.stream(file.getInputStream(), file.getSize(), -1)
.contentType(file.getContentType())
.build();
minioClient.putObject(args);
// 从MinIo取出
GetObjectArgs getArgs = GetObjectArgs.builder()
.bucket(bucket)
.object(filename)
.build();
InputStream inputStream = minioClient.getObject(getArgs);
try (BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();){
byte[] buffer = null;
int len = 0;
byte[] buf = new byte[2048];
while ((len = bufferedInputStream.read(buf)) != -1) {
byteArrayOutputStream.write(buf, 0, len);
}
byteArrayOutputStream.flush();
buffer = byteArrayOutputStream.toByteArray();
//计算上传后的md5值
String now = Md5Utils.md5(buffer);
//检验上传前后md5值是否一样防篡改
if (!now.equals(original)){
deleteFile(filename,bucket);
throw new IOException();
}
}catch (IOException e){
log.error(e.getMessage(), e);
}}finally {
//删除本地临时文件
FileUtils.deleteTempFile(template);
return filename;
}
public void deleteFile(String fileName, String bucket) throws Exception {
RemoveObjectArgs args = null;
try {
args = RemoveObjectArgs.builder()
.bucket(bucket)
.object(fileName)
.build();
minioClient.removeObject(args);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
public InputStream download(String filePath, String bucket, String downloadName, HttpServletResponse response) throws Exception {
if (!FileUtils.checkAllowDownload(filePath)) {
throw new Exception(StringUtils.format("资源文件({})非法,不允许下载。 ", filePath));
}
// 从MinIo取出
GetObjectArgs args = GetObjectArgs.builder()
.bucket(bucket)
.object(filePath)
.build();
InputStream inputStream = minioClient.getObject(args);
// 写出至响应
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
FileUtils.setAttachmentResponseHeader(response, downloadName);
try(ServletOutputStream os = response.getOutputStream()) {
if (inputStream == null) {
throw new FileNotFoundException(filePath);
}
byte[] b = new byte[1024];
int length;
while ((length = inputStream.read(b)) > 0) {
os.write(b, 0, length);
}
} catch (IOException e) {
log.error(e.getMessage(), e);
} finally {
if (inputStream != null) {
inputStream.close();
}
}
return inputStream;
}
public String preview(String filePath, String bucket, String downloadName, HttpServletResponse response) {
// 从MinIo取出
GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder()
.bucket(bucket)
.object(filePath)
.expiry(3600 * 24)
.method(Method.GET)
.build();
String url = null;
try {
url = minioClient.getPresignedObjectUrl(args);
response.setContentType(MediaType.APPLICATION_PDF_VALUE);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return url;
}
其他功能自个儿另行探索吧。