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数据库常用的10条操作命令
Jun 18 MongoDB
详解MongoDB的条件查询和排序
Jun 23 MongoDB
Mongo服务重启异常问题的处理方法
Jul 01 MongoDB
mongodb数据库迁移变更的解决方案
Sep 04 MongoDB
阿里云服务器部署mongodb的详细过程
Sep 04 MongoDB
MongoDB日志切割的三种方式总结
Sep 15 MongoDB
MongoDB支持的索引类型
Apr 11 MongoDB
Centos系统通过Docker安装并搭建MongoDB数据库
Apr 12 MongoDB
SpringBoot集成MongoDB实现文件上传的步骤
Apr 18 MongoDB
MongoDB数据库之添删改查
Apr 26 MongoDB
详解MongoDB排序时内存大小限制与创建索引的注意事项
May 06 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完整的日历类(CLASS)
2006/11/27 PHP
PHP语法自动检查的Vim插件
2014/08/11 PHP
PHP也能干大事 随机函数
2015/04/14 PHP
PHP实现驼峰样式字符串(首字母大写)转换成下划线样式字符串的方法示例
2017/08/10 PHP
PHP 计算两个时间段之间交集的天数示例
2019/10/24 PHP
动态载入/删除/更新外部 JavaScript/Css 文件的代码
2010/07/03 Javascript
初窥JQuery(二)事件机制(2)
2010/12/06 Javascript
解决jquery submit()提交表单提示:f[s] is not a function
2013/01/23 Javascript
php与js的区别是什么
2013/08/05 Javascript
js中点击空白区域时文本框与隐藏层的显示与影藏问题
2013/08/26 Javascript
使用jQueryMobile实现滑动翻页效果的方法
2015/02/04 Javascript
Javascript中3个需要注意的运算符
2015/04/02 Javascript
javascript实现Table排序的方法
2015/05/15 Javascript
JavaScript中iframe实现局部刷新的几种方法汇总
2016/01/06 Javascript
Vuejs第一篇之入门教程详解(单向绑定、双向绑定、列表渲染、响应函数)
2016/09/09 Javascript
BootStrap表单控件之文本域textarea
2017/05/23 Javascript
webpack打包单页面如何引用的js
2017/06/07 Javascript
Vue仿支付宝支付功能
2018/05/25 Javascript
微信小程序上传文件到阿里OSS教程
2019/05/20 Javascript
详解Vue后台管理系统开发日常总结(组件PageHeader)
2019/11/01 Javascript
微信小程序点击view动态添加样式过程解析
2020/01/21 Javascript
Ant Design的Table组件去除
2020/10/24 Javascript
python 字符串格式化代码
2013/03/17 Python
Python3中使用PyMongo的方法详解
2017/07/28 Python
Python实现的快速排序算法详解
2017/08/01 Python
Python+matplotlib实现计算两个信号的交叉谱密度实例
2018/01/08 Python
python获取代码运行时间的实例代码
2018/06/11 Python
10分钟教你用python动画演示深度优先算法搜寻逃出迷宫的路径
2019/08/12 Python
python中with语句结合上下文管理器操作详解
2019/12/19 Python
Python语法之精妙的十个知识点(装B语法)
2020/01/18 Python
YII2 全局异常处理深入讲解
2021/03/24 PHP
12月小学生校园广播稿
2014/02/04 职场文书
优秀学生干部个人事迹材料
2014/06/02 职场文书
党支部创先争优活动总结
2014/08/28 职场文书
2016年寒假见闻
2015/10/10 职场文书
世界各国短波电台对东亚播送时间频率表(SW)
2021/06/28 无线电