第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 的元数据功能,给文件添加标签或其他信息,以便于分类和搜索。
相关推荐
恒辉信达23 分钟前
hhdb客户端介绍(53)
数据库·mysql·hhdb·数据库可视化界面客户端
指尖上跳动的旋律2 小时前
shell脚本定义特殊字符导致执行mysql文件错误的问题
数据库·mysql
一勺菠萝丶2 小时前
MongoDB 常用操作指南(Docker 环境下)
数据库·mongodb·docker
m0_748244833 小时前
StarRocks 排查单副本表
大数据·数据库·python
C++忠实粉丝3 小时前
Redis 介绍和安装
数据库·redis·缓存
wmd131643067124 小时前
将微信配置信息存到数据库并进行调用
数据库·微信
是阿建吖!4 小时前
【Linux】基础IO(磁盘文件)
linux·服务器·数据库
凡人的AI工具箱4 小时前
每天40分玩转Django:Django国际化
数据库·人工智能·后端·python·django·sqlite
ClouGence4 小时前
Redis 到 Redis 数据迁移同步
数据库·redis·缓存
m0_748236584 小时前
《Web 应用项目开发:从构思到上线的全过程》
服务器·前端·数据库