MongoDB存储文件,小文件存储在普通文档,大于>16MB存储在GridFs
1.1、存储小文件
文档存储类型JSON,图片等文件存储数据类型为BLOB(BSON),对应类型org.bson.types.Binary,如图
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说明
如图,与普通文档不同的是,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”字段数据,还原文件。
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