SpringBoot整合MongoDB+GridFSFile完成crud,存储大型文件,2020年最新版,带注释。

目录

前言:文章有点长,希望客官能慢慢看,对您应该有一些帮助,网上的资料都太乱了。

MongoDB:

支持的数据类型:

Mongodb的优点:

实战使用:

前期准备

正式开始:

创建一个父模型类

创建一个子类模型类

编写service层接口

编写Impl层<重点>

编写controller层的接口


前言:文章有点长,希望客官能慢慢看,对您应该有一些帮助,网上的资料都太乱了,很不直接,笔者进行了大量的整合和优化,甚则可以自己封装一下以后直接进行使用。

MongoDB:

最像关系型数据库的非关系型数据库。

以二进制json的个数存储——BSON

支持的数据类型:

String 、对象id 、布尔值 、数组 、整数 、 浮点数(默认) 、null值 、正则表达式 、 代码 、二进制

 

Mongodb的优点:

高性能:

     支持索引

     高可用:

     高扩展:

其 他:

      数据结构灵活,没有固定的列(无模式)

缺点:

      对事物的支持不强

mongodb的安装笔者在这里就不说了,网上教程一大堆也很简单,推荐使用docker直接安装,方便好用。

实战使用:

前期准备

导入依赖:


    org.springframework.boot
    spring-boot-starter-data-mongodb



    cn.hutool
    hutool-all
    5.5.1

编写配置文件:

spring:
  data:
    mongodb:
        #库名称
      database: articledb
      host: 127.0.0.1
      port: 27017

编写配置类:

package com.juhe.web.config;

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;

/**
 * @author 
 * @date 2020/11/6 17:28
 */
@Configuration
public class MongoConfig {
    //获取配置文件中数据库信息
    @Value("${spring.data.mongodb.database}")
    String db;

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

创建工具类:

package com.liuh.commom.utils;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * @author 
 * @date 2020/12/9 15:29
 */
public class FileUtils {

  /**
   * @param response    响应
   * @param fileName    文件名称
   * @param contentType 文件类型
   * @param content     文件内容
   * @throws IOException
   */
  public static void downloadFile(HttpServletResponse response, String fileName, String contentType, byte[] content) throws IOException {
    // 通知浏览器进行文件下载
    response.setHeader("Content-Disposition", "attachment;filename=" + new String(fileName.getBytes(StandardCharsets.UTF_8), "ISO8859-1"));
    response.setContentType(contentType);
    response.setCharacterEncoding("utf-8");

    OutputStream outputStream = response.getOutputStream();
    outputStream.write(content);
    outputStream.flush();
    outputStream.close();
  }

  /**
   * 获取该输入流的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();
  }
}

正式开始:

创建一个父模型类

package com.liuh.mongodb.model;

import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.format.annotation.DateTimeFormat;

import java.io.Serializable;
import java.util.Date;

/**
 * 父类模型类
 * @author
 * @date 2020/11/30 15:51
 */
@Data
public class CommonFileModel implements Serializable {

    @Id
    @ApiModelProperty(value = "主键id")
    private String id;

    @ApiModelProperty("文件名称")
    private String name;

    @ApiModelProperty("文件类型")
    private String contentType;

    @ApiModelProperty("文件大小")
    private long size;

    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @ApiModelProperty("文件第一次上传时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date uploadDate;

    @ApiModelProperty("文件md5值")
    private String md5;

    @ApiModelProperty("文件后辍名")
    private String suffix;

    @ApiModelProperty("文件内容")
    private byte[] content;

    @ApiModelProperty("大文件管理GridsFsID")
    private String gridFsId;
}

创建一个子类模型类

      每一个业务的文件继承父模型类,进行解耦,并通过@Document(collection = "自定义的表名")

灵活性:mongodb的表可以通过程序直接创建

package com.liuh.mongodb.model;

import lombok.Data;
import org.springframework.data.mongodb.core.mapping.Document;

/**
 * 每一个业务应该有自己子模型类,继承父模型类,解耦
 * @author 
 * @date 2020/12/9 14:46
 */
@Data
//设置对应的表名称
@Document(collection = "mongodbTest")
public class testFileModel extends CommonFileModel{

}

编写service层接口

将数据存入mongodb

package com.liuh.mongodb.service;

import com.liuh.mongodb.model.TestFileModel;

import java.io.InputStream;
import java.util.Optional;

/**
 * @author 
 * @date 2020/12/9 14:51
 */
public interface TestMongodbService {
  /**
   * @param in        io输入流
   * @param fileModel 对应文件的模型类
   * @return 成功
   */
  TestFileModel savaFile(InputStream in, TestFileModel fileModel);

  /**
   * 从mongodb中将文件内容查询出来
   *
   * @param fileId 文件id
   * @return Optional
   */
  Optional getFileContent(String fileId);

  /**
   * 删除mongodb  根据file_id
   *
   * @param fileId
   * @return 1 success
   */
  int removeFile(String fileId);
}

编写Impl层<重点>

package com.liuh.mongodb.service.Impl;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.IdUtil;
import com.liuh.mongodb.model.TestFileModel;
import com.liuh.mongodb.service.TestMongodbService;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSDownloadStream;
import com.mongodb.client.gridfs.model.GridFSFile;
import com.mongodb.client.result.DeleteResult;
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 java.io.InputStream;
import java.util.Optional;

/**
 * @author 
 * @date 2020/12/9 15:08
 */
@Service
public class TestMongodbServiceImpl implements TestMongodbService {

  @Autowired
  GridFsTemplate gridFsTemplate;
  @Autowired
  MongoTemplate mongoTemplate;

  @Autowired
  GridFSBucket fsBucket;

  @Override
  public TestFileModel savaFile(InputStream in, TestFileModel fileModel) {
    //设置存入GridFs中的文件名
    String gridFsId = IdUtil.simpleUUID();
    //将文件二进制数据存入GridFs中
    //需要传递输入流,文件id,文件类型
    gridFsTemplate.store(in, gridFsId, fileModel.getContentType());
    fileModel.setGridFsId(gridFsId);
    //在这里将文件对象数据存入monggdb当中
    fileModel = mongoTemplate.save(fileModel);
    //在将文件id和文件名称返回给前端
    return fileModel;
    //总监:先存储文件对象,在存储文件内容
  }


  @Override
  public Optional getFileContent(String fileId) {
    //根据id将文件对象数据从mongodb中查询出来
    TestFileModel testFileModel = mongoTemplate.findById(fileId, TestFileModel.class);
    //随手进行非空判断
    if (testFileModel != null) {
      //因为实际上真正的数据是存储到gridFs当中的,通过文件对象中的GridFsId就能操作gridFs了
      Query gridQuery = new Query().addCriteria(Criteria.where("filename").is(testFileModel.getGridFsId()));
      try {
        //根据id查询单挑数据
        final GridFSFile fsFile = gridFsTemplate.findOne(gridQuery);
        //打开流下载对象
        assert fsFile != null;
        GridFSDownloadStream in = fsBucket.openDownloadStream(fsFile.getObjectId());
        //在随手判断一手长度>0
        if (in.getGridFSFile().getLength() > 0) {
          //获取流对象
          GridFsResource resource = new GridFsResource(fsFile, in);
          //获取数据
          testFileModel.setContent(IoUtil.readBytes(resource.getInputStream()));
          return Optional.of(testFileModel);
        } else {
          return Optional.empty();
        }
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
    return Optional.empty();
    //总结:先查出文件对象,在查出文件内容,在转换成流对象传递
  }

  @Override
  public int removeFile(String fileId) {
    //老办法先从mongodb中查询出对象数据,因为里面有我们需要的GridFs的id
    TestFileModel fileModel = mongoTemplate.findById(fileId, TestFileModel.class);
    //随手进行非空判断养成好习惯
    if (fileModel != null) {
      //根据对象中的gridfsid操作gridfs
      Query deleteFile = new Query().addCriteria(Criteria.where("filename").is(fileModel.getGridFsId()));
      //删除文件内容
      gridFsTemplate.delete(deleteFile);
      //删除文件对象
      Query deleteQuery = new Query(Criteria.where("id").is(fileId));
      DeleteResult remove = mongoTemplate.remove(deleteQuery, TestFileModel.class);
      return (int) remove.getDeletedCount();
      //总结先查询出 gridfsid 根据gridfsid删除gridfs中的文件内容,然后在删除mongodb中的文件对象。
    }
    return 0;
  }
}

编写controller层的接口

package com.juhe.demo.controller;

import com.liuh.commom.utils.FileUtils;
import com.liuh.mongodb.model.TestFileModel;
import com.liuh.mongodb.service.TestMongodbService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * @author 
 * @date 2020/12/9 14:37
 */
@RestController
@Api(tags = "mongodb测试API")
@RequestMapping("/test/mongodb")
@Slf4j
public class mongodbcontroller {
  @Autowired
  TestMongodbService testMongodbService;


  /**
   * 文件上传,并返回文件id和文件名称
   *
   * @param file
   * @return map
   */
  @PostMapping("/upload")
  @ApiOperation("上传附件")
  public Map uploadtest(MultipartFile file) {
    try {
      Map map = new HashMap<>(2);
      //将上窜的文件存储到首先创建好的模型类
      TestFileModel testFileModel = new TestFileModel();
      //从file中获取到文件名称
      testFileModel.setName(file.getOriginalFilename());
      //从file中获取到文件的长度
      testFileModel.setSize(file.getSize());
      //从file中获取到文件类型
      testFileModel.setContentType(file.getContentType());
      //记录首次上传时间
      testFileModel.setUploadDate(new Date());
      //获取文件后缀 通过‘.’的索引进行切割
      String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().indexOf("."));
      testFileModel.setSuffix(suffix);
      //获取这个输入流的MD5值
      testFileModel.setMd5(FileUtils.getMD5(file.getInputStream()));
      final TestFileModel fileModel = testMongodbService.savaFile(file.getInputStream(), testFileModel);
      //将实现层生成的文件id和文件名称返回给前端
      map.put("fileId", fileModel.getId());
      map.put("fileName", fileModel.getName());
      return map;
    } catch (Exception e) {
      e.printStackTrace();
    }
    return null;
  }

  @GetMapping("/download")
  @ApiOperation("文件下载")
  public void downloadtest(@RequestParam("fileId") String fineId, HttpServletResponse response) {
    try {
      //直接从实现层获取数据
      Optional fileContent = testMongodbService.getFileContent(fineId);
      TestFileModel fileModel = fileContent.get();
      //这里就用到了我们前期准备的工具类了,通知浏览器进行下载
      FileUtils.downloadFile(response, fileModel.getName(), fileModel.getContentType(), fileModel.getContent());
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  @DeleteMapping("/delete/file")
  @ApiOperation("删除文件")
  public int deletetestfile(@RequestParam String fileId){
    //先删除mongodb数据
     int i = testMongodbService.removeFile(fileId);
     if(i!=1){
       log.error("文件删除石板 文件id为:{}", fileId);
     }
     return i;
  }
}

源码地址:

https://liuhong.lanzous.com/iPyGLj7dsyb

 

 

 

 

 

 

你可能感兴趣的:(java,java,mongodb,springboot,spring)