第19章 用 Spring Boot 和 MongoDB GridFS实现大文件存储与管理

本文通过一个在线教育平台的实际案例,详细介绍如何使用 Spring Boot 和 MongoDB 的 GridFS 功能来存储和管理大文件(如视频、图片等)。我们将从环境搭建、代码实现到测试验证,一步步带你掌握 GridFS 的核心用法,让你轻松应对大文件存储的需求。

知识回顾

简介

MongoDB 是一种文档型数据库,主要用于存储 JSON 格式的数据,但它也能处理普通的文件。通过 BSON 格式,MongoDB 可以轻松保存各种类型的文件,比如图片或文本文件。不过,单个 BSON 文档的大小不能超过 16MB,这限制了大文件的直接存储。为了解决这个问题,MongoDB 提供了 GridFS 功能,允许我们存储大于 16MB 的文件。特点注意:GridFS不支持多文档事务。

基本原理

GridFS 的工作方式很简单:将大文件分割成多个小块(称为 chunks),然后分别存储这些小块。每个文件的相关信息会被保存在一个名为 fs.files 的集合中,而实际的文件内容则会被分割并存储在另一个名为 fs.chunks 的集合里。

  1. 文件信息 (fs.files) 每条记录包含了文件的基本信息,如:
  • _id: 文件的唯一标识符。
  • length: 文件的总大小。
  • chunkSize: 每个 chunk 的大小,决定了文件会被分成多少部分。
  • uploadDate: 文件上传的时间。
  • filename: 文件的名字。
  • metadata: 用户可以自定义的额外信息,便于后续的查找和使用。
  1. 文件内容 (fs.chunks) 每个 chunk 由一条记录表示,包含的信息有:
  • _id: chunk 的唯一标识符。
  • files_id: 该 chunk 所属文件的 ID。
  • n: chunk 的序号,从 0 开始计数。
  • data: 实际的文件内容。

当文件大小不超过 chunkSize 时,fs.files 和 fs.chunks 中都只会有一条记录。但如果文件较大,则 fs.files 中仍只有一个条目,而 fs.chunks 中会有多个条目来存储不同的 chunk。

MongoDB 还会自动创建索引来加快查询速度,例如对 fs.files 集合中的文件名和上传时间建立索引,以及对 fs.chunks 集合中的文件 ID 和 chunk 序号建立索引。

通过这种方式,GridFS 让我们在 MongoDB 中高效地管理和访问大文件成为了可能。

任务描述

假设您正在开发一个在线教育平台,需要存储大量的教学视频资源。由于视频文件通常比较大,直接使用 BSON 格式存储可能会遇到 16MB 的大小限制。因此,您决定采用 GridFS 来解决这个问题。学习如何使用 MongoDB 的 GridFS 功能来存储和检索大文件(例如视频或大型图片文件)。

任务准备

  1. 安装 MongoDB 数据库。
  2. 安装 MongoDB Compass 或Navicat Premium 16其他图形化管理工具,用于查看数据库状态。
  3. 准备好一个大文件(例如一个 50MB 的视频文件)作为测试用例。
  4. 安装和配置好postman测试工具

任务实施

源代码地址:study-springboot-chapter22 gitee.com/ossbar/stud...

步骤 1:创建 Spring Boot 项目

  • 使用 Spring Initializr 创建一个新的 Spring Boot 项目。
  • 添加 Spring Web, Spring Data MongoDB 和 Thymeleaf 依赖。

步骤 2:依赖配置:

在 pom.xml 文件中添加必要的依赖项:

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

在application.yml文件中添加mongodb相关配置

yaml 复制代码
spring:
  data:
    mongodb:
      uri: mongodb://localhost:27019
      database: student

步骤3:创建MongoConfig注入GridFsTemplate

kotlin 复制代码
package com.cbitedu.springboot.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.data.mongodb.core.MongoTemplate;
import com.mongodb.client.MongoClient;

@Configuration
public class MongoConfig {

    @Bean
    public GridFsTemplate gridFsTemplate(MongoTemplate mongoTemplate) {
        return new GridFsTemplate(mongoTemplate.getMongoDbFactory(), mongoTemplate.getConverter());
    }
}

步骤4:创建FileService文件服务类

kotlin 复制代码
package com.cbitedu.springboot.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;

@Service
public class FileService {

    @Autowired
    private GridFsTemplate gridFsTemplate;

    // 上传文件
    public String uploadFile(MultipartFile file) throws IOException {
        return gridFsTemplate.store(file.getInputStream(), file.getOriginalFilename(), file.getContentType()).toString();
    }

    // 下载文件
    public GridFsResource downloadFile(String id) {
        return gridFsTemplate.getResource(id);
    }
}

步骤5:创建FileController文件控制类

kotlin 复制代码
package com.cbitedu.springboot.controller;
import com.cbitedu.springboot.service.FileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;

@RestController
@RequestMapping("/files")
public class FileController {

    @Autowired
    private FileService fileService;

    // 上传文件接口
    @PostMapping("/upload")
    public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) throws IOException {
        String fileId = fileService.uploadFile(file);
        return ResponseEntity.ok(fileId);
    }

    // 下载文件接口
    @GetMapping("/download/{id}")
    public ResponseEntity<?> downloadFile(@PathVariable String id) {
        try {
            GridFsResource resource = fileService.downloadFile(id);
            if (resource == null) {
                return ResponseEntity.status(HttpStatus.NOT_FOUND).body("文件不存在");
            }
            return ResponseEntity.ok()
                    .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename="" + resource.getFilename() + """)
                    .body(new InputStreamResource(resource.getInputStream()));
        } catch (IOException e) {
            // 处理下载文件时的异常
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("文件下载失败:" + e.getMessage());
        }
    }
}

步骤5:postman测试上传下载测试

上传文件接口测试:

  1. 打开 Postman

  2. 选择 POST 请求

  3. 在 URL 中输入 http://localhost:81/files/upload(假设你的 Spring Boot 应用运行在本地 81 端口)。

  4. 在 Body 选项中选择 form-data

  5. 添加一个键值对

    • Key: file
    • Value: 选择一个文件:test.mp4
  6. 发送请求,检查响应是否返回文件 ID。

下载文件接口测试:

  1. 选择 GET 请求
  2. 在 URL 中输入 http://localhost:81/files/download/{fileId},将 {fileId} 替换为在上传文件时获得的文件 ID。
  3. 发送请求,检查响应是否返回文件内容并提示下载。

实验实训

  • 尝试上传不同类型的文件(如图片、PDF、视频等)。
  • 修改 chunkSize 参数,观察对上传时间和存储效率的影响。
  • 实现一个简单的 Web 接口,允许用户上传和下载文件。
  • 探索 GridFS 的元数据功能,给文件添加标签或其他信息,以便于分类和搜索。
相关推荐
冒泡的肥皂2 小时前
MVCC初学demo(一
数据库·后端·mysql
.Shu.3 小时前
Redis Reactor 模型详解【基本架构、事件循环机制、结合源码详细追踪读写请求从客户端连接到命令执行的完整流程】
数据库·redis·架构
anghost1505 小时前
基于单片机的智能声控窗帘
单片机·嵌入式硬件·mongodb
薛晓刚6 小时前
当MySQL的int不够用了
数据库
SelectDB技术团队6 小时前
Apache Doris 在菜鸟的大规模湖仓业务场景落地实践
数据库·数据仓库·数据分析·apache doris·菜鸟技术
星空下的曙光6 小时前
mysql 命令语法操作篇 数据库约束有哪些 怎么使用
数据库·mysql
小楓12016 小时前
MySQL數據庫開發教學(一) 基本架構
数据库·后端·mysql
染落林间色6 小时前
达梦数据库-实时主备集群部署详解(附图文)手工搭建一主一备数据守护集群DW
数据库·sql
颜颜yan_7 小时前
企业级时序数据库选型指南:从传统架构向智能时序数据管理的转型之路
数据库·架构·时序数据库
lichenyang4537 小时前
管理项目服务器连接数据库
数据库·后端