SpringBoot集成MongoDB实现文件上传的步骤


Posted in MongoDB onApril 18, 2022

前言

  • 记录下SpringBoot集成MongoDB实现文件上传的步骤
  • MongoDB - 5.0.6安装包

链接:https://pan.baidu.com/s/1lCcPvYYNWncb6lbvrZdeVg
提取码:0tf1

环境

SpringBoot - 2.5.12
MongoDB - 5.0.6

代码实现

pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- mongodb -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<!-- lombok -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>
<!-- hutool -->
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>4.5.1</version>
</dependency>

application.yml

server:
  port: 31091

spring:
  servlet:
    multipart:
      max-file-size: 100MB
  data:
    mongodb:
      host: 127.0.0.1
      port: 27017
      database: admin
      username: root
      password: sunday

fileUploadService:
  impl: fileMongoServiceImpl

MongoConfig.java

import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSBuckets;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Description MongoDB配置类
 */
@Configuration
public class MongoConfig {
    /**
     * 数据库配置信息
     */
    @Value("${spring.data.mongodb.database}")
    private String db;

    /**
     * GridFSBucket用于打开下载流
     * @param mongoClient
     * @return
     */
    @Bean
    public GridFSBucket getGridFSBucket(MongoClient mongoClient){
        MongoDatabase mongoDatabase = mongoClient.getDatabase(db);
        return GridFSBuckets.create(mongoDatabase);
    }
}

FileUploadController.java

import com.coisini.mongodb.model.ResponseMessage;
import com.coisini.mongodb.service.FileUploadService;
import com.coisini.mongodb.vo.FileExportVo;
import lombok.extern.slf4j.Slf4j;
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 javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
/**
 * @Description 文件上传接口
 */
@Slf4j
@RestController
@RequestMapping("/file")
public class FileUploadController {
    /**
     * 文件上传实现类
     */
    @Resource(name="${fileUploadService.impl}")
    private FileUploadService fileUploadService;
     * 文件上传
     * @param file
     * @return
    @PostMapping("/upload")
    public ResponseMessage<?> uploadFile(@RequestParam(value = "file") MultipartFile file) {
        try {
            return ResponseMessage.ok("上传成功", fileUploadService.uploadFile(file));
        } catch (Exception e) {
            log.error("文件上传失败:", e);
            return ResponseMessage.error(e.getMessage());
        }
    }
     * 多文件上传
     * @param files
    @PostMapping("/uploadFiles")
    public ResponseMessage<?> uploadFile(@RequestParam(value = "files") List<MultipartFile> files) {
            return ResponseMessage.ok("上传成功", fileUploadService.uploadFiles(files));
     * 文件下载
     * @param fileId
    @GetMapping("/download/{fileId}")
    public ResponseEntity<Object> fileDownload(@PathVariable(name = "fileId") String fileId) {
        FileExportVo fileExportVo = fileUploadService.downloadFile(fileId);
        if (Objects.nonNull(fileExportVo)) {
            return ResponseEntity.ok()
                    .header(HttpHeaders.CONTENT_DISPOSITION, "fileName=\"" + fileExportVo.getFileName() + "\"")
                    .header(HttpHeaders.CONTENT_TYPE, fileExportVo.getContentType())
                    .header(HttpHeaders.CONTENT_LENGTH, fileExportVo.getFileSize() + "").header("Connection", "close")
                    .body(fileExportVo.getData());
        } else {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body("file does not exist");
     * 文件删除
    @DeleteMapping("/remove/{fileId}")
    public ResponseMessage<?> removeFile(@PathVariable(name = "fileId") String fileId) {
        fileUploadService.removeFile(fileId);
        return ResponseMessage.ok("删除成功");
}

FileUploadService.java

import com.coisini.mongodb.vo.FileExportVo;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
 * @Description 文件上传接口
 */
public interface FileUploadService {
    /**
     * 文件上传
     * @param file
     * @return
     */
    FileExportVo uploadFile(MultipartFile file) throws Exception;
    /**
     * 多文件上传
     * @param files
     * @return
     */
    List<FileExportVo> uploadFiles(List<MultipartFile> files);
    /**
     * 文件下载
     * @param fileId
     * @return
     */
    FileExportVo downloadFile(String fileId);
    /**
     * 文件删除
     * @param fileId
     */
    void removeFile(String fileId);
}

FileMongoServiceImpl.java

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.IdUtil;
import com.coisini.mongodb.model.MongoFile;
import com.coisini.mongodb.repository.MongoFileRepository;
import com.coisini.mongodb.service.FileUploadService;
import com.coisini.mongodb.util.MD5Util;
import com.coisini.mongodb.vo.FileExportVo;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSDownloadStream;
import com.mongodb.client.gridfs.model.GridFSFile;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.bson.types.Binary;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
/**
 * @Description MongoDB文件上传实现类
 */
@Slf4j
@Service("fileMongoServiceImpl")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class FileMongoServiceImpl implements FileUploadService {
    private final MongoFileRepository mongoFileRepository;
    private final MongoTemplate mongoTemplate;
    private final GridFsTemplate gridFsTemplate;
    private final GridFSBucket gridFSBucket;
    /**
     * 多文件上传
     * @param files
     * @return
     */
    @Override
    public List<FileExportVo> uploadFiles(List<MultipartFile> files) {
        return files.stream().map(file -> {
            try {
                return this.uploadFile(file);
            } catch (Exception e) {
                log.error("文件上传失败", e);
                return null;
            }
        }).filter(Objects::nonNull).collect(Collectors.toList());
    }
    /**
     * 文件上传
     * @param file
     * @return
     * @throws Exception
     */
    @Override
    public FileExportVo uploadFile(MultipartFile file) throws Exception {
        if (file.getSize() > 16777216) {
            return this.saveGridFsFile(file);
        } else {
            return this.saveBinaryFile(file);
        }
    }
    /**
     * 文件下载
     * @param fileId
     * @return
     */
    @Override
    public FileExportVo downloadFile(String fileId) {
        Optional<MongoFile> option = this.getBinaryFileById(fileId);
        if (option.isPresent()) {
            MongoFile mongoFile = option.get();
            if(Objects.isNull(mongoFile.getContent())){
                option = this.getGridFsFileById(fileId);
            }
        }
        return option.map(FileExportVo::new).orElse(null);
    }
    /**
     * 文件删除
     * @param fileId
     */
    @Override
    public void removeFile(String fileId) {
        Optional<MongoFile> option = this.getBinaryFileById(fileId);
        if (option.isPresent()) {
            if (Objects.nonNull(option.get().getGridFsId())) {
                this.removeGridFsFile(fileId);
            } else {
                this.removeBinaryFile(fileId);
            }
        }
    }
    /**
     * 删除Binary文件
     * @param fileId
     */
    public void removeBinaryFile(String fileId) {
        mongoFileRepository.deleteById(fileId);
    }
    /**
     * 删除GridFs文件
     * @param fileId
     */
    public void removeGridFsFile(String fileId) {
        // TODO 根据id查询文件
        MongoFile mongoFile = mongoTemplate.findById(fileId, MongoFile.class );
        if(Objects.nonNull(mongoFile)){
            // TODO 根据文件ID删除fs.files和fs.chunks中的记录
            Query deleteFileQuery = new Query().addCriteria(Criteria.where("filename").is(mongoFile.getGridFsId()));
            gridFsTemplate.delete(deleteFileQuery);
            // TODO 删除集合mongoFile中的数据
            Query deleteQuery = new Query(Criteria.where("id").is(fileId));
            mongoTemplate.remove(deleteQuery, MongoFile.class);
        }
    }
    /**
     * 保存Binary文件(小文件)
     * @param file
     * @return
     * @throws Exception
     */
    public FileExportVo saveBinaryFile(MultipartFile file) throws Exception {
        String suffix = getFileSuffix(file);
        MongoFile mongoFile = mongoFileRepository.save(
                MongoFile.builder()
                        .fileName(file.getOriginalFilename())
                        .fileSize(file.getSize())
                        .content(new Binary(file.getBytes()))
                        .contentType(file.getContentType())
                        .uploadDate(new Date())
                        .suffix(suffix)
                        .md5(MD5Util.getMD5(file.getInputStream()))
                        .build()
        );
        return new FileExportVo(mongoFile);
    }
    /**
     * 保存GridFs文件(大文件)
     * @param file
     * @return
     * @throws Exception
     */
    public FileExportVo saveGridFsFile(MultipartFile file) throws Exception {
        String suffix = getFileSuffix(file);
        String gridFsId = this.storeFileToGridFS(file.getInputStream(), file.getContentType());
        MongoFile mongoFile = mongoTemplate.save(
                MongoFile.builder()
                        .fileName(file.getOriginalFilename())
                        .fileSize(file.getSize())
                        .contentType(file.getContentType())
                        .uploadDate(new Date())
                        .suffix(suffix)
                        .md5(MD5Util.getMD5(file.getInputStream()))
                        .gridFsId(gridFsId)
                        .build()
        );
        return new FileExportVo(mongoFile);
    }
    /**
     * 上传文件到Mongodb的GridFs中
     * @param in
     * @param contentType
     * @return
     */
    public String storeFileToGridFS(InputStream in, String contentType){
        String gridFsId = IdUtil.simpleUUID();
        // TODO 将文件存储进GridFS中
        gridFsTemplate.store(in, gridFsId , contentType);
        return gridFsId;
    }
    /**
     * 获取Binary文件
     * @param id
     * @return
     */
    public Optional<MongoFile> getBinaryFileById(String id) {
        return mongoFileRepository.findById(id);
    }
    /**
     * 获取Grid文件
     * @param id
     * @return
     */
    public Optional<MongoFile> getGridFsFileById(String id){
        MongoFile mongoFile = mongoTemplate.findById(id , MongoFile.class );
        if(Objects.nonNull(mongoFile)){
            Query gridQuery = new Query().addCriteria(Criteria.where("filename").is(mongoFile.getGridFsId()));
            try {
                // TODO 根据id查询文件
                GridFSFile fsFile = gridFsTemplate.findOne(gridQuery);
                // TODO 打开流下载对象
                GridFSDownloadStream in = gridFSBucket.openDownloadStream(fsFile.getObjectId());
                if(in.getGridFSFile().getLength() > 0){
                    // TODO 获取流对象
                    GridFsResource resource = new GridFsResource(fsFile, in);
                    // TODO 获取数据
                    mongoFile.setContent(new Binary(IoUtil.readBytes(resource.getInputStream())));
                    return Optional.of(mongoFile);
                }else {
                    return Optional.empty();
                }
            }catch (IOException e){
                log.error("获取MongoDB大文件失败", e);
            }
        }
        return Optional.empty();
    }
    /**
     * 获取文件后缀
     * @param file
     * @return
     */
    private String getFileSuffix(MultipartFile file) {
        String suffix = "";
        if (Objects.requireNonNull(file.getOriginalFilename()).contains(".")) {
            suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
        }
        return suffix;
    }
}

MongoFileRepository.java

import com.coisini.mongodb.model.MongoFile;
import org.springframework.data.mongodb.repository.MongoRepository;

/**
 * @Description MongoDB文件仓储
 */
public interface MongoFileRepository extends MongoRepository<MongoFile, String> {

}

MongoFile.java

import lombok.Builder;
import lombok.Data;
import org.bson.types.Binary;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import java.util.Date;

/**
 * @Description MongoDB文件实体
 */
@Document
@Builder
@Data
public class MongoFile {

    /**
     * 主键
     */
    @Id
    public String id;

    /**
     * 文件名称
     */
    public String fileName;

    /**
     * 文件大小
     */
    public long fileSize;

    /**
     * 上传时间
     */
    public Date uploadDate;

    /**
     * MD5值
     */
    public String md5;

    /**
     * 文件内容
     */
    private Binary content;

    /**
     * 文件类型
     */
    public String contentType;

    /**
     * 文件后缀名
     */
    public String suffix;

    /**
     * 文件描述
     */
    public String description;

    /**
     * 大文件管理GridFS的ID
     */
    private String gridFsId;

}

ResponseMessage.java

/**
 * @Description 统一消息
 */
public class ResponseMessage<T> {

    private String status;
    private String message;
    private T data;

    // 省略

}

FileExportVo.java

import java.util.Objects;

/**
 * @Description 统一文件下载vo
 */
@Data
public class FileExportVo {

    private String fileId;

    private String fileName;

    private String contentType;

    private String suffix;

    private long fileSize;

    @JsonIgnore
    private byte[] data;

    public FileExportVo(MongoFile mongoFile) {
        BeanUtil.copyProperties(mongoFile, this);
        if (Objects.nonNull(mongoFile.getContent())) {
            this.data = mongoFile.getContent().getData();
        }
        this.fileId = mongoFile.getId();
    }

}

MD5Util.java

import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * @Description MD5工具类
 */
public class MD5Util {
    /**
     * 获取该输入流的MD5值
     */
    public static String getMD5(InputStream is) throws NoSuchAlgorithmException, IOException {
        StringBuffer md5 = new StringBuffer();
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] dataBytes = new byte[1024];

        int nread = 0;
        while ((nread = is.read(dataBytes)) != -1) {
            md.update(dataBytes, 0, nread);
        };
        byte[] mdbytes = md.digest();

        // convert the byte to hex format
        for (int i = 0; i < mdbytes.length; i++) {
            md5.append(Integer.toString((mdbytes[i] & 0xff) + 0x100, 16).substring(1));
        }
        return md5.toString();
    }
}

测试

文件上传

SpringBoot集成MongoDB实现文件上传的步骤

多文件上传

SpringBoot集成MongoDB实现文件上传的步骤

文件下载

SpringBoot集成MongoDB实现文件上传的步骤

文件删除

SpringBoot集成MongoDB实现文件上传的步骤

源码

GitHubhttps://github.com/Maggieq8324/java-learn-demo/tree/master/springboot-mongodb-file

Giteehttps://gitee.com/maggieq8324/java-learn-demo/tree/master/springboot-mongodb-file

到此这篇关于SpringBoot 集成MongoDB实现文件上传的文章就介绍到这了!

MongoDB 相关文章推荐
MongoDB balancer的使用详解
Apr 30 MongoDB
浅析MongoDB之安全认证
Jun 26 MongoDB
mongodb的安装和开机自启动详细讲解
Aug 02 MongoDB
mongodb数据库迁移变更的解决方案
Sep 04 MongoDB
mongodb清除连接和日志的正确方法分享
Sep 15 MongoDB
springboot + mongodb 通过经纬度坐标匹配平面区域的方法
Nov 01 MongoDB
SpringBoot 整合mongoDB并自定义连接池的示例代码
Feb 28 MongoDB
MongoDB误操作后使用oplog恢复数据
Apr 11 MongoDB
Mongodb 迁移数据块的流程介绍分析
Apr 18 MongoDB
详解MongoDB排序时内存大小限制与创建索引的注意事项
May 06 MongoDB
NoSQL优缺点与MongoDB数据库简介
Jun 05 MongoDB
Centos系统通过Docker安装并搭建MongoDB数据库
MongoDB修改oplog大小的四种方法
Apr 11 #MongoDB
MongoDB支持的索引类型
Apr 11 #MongoDB
MongoDB支持的数据类型
Apr 11 #MongoDB
MongoDB误操作后使用oplog恢复数据
Apr 11 #MongoDB
mongoDB数据库索引快速入门指南
MongoDB数据库部署环境准备及使用介绍
You might like
php下HTTP Response中的Chunked编码实现方法
2008/11/19 PHP
PHP中的命名空间相关概念浅析
2015/01/22 PHP
PHP异常处理Exception类
2015/12/11 PHP
PHP5.2中PDO的简单使用方法
2016/03/25 PHP
浅析Yii2 GridView 日期格式化并实现日期可搜索教程
2016/04/22 PHP
做网页的一些技巧(续)
2007/02/01 Javascript
javascript十个最常用的自定义函数(中文版)
2009/09/07 Javascript
使用js操作css实现js改变背景图片示例
2014/03/10 Javascript
基于jQuery实现最基本的淡入淡出效果实例
2015/02/02 Javascript
【JS+CSS3】实现带预览图幻灯片效果的示例代码
2016/03/17 Javascript
jquery自定义插件——window的实现【示例代码】
2016/05/06 Javascript
JS实现星星评分功能实例代码(两种方法)
2016/06/09 Javascript
基于bootstrap按钮式下拉菜单组件的搜索建议插件
2017/03/25 Javascript
js装饰设计模式学习心得
2018/02/17 Javascript
nodeJS模块简单用法示例
2018/04/21 NodeJs
Vue 中文本内容超出规定行数后展开收起的处理的实现方法
2019/04/28 Javascript
使用webpack搭建vue项目及注意事项
2019/06/10 Javascript
Vue实现购物车详情页面的方法
2019/08/20 Javascript
基于vue-cli3和element实现登陆页面
2019/11/13 Javascript
vue打包通过image-webpack-loader插件对图片压缩优化操作
2020/11/12 Javascript
Vue+scss白天和夜间模式切换功能的实现方法
2021/01/05 Vue.js
Python使用htpasswd实现基本认证授权的例子
2014/06/10 Python
Python实现简单遗传算法(SGA)
2018/01/29 Python
Python读取Excel数据并生成图表过程解析
2020/06/18 Python
详解Selenium 元素定位和WebDriver常用方法
2020/12/04 Python
利用Bootstrap实现漂亮简洁的CSS3价格表实例源码
2017/03/02 HTML / CSS
廉价连衣裙和婚纱礼服在线销售:Tbdress
2019/02/28 全球购物
英国旅行箱包和行李箱购物网站:Travel Luggage & Cabin Bags
2019/08/26 全球购物
新闻网站实习自我鉴定
2013/09/25 职场文书
花卉与景观设计系大学生求职信
2013/10/01 职场文书
优乐美广告词
2014/03/14 职场文书
股权转让意向书
2014/04/01 职场文书
2015年小学校长工作总结
2015/05/19 职场文书
我的生日感言
2015/08/03 职场文书
Python进度条的使用
2021/05/17 Python
CSS filter 有什么神奇用途
2021/05/25 HTML / CSS