广告
返回顶部
首页 > 资讯 > 后端开发 > Python >SpringBoot 使用Mongo的GridFs实现分布式文件存储操作
  • 766
分享到

SpringBoot 使用Mongo的GridFs实现分布式文件存储操作

2024-04-02 19:04:59 766人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

目录前言GridFs介绍什么时候使用GridFsGridFs的原理环境引入依赖和项目配置使用GridFsTemplate操作GridFs前言 这段时间在公司实习,安排给我一个任务,让

前言

这段时间在公司实习,安排给我一个任务,让在系统里实现一个知识库的模块,产品说,就像百度网盘那样。。。我tm…,这不就是应了那句话,“这个需求很简单,怎么实现我不管”。

可是我Google小能手怎么会认输呢,本来还说研究一下FastDFS啥的,但是因为我们项目用的Mongo作为数据库,了解到Mongo自带分布式文件系统GridFs,这简直天助我也。

GridFs介绍

什么时候使用GridFs

我们平时使用Mongo也可以直接把文件的二进制保存在Document中,就相当于Mysql的blob格式,但是mongo限制Document最大为16MB,那我们超过16MB的文件可咋办呐,就可以利用GridFs来存储。

  • 在某些情况下,在mongoDB数据库中存储大文件可能比在系统级文件系统上更高效。
  • 如果文件系统限制目录中的文件数,则可以使用GridFS根据需要存储任意数量的文件。如果要从大型文件的各个部分访问信息而无需将整个文件加载到内存中,可以使用GridFS调用文件的各个部分,而无需将整个文件读入内存。
  • 如果要保持文件和元数据在多个系统和设施中自动同步和部署,可以使用GridFS。使用地理位置分散的副本集时,MongoDB可以自动将文件及其元数据分发到多个 mongod实例和工具中。

GridFs的原理

GridFS不是将文件存储在单个文档中,而是将文件分成多个部分或块,并将每个块存储为单独的文档。

GridFS使用两个集合来存储文件。一个集合存储文件块,另一个存储文件元数据。

在这里插入图片描述 在这里插入图片描述

默认情况下,每一个块的大小为255kB; 但最后一个块除外。最后一个块只有必要的大小。类似地,不大于块大小的文件只有最终块,只使用所需的空间和一些额外的元数据。

当查询GridFS文件时,驱动程序将根据需要重新组装块。可以对通过GridFS存储的文件执行范围查询。还可以从文件的任意部分访问信息,例如“跳过”到视频或音频文件的中间。

环境

引入依赖和项目配置

首先添加Mongo客户端的依赖


<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

然后编写配置文件


spring:
  application:
    name: demo
  data:
    mongodb:
      uri: mongodb://root:你的密码@localhost:27019
      authentication-database: admin
      database: 你的数据库

使用GridFsTemplate操作GridFs

GridFsTemplate是Spring提供的专门操作GridFs的客户端,提供了一系列开箱即用的方法

在这里插入图片描述

只要把它注入到我们的Conteoller中,就可以愉快的CRUD了,需要注意的是获取文件时要注入MongoDbFactory ,我们使用默认配置的话,直接注入就好。

 
import com.mongodb.Block;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSBuckets;
import com.mongodb.client.gridfs.model.GridFSFile;
import com.mongodb.client.gridfs.model.GridFSUploadOptions;
import com.mongodb.gridfs.GridFS;
import com.mongodb.gridfs.GridFSDBFile;
import org.bson.BsonValue;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.WEB.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; 
import javax.servlet.Http.httpservletResponse;
import java.io.*;
import java.util.*;
   
@RestController
@RequestMapping("/files")
public class FileController {
	private Logger logger = LoggerFactory.getLogger(GridFsServiceImpl.class);
    //匹配文件ID的正则
    private static Pattern NUMBER_PATTERN = Pattern.compile("(?<==).*(?=})"); 
    @Autowired
    GridFsTemplate gridFsTemplate;
    @Autowired
    MongoDbFactory mongoDbFactory;
 
    
    @RequestMapping(value = "/upload", method = RequestMethod.POST)
    public Map<String, ObjectId> upload(@RequestParam(value = "file") MultipartFile file) {
  if(pathId == null || fileType == null || pathId.equals("") || fileType.equals("")){
            logger.debug("上传文件出错");
            throw new RuntimeException("上传文件出错:pathId and fileType can not be null");
        }
        Map<String, String> map = new HashMap<>(1);
        String fileName = file.getOriginalFilename();
        //设置元数据
        DBObject metaData = new BasicDBObject();
        metaData.put("userId","1");
        metaData.put("fileExtension",FilenameUtils.getExtension(file.getOriginalFilename()));
        //存储文件的扩展名
       
        try {
            InputStream inputStream = file.getInputStream();
            ObjectId fileId = gridFsTemplate.store(inputStream, fileName,metaData);
            //这个getFileId是我自己封装的获取文件ID的方法
            map.put(file.getOriginalFilename(),getFileId(fileId.toString()));
        } catch (IOException e) {
            logger.debug("上传文件失败: "+file);
            throw new RuntimeException("上传文件失败:"+e.getMessage());
        }
        return map;
    }
 
    
    @RequestMapping(value = "/downLoadByFileId")
    public void downLoadByFileId(@RequestParam(value = "fileId") ObjectId fileId, HttpServletResponse response) {
 GridFSFile gridFsFile = gridFsTemplate.findOne(new Query().addCriteria(Criteria.where("_id").is(fileId)));
        if (gridFsFile != null) {
            // mongo-java-driver3.x以上的版本就变成了这种方式获取
            GridFSBucket bucket = GridFSBuckets.create(mongoDbFactory.getDb());
            GridFSDownloadStream gridFsDownloadStream = bucket.openDownloadStream(gridFsFile.getObjectId());
            GridFsResource gridFsResource = new GridFsResource(gridFsFile,gridFsDownloadStream);
            String fileName = gridFsFile.getFilename().replace(",", "");
            //处理中文文件名乱码
            if (request.getHeader("User-Agent").toUpperCase().contains("MSIE") ||
                    request.getHeader("User-Agent").toUpperCase().contains("TRIDENT")
                    || request.getHeader("User-Agent").toUpperCase().contains("EDGE")) {
                fileName = java.net.URLEncoder.encode(fileName, "UTF-8");
            } else {
                //非IE浏览器的处理:
                fileName = new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
            }
            response.setHeader("Content-Disposition", "inline;filename=\"" + fileName + "\"");
            response.setContentType(application/octet-stream);
            IOUtils.copy(gridFsResource.getInputStream(), response.getOutputStream());
        }else {
            logger.info("文件不存在");
        } 
    }
    
	
    @RequestMapping("/search")
    public List<Map<String,Object>> search(String filePath, String fileName) {
		//这里返回的是一个List<Map<String,Object>>
		//因为GridFSFindIterable 迭代出来的GridFSFile不能直接返回
        GridFSFindIterable gridFSFiles = gridFsTemplate.find(new Query().addCriteria
                (Criteria.where("filename").regex("^.*"+fileName+".*$")));
        return getGridFSFiles(gridFSFiles);
    }
 
    
    @RequestMapping("/deleteFilesByObjectId")
    public boolean deleteFilesByObjectId(@RequestParam(value = "fileId") String fileId) {
         try {
            gridFsTemplate.delete(new Query().addCriteria(Criteria.where("_id").is(fileId)));
        }catch (Exception e){
            logger.debug("删除文件失败: fileId= "+fileId);
            throw new RuntimeException("删除文件失败:"+e.getMessage());
        }
    }
	
    private List<Map<String,Object>> getGridFSFiles(GridFSFindIterable gridFSFiles){
        List<Map<String,Object>> result = new ArrayList<>();
        for (GridFSFile file : gridFSFiles) {
            HashMap<String,Object> map = new HashMap<>(6);
            map.put("fileId",getFileId(file.getId().toString()));
            map.put("fileName",file.getFilename());
            map.put("fileExtension",file.getMetadata().get("fileExtension"));
            map.put("fileSize",file.getLength()/1024);
            map.put("uploadTime",file.getUploadDate());
            map.put("user",file.getMetadata().get("userId"));
            result.add(map);
        }
        return result;
    }
    
    private String getFileId(String bsonObjectId) {
        Matcher m = NUMBER_PATTERN.matcher(bsonObjectId);
        if(!m.find()){
            return bsonObjectId;
        }
        return m.group();
    }
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

--结束END--

本文标题: SpringBoot 使用Mongo的GridFs实现分布式文件存储操作

本文链接: https://www.lsjlt.com/news/155245.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • SpringBoot 使用Mongo的GridFs实现分布式文件存储操作
    目录前言GridFs介绍什么时候使用GridFsGridFs的原理环境引入依赖和项目配置使用GridFsTemplate操作GridFs前言 这段时间在公司实习,安排给我一个任务,让...
    99+
    2022-11-12
  • 使用Springboot整合GridFS实现文件操作
    目录GridFsOperations,实现GridFS文件上传下载删除上传下载删除功能实现测试上传下载删除GridFsOperations,实现GridFS文件上传下载删除 最近学习...
    99+
    2022-11-12
  • 如何利用Redis实现分布式文件存储
    如何利用Redis实现分布式文件存储在分布式系统中,大规模的文件存储是一个常见的需求。Redis作为一个高性能的缓存和存储系统,具有快速、可靠和可扩展的特点,非常适合用来实现分布式文件存储。本文将介绍如何利用Redis实现分布式文件存储,并...
    99+
    2023-11-07
    分布式 redis 文件存储
  • 如何使用 PHP 容器实现高效的分布式文件存储?
    随着互联网的不断发展,数据的存储需求越来越大。对于分布式系统而言,文件存储是一个非常重要的问题。PHP 容器可以帮助我们实现高效的分布式文件存储,本文将为大家介绍如何使用 PHP 容器实现高效的分布式文件存储。 一、什么是 PHP 容器? ...
    99+
    2023-10-01
    容器 文件 分布式
  • SpringBoot使用Minio进行文件存储的实现
    目录一、minio二、SpringBoot 使用 Minio 进行文件存储三、测试一、minio MinIO 是一个高性能的对象存储原生支持 Kubernetes 部署的解决方案。 ...
    99+
    2022-11-13
  • 文件分布式存储系统的Numpy实现方法有哪些?
    随着数据量的爆炸性增长和云计算、大数据等技术的发展,文件分布式存储系统越来越受到重视。文件分布式存储系统可以将大量数据分散存储在多台计算机上,实现数据的高效存储和访问。在实现分布式存储系统时,Numpy是一个非常强大的工具。那么,文件分布...
    99+
    2023-07-28
    文件 分布式 numpy
  • 分布式文件存储中,使用 PHP 容器的优缺点是什么?
    分布式文件存储是当前互联网技术中非常重要的一部分,而PHP容器在分布式文件存储中的应用也越来越广泛。那么在使用PHP容器时,有哪些优点和缺点呢? 一、优点 1.1 灵活性 使用PHP容器,可以很方便地进行动态扩展和缩减,而无需停机或者重启服...
    99+
    2023-10-01
    容器 文件 分布式
  • 如何使用PHP实现高效的实时索引和分布式存储?
    PHP是一种流行的Web开发语言,拥有强大的数据库和文件处理能力。在处理大量数据时,实时索引和分布式存储是非常重要的。本文将介绍如何使用PHP实现高效的实时索引和分布式存储。 一、实时索引 实时索引是指在数据写入时立即对其进行索引,以便能够...
    99+
    2023-07-06
    实时 索引 分布式
  • 如何使用Python和Apache实现高可用的分布式文件系统?
    随着互联网的发展,越来越多的数据需要被存储和管理。因此,分布式文件系统成为了一种流行的解决方案。在本文中,我们将介绍如何使用Python和Apache实现高可用的分布式文件系统。 什么是分布式文件系统? 分布式文件系统是由多个计算机节点...
    99+
    2023-07-31
    apache 文件 分布式
  • 如何在PHP中使用分布式函数实现高效的并发操作?
    在当今互联网时代,高并发操作已经成为了每个Web开发人员都需要考虑的问题。无论是从用户体验还是从服务器性能角度出发,都需要实现高效的并发操作。在PHP中,使用分布式函数可以实现高效的并发操作。本文将介绍如何在PHP中使用分布式函数实现高效的...
    99+
    2023-10-06
    分布式 函数 并发
  • 如何使用Go语言实现高效的分布式文件负载均衡?
    在分布式系统中,负载均衡是一个非常重要的问题。在处理大量数据和请求时,负载均衡可以帮助我们提高系统的性能和可靠性。Go语言是一种高效的编程语言,它可以帮助我们实现高效的分布式文件负载均衡。在本文中,我们将介绍如何使用Go语言实现高效的分布式...
    99+
    2023-08-18
    分布式 load 文件
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作