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 常用的crud操作语句
Jun 20 MongoDB
MongoDB orm框架的注意事项及简单使用
Jun 20 MongoDB
mongodb的安装和开机自启动详细讲解
Aug 02 MongoDB
阿里云服务器部署mongodb的详细过程
Sep 04 MongoDB
mongodb清除连接和日志的正确方法分享
Sep 15 MongoDB
剖析后OpLog订阅MongoDB的数据变更就没那么难了
Feb 24 MongoDB
SpringBoot 整合mongoDB并自定义连接池的示例代码
Feb 28 MongoDB
一次线上mongo慢查询问题排查处理记录
Mar 18 MongoDB
MongoDB数据库部署环境准备及使用介绍
Mar 21 MongoDB
mongoDB数据库索引快速入门指南
Mar 23 MongoDB
Centos系统通过Docker安装并搭建MongoDB数据库
Apr 12 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 命名空间实例说明
2011/01/27 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(六)
2014/06/23 PHP
使用GD库生成带阴影文字的图片
2015/03/27 PHP
ThinkPHP中limit()使用方法详解
2016/04/19 PHP
PHP网站自动化配置的实现方法(必看)
2017/05/27 PHP
PHP调用微博接口实现微博登录的方法示例
2018/09/22 PHP
JavaScript 获取用户客户端操作系统版本
2009/08/25 Javascript
Javascript中的var_dump函数实现代码
2009/09/07 Javascript
js cookies实现简单统计访问次数
2009/11/24 Javascript
js之ActiveX控件使用说明 new ActiveXObject()
2014/03/03 Javascript
JS实现闪动的title消息提醒效果
2014/06/20 Javascript
JS控制弹出新页面窗口位置和大小的方法
2015/03/02 Javascript
JSON字符串和对象之间的转换详解
2015/05/26 Javascript
网页收藏夹显示ICO图标(代码少)
2015/08/04 Javascript
jQuery双向列表选择器select版
2016/11/01 Javascript
BootStrapTable服务器分页实例解析
2016/12/20 Javascript
使用Xcache缓存器加速PHP网站的配置方法
2017/04/22 Javascript
AngularJS 将再发布一个重要版本 然后进入长期支持阶段
2018/01/31 Javascript
总结JavaScript在IE9之前版本中内存泄露问题
2018/04/28 Javascript
使用elementUI实现将图片上传到本地的示例
2018/09/04 Javascript
新版小程序登录授权的方法
2018/12/12 Javascript
搭建一个nodejs脚手架的方法步骤
2019/06/28 NodeJs
JS如何在数组指定位置插入元素
2020/03/10 Javascript
python轻松实现代码编码格式转换
2015/03/26 Python
python协程用法实例分析
2015/06/04 Python
Python 实现文件的全备份和差异备份详解
2016/12/27 Python
Python中%r和%s的详解及区别
2017/03/16 Python
解决python3捕获cx_oracle抛出的异常错误问题
2018/10/18 Python
Python将字符串常量转化为变量方法总结
2019/03/17 Python
使用python进行广告点击率的预测的实现
2019/07/04 Python
Python 实现敏感目录扫描的示例代码
2020/05/21 Python
数控加工专业毕业生自荐信
2013/09/27 职场文书
计算机专业毕业生自我鉴定
2014/01/16 职场文书
公益广告标语
2014/06/19 职场文书
《地震中的父与子》教学反思
2016/02/16 职场文书
JavaScript实现两个数组的交集
2022/03/25 Javascript