一、GridFS概述
'GridFS是MongoDB提供的用于持久化存储文件的模块'
`工作原理:`
a、GridFS存储文件是将文件分块存储,文件会按照256KB的大小分割成多个块进行存储,
b、GridFS使用两个集合(collection)存储文件,一个集合是chunks, 用于存储文件的二进制数据;
一个集合是files,用于存储文件的元数据信息(文件名称、块大小、上传时间等信息)。
`特点:`
a、用于存储和恢复超过16M(BSON文件限制)的文件(如:图片、音频、视频等)
b、是文件存储的一种方式,但它是存储在MonoDB的集合中
c、可以更好的存储大于16M的文件
d、会将大文件对象分割成多个小的chunk(文件片段),一般为256k/个,每个chunk将作为MongoDB的一个文档(document)被存储在chunks集合中
e、用两个集合来存储一个文件:fs.files与fs.chunks
f、每个文件的实际内容被存在chunks(二进制数据)中,和文件有关的meta数据(filename,content_type,还有用户自定义的属性)将会被存在files集合中。
详细参考:官网文档
二、添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
三、配置文件
spring:
data:
mongodb:
uri: mongodb://admin:123456@127.0.0.1:27017/database
四、gridFSBucket配置
@Configuration
@Slf4j
public class CommonConfig {
@Bean
public GridFSBucket getGridFSBucket(MongoClient mongoClient){
MongoDatabase mongoDatabase = mongoClient.getDatabase("database");
return GridFSBuckets.create(mongoDatabase);
}
}
五、代码示例
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSDownloadStream;
import com.mongodb.client.gridfs.model.GridFSFile;
import org.bson.Document;
import org.bson.types.ObjectId;
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 java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.Charset;
@RestController
@RequestMapping("/test")
@Slf4j
@RefreshScope
@RequiredArgsConstructor
public class AlgorithmController {
private final MongoTemplate mongoTemplate;
private final MinIoUtils minIoUtils;
private final GridFsTemplate gridFsTemplate;
private final GridFSBucket gridFSBucket;
/**
* GridFS查询操作
*/
@PostMapping("/find")
public R find(String id) throws IOException {
// 1、根据文件id查询文件
GridFSFile gridFSFile = gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(id)));
// 2、打开一个下载流对象
GridFSDownloadStream gridFSDownloadStream = gridFSBucket.openDownloadStream(gridFSFile.getObjectId());
// 3、创建GridFsResource对象,获取流
GridFsResource gridFsResource = new GridFsResource(gridFSFile, gridFSDownloadStream);
String s = IOUtils.toString(gridFsResource.getInputStream(), Charset.defaultCharset());
// 4、解压缩
String gzipDecompress = CompressUtil.gzipDecompressString(s);
System.out.println(gzipDecompress);
return R.success();
}
/**
* GridFS保存操作
*/
@PostMapping("/save")
public R save() throws IOException {
// 1、加载本地测试文件
FileReader fileReader = new FileReader("measure.json");
// 2、文件流转字节数据
byte[] bd = CompressUtil.gzipCompressBytes(fileReader.getInputStream().readAllBytes());
// 3、设置base64编码
String encodeStr = Base64.encodeBase64String(bd);
Document document = new Document();
document.append("contentType","application/json").append("name","test").append("customId","1");
// 4、使用gridfs保存
ObjectId objectId = gridFsTemplate.store(new ByteArrayInputStream(encodeStr.getBytes()), "test.json", document);
// ObjectId objectId = gridFsTemplate.store(fileReader.getInputStream(), "test.json", document);
// 5、输出保存后的_id 用于调试查询
System.out.println(objectId);
}
/**
* GridFS删除操作
*/
@PostMapping("/del")
public R del(String id) throws IOException {
// 1、根据文件id删除fs.files和fs.chunks中的记录
gridFsTemplate.delete(Query.query(Criteria.where("_id").is(id)));
return R.success();
}
}
六、总结及最终方案
`优点:`
集成mongodb内部,业务方面无需引入存储平台等。
`缺点:`
性能相比对象存储较差,小文件快太多维护起来不方便,而且修改文档时候需要先删除再重新保存。
`最终业务方案:`
由于整个大的json文件大于16M,项目中也使用到对象存储,但是为了和之前业务存储逻辑保持统一性,本次将业务中涉及到输出的大json中部分较大的json信息数据进行压缩存储,这样就保证存储的整个json结构小于16M(业务中原25M json数据部分数据压缩后控制整体到1M左右)。取这部分数据时进行解压缩处理相关逻辑。
参考文章:
http://t.zoukankan.com/huangzejun-p-8779734.html
https://www.jb51.net/article/256752.htm
https://blog.youkuaiyun.com/qq_38628046/article/details/110846272
https://blog.youkuaiyun.com/mijichui2153/article/details/118977823
https://blog.youkuaiyun.com/qq_20783497/article/details/110930342
https://www.cnblogs.com/mengrennwpu/p/8849551.html