MongoDB GridFS 简介
MongoDB GridFS
是一个用于存储和检索大型文件的规范,它允许在MongoDB
数据库中存储超过16MB的文件,如图片、音频、视频等。GridFS通过将文件分割成多个小的chunk(文件片段),每个chunk通常为255KB,并将这些chunk存储在MongoDB的集合中,从而解决了MongoDB对单个文档大小的限制。以下是GridFS
的详细介绍:
GridFS的基本概念
- 文件分割:GridFS将大型文件分割成多个chunk,每个chunk的大小默认为255KB,最后一个chunk的大小可能小于255KB,以适应文件的实际大小。
- 存储结构:GridFS使用两个集合来存储文件:
fs.files
和fs.chunks
。fs.files
集合存储文件的元数据,如文件名、文件类型、上传时间等;fs.chunks
集合存储文件的二进制数据块。
GridFS的使用场景
- 存储大型文件:对于超过16MB的文件,可以使用GridFS进行存储。
- 文件的部分访问:可以只加载文件的部分内容,而不必将整个文件加载到内存中,这对于处理大文件非常有用。
- 分布式文件系统:在多个系统和设施之间自动同步和部署文件及元数据。
如何使用GridFS
- 安装MongoDB驱动程序:首先需要安装MongoDB的官方驱动程序。
- 连接到MongoDB数据库:在应用程序中创建一个MongoDB数据库连接。
- 创建GridFS存储:使用MongoDB的GridFS API创建一个GridFS存储对象。
- 上传文件:使用GridFS的API将文件上传到数据库中。
- 下载文件:使用GridFS的API从数据库中下载文件。
GridFS的优势
- 灵活性:GridFS允许存储任意大小的文件,只要它们可以分割成多个chunk。
- 性能:在某些情况下,存储大型文件在
MongoDB
数据库中可能比在系统级文件系统上更有效率。 - 易用: 使用springboot整合GridFS非常简单容易上手。
代码教程
引入依赖
在pom.xml文件中添加mongo依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
配置连接信息
在spring配置文件里,配置mongo数据库连接信息
spring:
data:
mongodb:
database: ${MONGO_DATABASE:work_face_exam}
uri: mongodb://${MONGO_USERNAME:glqxzh}:${MONGO_PASSWORD:123456789}@${MONGO_HOST:127.0.0.1}:27017
创建MongoDB GridFS 服务类
代码如下:
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.mongodb.client.gridfs.model.GridFSFile;
import lombok.AllArgsConstructor;
import org.bson.types.ObjectId;
import org.springblade.coalface.modules.file.vo.FileVO;
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.ArrayList;
import java.util.Date;
import java.util.List;
@Service
@AllArgsConstructor
public class MongoFileService {
private final GridFsTemplate gridFsTemplate;
public FileVO saveFile(MultipartFile file) throws IOException {
FileVO filevo = new FileVO();
// 新文件名
String originalFilename = file.getOriginalFilename();
filevo.setFileName(originalFilename);
filevo.setFileSize(file.getSize());
// 获得文件类型
String contentType = file.getContentType();
filevo.setType(contentType);
// 将文件存储到mongodb中,mongodb将会返回这个文件的具体信息
// 上传文件中我们也可以使用DBObject附加一些属性
// 获得文件输入流
InputStream ins = file.getInputStream();
DBObject metadata = new BasicDBObject();
ObjectId objectId = gridFsTemplate.store(ins, originalFilename, contentType, metadata);
filevo.setId(objectId.toString());
filevo.setUploadTime(new Date());
filevo.setUrl("/files/" + objectId);
return filevo;
}
public List<GridFSFile> list() {
return gridFsTemplate.find(new Query()).into(new ArrayList<>());
}
public void removeById(String fileId) {
gridFsTemplate.delete(Query.query(Criteria.where("_id").is(fileId)));
}
public GridFSFile getById(String fileId) {
return gridFsTemplate.findOne(new Query(Criteria.where("_id").is(fileId)));
}
public InputStream getStream(GridFSFile file) throws IOException {
GridFsResource resource = gridFsTemplate.getResource(file);
return resource.getInputStream();
}
}
代码解读:
这段代码是一个用于处理MongoDB GridFS文件存储的服务类。下面是对这段代码的详细解读:
-
导入依赖:
导入了所需的依赖包,包括MongoDB的相关类、Spring Boot的相关类以及Lombok库。 -
服务类定义:
使用@Service
注解标记该类为一个服务类,表示该类提供业务逻辑功能。同时使用@AllArgsConstructor
注解来自动生成一个包含所有成员变量的构造函数。 -
成员变量:
private final GridFsTemplate gridFsTemplate;
:这是一个GridFsTemplate对象,用于操作MongoDB的GridFS存储。 -
saveFile方法:
该方法用于将上传的文件保存到MongoDB的GridFS中。首先创建一个FileVO对象,设置文件的基本信息(如文件名、文件大小、文件类型等)。然后获取文件的输入流,并创建一个DBObject对象用于存储文件的元数据。接着调用gridFsTemplate.store()
方法将文件存储到MongoDB中,并返回一个ObjectId对象。最后设置FileVO对象的ID、上传时间和URL,并返回该对象。 -
list方法:
该方法用于列出GridFS中的所有文件。通过调用gridFsTemplate.find()
方法并传入一个空的Query对象来获取所有的GridFSFile对象,并将其转换为ArrayList返回。 -
removeById方法:
该方法用于根据文件ID删除GridFS中的文件。通过调用gridFsTemplate.delete()
方法并传入一个包含文件ID的Criteria对象来实现。 -
getById方法:
该方法用于根据文件ID获取GridFS中的文件。通过调用gridFsTemplate.findOne()
方法并传入一个包含文件ID的Criteria对象来实现。 -
getStream方法:
该方法用于获取GridFS中文件的输入流。首先通过调用gridFsTemplate.getResource()
方法获取一个GridFsResource对象,然后调用该对象的getInputStream()
方法获取文件的输入流。
创建MongoDB GridFS API接口类
代码如下:
import com.mongodb.client.gridfs.model.GridFSFile;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.springblade.coalface.modules.file.service.MongoFileService;
import org.springblade.coalface.modules.file.vo.FileVO;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.IoUtil;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
@Slf4j
@RestController
@RequestMapping("/")
@AllArgsConstructor
public class MongoFileController {
private final MongoFileService mongoFileService;
@PostMapping("file/upload")
@ApiOperation(value = "文件上传")
public R<FileVO> uploadFile(MultipartFile file) {
try {
return R.data(mongoFileService.saveFile(file));
} catch (Exception e) {
return R.fail(e.getMessage());
}
}
@PostMapping("download")
@ApiOperation(value = "文件仅下载")
public void downloadFile(String fileId, HttpServletResponse response) {
try {
GridFSFile file = mongoFileService.getById(fileId);
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
String encodedFileName = URLEncoder.encode(file.getFilename(), "UTF-8").replace("+", "%20");
response.setHeader(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename*=UTF-8''" + encodedFileName);
IoUtil.copy(mongoFileService.getStream(file), response.getOutputStream());
} catch (Exception e) {
log.error(e.getMessage());
}
}
@GetMapping("files/{fileId}")
@ApiOperation(value = "文件预览下载")
public void getFile(@PathVariable("fileId") String fileId, HttpServletResponse response) {
try {
GridFSFile file = mongoFileService.getById(fileId);
Document doc=file.getMetadata();
// 获取文件的MIME类型
assert doc != null;
String mimeType = doc.getString("_contentType");
response.setContentType(mimeType);
String encodedFileName = URLEncoder.encode(file.getFilename(), "UTF-8").replace("+", "%20");
response.setHeader(HttpHeaders.CONTENT_DISPOSITION,
"inline; filename*=UTF-8''" + encodedFileName);
IoUtil.copy(mongoFileService.getStream(file), response.getOutputStream());
} catch (Exception e) {
log.error(e.getMessage());
}
}
@PostMapping("remove/{fileId}")
@ApiOperation(value = "文件删除")
public R<String> removeFile(@PathVariable("fileId") String fileId) {
mongoFileService.removeById(fileId);
return R.success();
}
}
- 该类中总共封装了三个接口,上传接口、仅下载接口、和文件预览接口
- 文件预览接口能将浏览器可以显示文件,显示在浏览器上,不直接下载,例如图片、视频、pdf文件等可以直接在浏览器预览、其他不能再浏览器上显示的文件、如zip压缩包、exe安装程序、word/excel文件等则直接下载。