MongoDB GridFS
是一个用于存储和检索大型文件的规范,它允许在MongoDB
数据库中存储超过16MB的文件,如图片、音频、视频等。GridFS通过将文件分割成多个小的chunk(文件片段),每个chunk通常为255KB,并将这些chunk存储在MongoDB的集合中,从而解决了MongoDB对单个文档大小的限制。以下是GridFS
的详细介绍:
fs.files
和fs.chunks
。fs.files
集合存储文件的元数据,如文件名、文件类型、上传时间等;fs.chunks
集合存储文件的二进制数据块。MongoDB
数据库中可能比在系统级文件系统上更有效率。在pom.xml文件中添加mongo依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-mongodbartifactId>
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
代码如下:
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()
方法获取文件的输入流。
代码如下:
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();
}
}