MongoDB存储文件,小文件存储在普通文档,大于>16MB存储在GridFs 

1.1、存储小文件

文档存储类型JSON,图片等文件存储数据类型为BLOB(BSON),对应类型org.bson.types.Binary,如图

mongodb 保存map mongodb 保存blob_mongodb


1.1.1、maven依赖

<!--引入mongoDb支持 -->
 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-data-mongodb</artifactId>
 </dependency>

1.1.2、文档对应实体

@ApiModel( description = "小文件集合")
@Data
@ToString
@Document(collection = "mongoPicture")
public class MongoPicture {

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

    @ApiModelProperty(value = "名称" )
    private String name;

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

    @ApiModelProperty(value = "分类" )
    private String type;

    @ApiModelProperty(value = "文件大小" )
    private Long size;


    @ApiModelProperty(value = "md5" )
    private String md5;

    @ApiModelProperty(value = "二进制内容" )
    private Binary content;

    @ApiModelProperty(value = "状态 1 正常 0 删除" )
    private String status;

1.1.3、文件上传控制层服务层

/**
 * 文件上传 控制层
 *
 * @param request
 * @return
 */
@RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
@ResponseBody
@ApiOperation(value = "上传文件", notes = "上传文件")
@ApiImplicitParam(name = "type", value = "1 标题 2 背景 3 小装饰 4 其他", required = true, dataType = "String", paramType = "query")
public Response uploadFile(@RequestParam("file")MultipartFile file,@RequestParam("type") String type) throws Exception {
    pictureService.uploadPicture(file,type);

    return new Response<>();
}

/**
 * 文件上传 服务层
 *
 */
  @Autowired
  private MongoTemplate mongoTemplate=null;

  // 保存图片文件
  public void uploadPicture(MultipartFile file, String type) throws Exception {
      MongoPicture mongoPicture = new MongoPicture(file.getOriginalFilename(), file.getContentType(),
              file.getSize(), new Binary(file.getBytes()), type);
      mongoPicture.setStatus("1");
      mongoPicture.setMd5(getMD5(file.getInputStream()));
      MongoPicture save = mongoTemplate.save(mongoPicture);
      // 
      MongoPictureRealation relation = new MongoPictureRealation();
      relation.setFileId(save.getId());
      relation.setName(save.getName());
      relation.setContentType(save.getContentType());
      relation.setUploadDate(new Date());
      relation.setStatus("1");
      relation.setType(save.getType());
      mongoTemplate.save(relation);

  }

1.2、存储大文件(保存到GridFs)

1.2.1、GridFs说明

mongodb 保存map mongodb 保存blob_存储文件_02


如图,与普通文档不同的是,GridFS使用两个集合(collection)存储文件。一个集合是chunks, 用于存储文件内容的二进制数据;一个集合是files,用于存储文件的元数据。

GridFS会将两个集合放在一个普通的buket中,并且这两个集合使用buket的名字作为前缀。MongoDB的GridFs默认使用fs命名的buket存放两个文件集合。因此存储文件的两个集合分别会命名为集合fs.files ,集合fs.chunks。

当把一个文件存储到GridFS时,如果文件大于chunksize (每个chunk块大小为256KB),会先将文件按照chunk的大小分割成多个chunk块,最终将chunk块的信息存储在fs.chunks集合的多个文档中。然后将文件信息存储在fs.files集合的唯一一份文档中。其中fs.chunks集合中多个文档中的file_id字段对应fs.files集中文档”_id”字段。

读文件时,先根据查询条件在files集合中找到对应的文档,同时得到“_id”字段,再根据“_id”在chunks集合中查询所有“files_id”等于“_id”的文档。最后根据“n”字段顺序读取chunk的“data”字段数据,还原文件。

mongodb 保存map mongodb 保存blob_字段_03

mongodb 保存map mongodb 保存blob_字段_04

mongodb 保存map mongodb 保存blob_字段_05

1.2.2、GridFs配置

配置桶对象和默认桶

/**
 **/
@Configuration
public class MongoGridFsConfig {

    @Value("${spring.data.mongodb.database}")
    String db;

    @Resource
    private MongoDbFactory mongoDbFactory;

    @Bean
    public GridFSBucket getGridFSBucket(MongoClient mongoClient){
        MongoDatabase database = mongoClient.getDatabase(db);
        GridFSBucket bucket = GridFSBuckets.create(database);
        return bucket;
    }

    // 默认文件桶fs 初始化需要创建fs文件组
    @Bean
    public GridFsTemplate gridFsTemplate(MongoDbFactory dbFactory, MongoConverter converter) {
        return new GridFsTemplate(dbFactory, converter, "fs");
    }
}

1.2.3、文件上传下载

// ko
    @Autowired
    private GridFsTemplate gridFsTemplate;

    @Autowired
    private GridFSBucket gridFSBucket;

    @Autowired
    private MongoGridService gridService;
    
    @RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value = "上传文件", notes = "上传文件")
    @ApiImplicitParam(name = "type", value = "", required = true, dataType = "String", paramType = "query")
    public Response uploadFile(@RequestParam("file")MultipartFile multiportFile,@RequestParam("type") String type) throws Exception {
        // 获得提交的文件名
        String fileName = multiportFile.getOriginalFilename();
        // 获得文件输入流
        InputStream ins = multiportFile.getInputStream();
        // 获得文件类型
        String contentType = multiportFile.getContentType();
        // 将文件存储到mongodb中,mongodb 将会返回这个文件的具体信息
        ObjectId objectId = gridFsTemplate.store(ins, fileName, contentType);
        //将维护文件类型关系
        gridService.save(fileName,objectId.toString(),type);

        return new Response<>();
    }

    /**
     * 下载
     *
     * @param fileId   文件id
     * @param response
     * @return
     */
    @GetMapping(value = "/downloadFile")
    @ApiOperation(value = "下载文件", notes = "下载文件")
    public void downloadFile(@RequestParam(name = "file_id") String fileId, HttpServletRequest request, HttpServletResponse response) throws Exception {
        Query query = Query.query(Criteria.where("_id").is(fileId));
        // 查询单个文件
        GridFSFile gfsFile = gridFsTemplate.findOne(query);
        GridFSDownloadStream in = gridFSBucket.openDownloadStream(gfsFile.getObjectId());
        GridFsResource gridFsResource=new GridFsResource(gfsFile, in);
        String fileName = gfsFile.getFilename().replace(",", "");
        //处理中文文件名乱码
        if (request.getHeader("User-Agent").toUpperCase().contains("MSIE") ||
                request.getHeader("User-Agent").toUpperCase().contains("TRIDENT")
                || request.getHeader("User-Agent").toUpperCase().contains("EDGE")) {
            fileName = java.net.URLEncoder.encode(fileName, "UTF-8");
        } else {
            //非IE浏览器的处理:
            fileName = new String(fileName.getBytes("UTF-8"), "ISO-8859-1");
        }
        // 通知浏览器进行文件下载
        response.setHeader("Content-Disposition", "attachment;filename=\"" + fileName + "\"");
        IOUtils.copy(gridFsResource.getInputStream(),response.getOutputStream());
    }

// 服务层

    /**
    * @Description:  保存文件关系
    * @Param: 
    */ 
    public void save(String fileName, String fileId, String type) {
        MongoGridFile target = new MongoGridFile();
        target.setFiledId(fileId);
        target.setFilename(fileName);
        target.setType(type);
        target.setUrl(getFileDownLoadUrl(fileId));
        mongoTemplate.save(target);
    }

Over