Springboot集成MongoDB存储文件、读取文件

这篇具有很好参考价值的文章主要介绍了Springboot集成MongoDB存储文件、读取文件。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、前言和开发环境及配置

可以转载,但请注明出处。  

之前自己写的SpringBoot整合MongoDB的聚合查询操作,感兴趣的可以点击查阅。

https://www.cnblogs.com/zaoyu/p/springboot-mongodb.html

 文章来源地址https://www.toymoban.com/news/detail-413167.html

使用mongodb存储文件并实现读取,通过springboot集成mongodb操作。 

可以有两种实现方式:

1. 单个文件小于16MB的,可以直接把文件转成二进制或者使用如Base64编码对文件做编码转换,以二进制或者string格式存入mongodb。

读取时,把二进制数据或者string数据转成对应的IO流或做解码,再返回即可。 

2. 对于单个文件大于16MB的,可以使用mongodb自带的GridFS

 

 开发环境、工具:JDK1.8,IDEA 2021

Springboot版本:2.7.5

Mongodb依赖版本:4.6.1

SpringBoot的配置 application.properties 如下

# 应用名称
spring.application.name=demo
#server.port=10086 不配置的话,默认8080

# springboot下mongoDB的配置参数。
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
# 指定数据库库名
spring.data.mongodb.database=temp

 

二、实现步骤和代码

1. 小文件存储

1.1 说明和限制

 由于MongoDB限制单个文档大小不能超过16MB,所以这种方式仅适用于单个文件小于16MB的。

如果传入大于16MB的文件,存储是会失败的,报错如下。

Springboot集成MongoDB存储文件、读取文件

 

1.2 实现代码

package com.onepiece.mongo;

import org.bson.Document;
import org.bson.types.Binary;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

import java.io.*;
import java.util.Base64;
import java.util.List;

/**
 * @author zaoyu
 * @description  用于演示Mongodb的文件存储(单个文件不大于16MB)
 */

@SpringBootTest
public class MongoSaveFiles {

    @Autowired
    private MongoTemplate mongoTemplate;

    // collection名
    private String IMAGE_COLLECTION = "image";
    // 源文件完整路径
    private String FILE_PATH = "D:\\temp\\onepiece.jpg";
    // 输出文件路径
    private String FILE_OUTPUT_PATH = "C:\\Users\\onepiece\\Desktop\\";
    // 限制16MB
    private Long FILE_SIZE_LIMIT = 16L * 1024L * 1024L;

    @Test
    public void saveFiles(){
        byte[] fileContent = null;
        FileInputStream fis = null;
        try {
            File file = new File(FILE_PATH);
            long length = file.length();
            // 校验文件大小,大于16MB返回。 这里的操作逻辑依据你自己业务需求调整即可。
            if (length >= FILE_SIZE_LIMIT) {
                System.out.println("文件: " + file.getAbsolutePath() + "  超出单个文件16MB的限制。" );
                return;
            }
            fileContent = new byte[(int) file.length()];
            fis = new FileInputStream(file);
            // 读取整个文件
            fis.read(fileContent);
            // 把文件内容以二进制格式写入到mongodb
            Document document = new Document();
            // fileName字段、content字段自定义。 
            document.append("fileName", file.getName());
            document.append("content", new Binary(fileContent));
            Document insert = mongoTemplate.insert(document, IMAGE_COLLECTION);
            System.out.println("文件 " + file.getName() + " 已存入mongodb,对应ID是: " + insert.get("_id").toString());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 测试读取并写入到指定路径。
     */
    @Test
    public void readAndWriteFiles(){
        // 这里也是,默认查所有,需要条件自行增加。 简单取1条验证。 
        List<Document> result = mongoTemplate.find(new Query(), Document.class, IMAGE_COLLECTION);
        Document document = result.get(0);
        // 取出存储的二进制数据,这里用binary.class处理。
        Binary content = document.get("content", Binary.class);
        String fileName = document.get("fileName", String.class);
        try {
            String newFilePath = FILE_OUTPUT_PATH + fileName;
            // 写入到指定路径
            FileOutputStream fos = new FileOutputStream(newFilePath);
            fos.write(content.getData());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

 

除了二进制的格式,也可以直接把文件用如Base64之类的编码工具来转码存储String。

  @Test
    public void testBase64(){
        saveFileWithBase64(FILE_PATH);
        getFileWithBase64();
    }

    public void saveFileWithBase64(String filePath){
        // 读取文件并编码为 Base64 格式
        File file = new File(filePath);
        byte[] fileContent = new byte[(int) file.length()];
        try (FileInputStream inputStream = new FileInputStream(file)) {
            inputStream.read(fileContent);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 把读取到的流转成base64
        String encodedString = Base64.getEncoder().encodeToString(fileContent);
        // 将 Base64 编码的文件内容存储到 MongoDB 文档中
        Document document = new Document();
        document.put("fileName", file.getName());
        document.put("base64Content", encodedString);
        Document insert = mongoTemplate.insert(document, IMAGE_COLLECTION);
        System.out.println("文件 " + file.getName() + " 已存入mongodb,对应ID是: " + insert.get("_id").toString());
    }

    public void getFileWithBase64(){
        Criteria criteria = Criteria.where("base64Content").exists(true);
        List<Document> result = mongoTemplate.find(new Query(criteria), Document.class, IMAGE_COLLECTION);
        Document document = result.get(0);
        String base64Content = document.get("base64Content", String.class);
        String fileName = document.get("fileName", String.class);
        byte[] decode = Base64.getDecoder().decode(base64Content);
        try {
            String newFilePath = FILE_OUTPUT_PATH + fileName;
            FileOutputStream fos = new FileOutputStream(newFilePath);
            fos.write(decode);
            System.out.println("文件已读取并复制到指定路径,详情为:" + newFilePath);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

 

1.3 落库效果 

直接存储二进制数据,可以看到,使用BinData存储,还会显示字节数(文件大小)。 

Springboot集成MongoDB存储文件、读取文件

 

2. 大于16MB的文件存储,使用GridFS

2.1 gridFS简介

GridFS is a specification for storing and retrieving files that exceed the BSON-document size limit of 16 MB.

字面直译就是说GridFS是用来存储大于BSON文档限制的16MB的文件。 

官方文档 https://www.mongodb.com/docs/manual/core/gridfs/   

 

存储原理:GridFS 会将大文件对象分割成多个小的chunk(文件片段), 一般为256k/个,每个chunk将作为MongoDB的一个文档(document)被存储在chunks集合中。

每一个数据库有一个GridFS区域,用来存储。

需要通过先创建bucket(和OSS中一样的概念)来存储,一个bucket创建后,一旦有文件存入,在collections中就会自动生成2个集合来存储文件的数据和信息,一般是bucket名字+files和bucket名字+chunks。 

每个文件的实际内容被存在chunks(二进制数据)中,和文件有关的meta数据(filename,content_type,还有用户自定义的属性)将会被存在files集合中。

如下图结构

Springboot集成MongoDB存储文件、读取文件

2.2 实现代码

package com.onepiece.mongo;

import com.mongodb.client.MongoDatabase;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSBuckets;
import com.mongodb.client.gridfs.model.GridFSUploadOptions;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.util.FileCopyUtils;

import java.io.*;
import java.util.List;

/**
 * @author zaoyu
 * @description:使用GridFS存储文件并做读取。
 */

@SpringBootTest
public class MongoGridFS {


    @Autowired
    private MongoTemplate mongoTemplate;

    // GridFS下的bucket,自行指定要把文件存储到哪个bucket。
    private String BUCKET_NAME = "images";
    // 源文件,即要被存储的文件的绝对路径
    private String FILE_PATH = "D:\\temp\\onepiece.jpg";
    // 存储文件后自动生成的存储文件信息的collection,一般是xx.files。 
    private String COLLECTION_NAME = "images.files";
    // 用于演示接收输出文件的路径
    private String FILE_OUTPUT_PATH = "C:\\Users\\onepiece\\Desktop\\";

    @Test
    public void testGridFSSaveFiles() {
        saveToGridFS();
        System.out.println("------------");
        readFromGridFS();
    }

    /**
     * 传入bucketName得到指定bucket操作对象。
     *
     * @param bucketName
     * @return
     */
    public GridFSBucket createGridFSBucket(String bucketName) {
        MongoDatabase db = mongoTemplate.getDb();
        return GridFSBuckets.create(db, bucketName);
    }

    /**
     * 储存文件到GridFS
     */
    public void saveToGridFS() {
        // 先调用上面方法得到一个GridFSBucket的操作对象
        GridFSBucket gridFSBucket = createGridFSBucket(BUCKET_NAME);
        File file = new File(FILE_PATH);
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        // 设置GridFS存储配置,这里是设置了每个chunk(块)的大小为1024个字节,也可以设置大一点。 MetaData是对文件的说明,如果不需要可以不写。 也是以键值对存在,BSON格式。
        GridFSUploadOptions options = new GridFSUploadOptions().chunkSizeBytes(1024).metadata(new Document("user", "onepiece"));
        // 调用GridFSBucket中的uploadFromStream方法,把对应的文件流传递进去,然后就会以binary(二进制格式)存储到GridFS中,并得到一个文件在xx.files中的主键ID,后面可以用这个ID来查找关联的二进制文件数据。
        ObjectId objectId = gridFSBucket.uploadFromStream(file.getName(), inputStream, options);
        System.out.println(file.getName() + "已存入mongodb gridFS, 对应id是:" + objectId);
    }

    /**
     * 从GridFS中读取文件
     */
    public void readFromGridFS() {
        // 这里查找条件我先不写,默认查所有,取第一条做验证演示。 用Document类接收。
        List<Document> files = mongoTemplate.find(new Query(), Document.class, COLLECTION_NAME);
        Document file = files.get(0);
        // 得到主键ID,作为等下要查询的文件ID值。
        ObjectId fileId = file.getObjectId("_id");
        String filename = file.getString("filename");
        // 先调用上面方法得到一个GridFSBucket的操作对象
        GridFSBucket gridFSBucket = createGridFSBucket(BUCKET_NAME);
        // 调用openDownloadStream方法得到文件IO流。
        InputStream downloadStream = gridFSBucket.openDownloadStream(fileId);
        FileOutputStream fileOutputStream = null;
        try {
            fileOutputStream = new FileOutputStream(FILE_OUTPUT_PATH + filename);
            // 把IO流直接到指定路径的输出流对象实现输出。
            FileCopyUtils.copy(downloadStream, fileOutputStream);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                fileOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

 2.3 落库效果

bucket:

Springboot集成MongoDB存储文件、读取文件

 

 注意这里的ID,就是files中的主键ID。

files collection (image.files):

Springboot集成MongoDB存储文件、读取文件

 

 chunks collection (image.chunks)

可以看到这里的files_id就是对应image.files中的主键ID。文件被拆成多个chunk块。

Springboot集成MongoDB存储文件、读取文件

 

三、小结

对于小文件的,可以直接转二进制存储,对于大于等于16MB的,使用GridFS存储。 

 

希望这篇文章能帮到大家,有错漏之处,欢迎指正。

请多点赞、评论~ 

完。

 

到了这里,关于Springboot集成MongoDB存储文件、读取文件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • springboot集成COS对象存储

    新建密钥(后面配置要用到) 此处使用工具类进行基本属性配置,也可选择在yml中配置

    2024年01月22日
    浏览(61)
  • SpringBoot集成-阿里云对象存储OSS

    阿里云对象存储 OSS (Object Storage Service),是一款海量、安全、低成本、高可靠的云存储服务。使用 OSS,你可以通过网络随时存储和调用包括文本、图片、音频和视频等在内的各种文件。 登录阿里云后进入阿里云控制台首页选择 对象存储 OSS 服务 开通服务 创建Bucket 填写

    2024年02月06日
    浏览(51)
  • Python:实现文件读取与输入,数据存储与读取的常用命令

    文本文件可用于存储大量的数据,里面的数据对于用户而言十分重要,因此,本文就如何利用Python实现文本内容的读取与输入,数据存储与读取进行介绍。 一、读取文件中的数据: 首先需要找到所需文件的路径:例如我在桌面创建了一个文本文件,它的路径为 利用函数 op

    2023年04月08日
    浏览(50)
  • 【uniapp】存储数据到本地文件以及读取本地文件数据

          可能存在的问题:                 1、高版本的安卓系统可能在文件系统中看不到文件但是可以读取                 2、该方法在安卓10系统中可能会有问题  

    2024年02月11日
    浏览(54)
  • Springboot集成阿里云对象存储oss-前端-后端完整实现

    1.注册阿里云并购买套餐流量包 2.点击套餐买个流量包,5元半年40g,还挺便宜    3.购买后进入管理控制台-点开对象存储oss 4.点开bucket创建,我已经创建好了    5.需要复制每个人的 外网访问,这个到时候需要在springboot项目中配置  6.点击个人头像创建每个人自己的key    

    2024年02月05日
    浏览(46)
  • 一款基于分布式文件存储的数据库MongoDB的介绍及基本使用教程

    MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。 在高负载的情况下,添加更多的节点,可以保证服务器性能。 MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。 MongoDB 将数据存储为一个文档,数据结构由键值(key=value)对组成。MongoDB 文档类

    2024年01月17日
    浏览(46)
  • uniapp安卓读取或写入txt文件,创建文件或文件夹,获取手机内置存储根路径

    原理:利用 H5plus 的 native ,引入 java 类来进行处理。 uniapp开发记录

    2024年02月11日
    浏览(59)
  • SpringBoot集成Milo库实现OPC UA客户端:连接、遍历节点、读取、写入、订阅与批量订阅

    前面我们搭建了一个本地的 PLC 仿真环境,并通过 KEPServerEX6 读取 PLC 上的数据,最后还使用 UAExpert 作为OPC客户端完成从 KEPServerEX6 这个OPC服务器的数据读取与订阅功能。在这篇文章中,我们将通过 SpringBoot 集成 Milo 库实现一个 OPC UA 客户端,包括连接、遍历节点、读取、写入

    2024年02月09日
    浏览(64)
  • vue+cordova混合开发APP中向手机本地存储/读取文件

    采用 vue + cordova 开发的App, 项目首屏为 three.js 编写的3D场景 3D模型的数据是首屏启动后前端调用接口获取的json数据,数据大小30M. 用户在首页与其他页面切换时,调用该接口时间过长,并消耗大量流量 解决思路: 首页页面不销毁,做缓存. (可行,但three.js的页面内存占用量极大,不做特

    2024年02月09日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包