Spring Data + MongoDB GridFS 可以通过 Repository 访问吗?
Posted
技术标签:
【中文标题】Spring Data + MongoDB GridFS 可以通过 Repository 访问吗?【英文标题】:Spring Data + MongoDB GridFS access via Repository possible? 【发布时间】:2013-10-03 07:57:23 【问题描述】:我最近发现了 GridFS,我想用它来存储带有元数据的文件。我只是想知道是否可以使用MongoRepository
来查询 GridFS?如果是,有人可以举个例子吗?
如果有的话,我也会采用 Hibernate 的解决方案。
原因是:我的元数据包含许多不同的字段,查询存储库要比为每个场景编写一些 new Query(Criteria.where(...))
容易得多。我希望也可以简单地获取一个 Java 对象并通过 REST API 提供它,而不需要文件本身。
编辑:我正在使用
春季 4 测试版 Spring Data Mongo 1.3.1 休眠 4.3 测试版【问题讨论】:
你找到解决这个问题的方法了吗?我有同样的问题。 嗨。我用我目前的“解决方案”在下面添加了一个答案 【参考方案1】:有办法解决这个问题:
@Document(collection="fs.files")
public class MyGridFsFile
@Id
private ObjectId id;
public ObjectId getId() return id;
private String filename;
public String getFilename() return filename;
private long length;
public long getLength() return length;
...
您可以为此编写一个普通的 Spring Mongo Repo。现在您至少可以使用 Spring Data Repo 查询 fs.files
集合。 但是:您无法通过这种方式访问文件内容。
要获取文件内容本身,您有(至少)2 个选项:
使用file = gridOperations.findOne(Query.query(Criteria.where("_id").is(id)));
InputStream is = file.getInputStream();
看看GridFSDBFile
的源码。在那里你可以看到它如何在内部查询fs.chunks
集合并填充 InputStream。
(选项 2 非常低级,选项 1 更容易,并且此代码由 MongoDB-Java-Driver 开发人员维护,尽管选项 1 是我的选择)。
更新 GridFS 条目:
GridFS 并非旨在更新文件内容! 尽管只更新metadata
字段可能有用。其余字段有点静态。
您应该能够简单地使用您自定义的MyGridFsFileRepo
的update
方法。我建议只为metadata
字段创建一个setter。
不同文件的不同元数据:
我使用带有通用元数据的abstract MyGridFsFile
类解决了这个问题,即:
@Document(collection="fs.files")
public abstract class AbstractMyGridFsFile<M extends AbstractMetadata>
...
private M metadata;
public M getMetadata() return metadata;
void setMetadata(M metadata) this.metadata = metadata;
当然,每个 impl 都有自己的 AbstractMetadata
impl 关联。我做了什么? AbstractMetadata
始终有一个名为 type
的字段。这样我就可以找到正确的AbstractMyGridFsFile
impl。虽然我也有一个通用的抽象存储库。
顺便说一句:与此同时,我从使用 Spring Repo 切换到通过 MongoTemplate
使用普通访问,例如:
protected List<A> findAll(Collection<ObjectId> ids)
List<A> files = mongoTemplate.find(Query.query(Criteria
.where("_id").in(ids)
.and("metadata.type").is(type) // this is hardcoded for each repo impl
), typeClass); // this is the corresponding impl of AbstractMyGridFsFile
return files;
希望这会有所帮助。如果您需要有关此的更多信息,我可以写更多。告诉我吧。
【讨论】:
我的存储库有一个自定义方法,它使用gridFsOperations.save(...)
来保存新文件。 InputStream 本身不是MyGridFsFile
的一部分,我通过myRepo.getInputStreamForFile(MyGridFsFile file)
检索它。然后此方法调用gridFsOperations.findOne(/* via file.getId() */).getInputStream()
。 ... 当然,您可以将 InputStream 检索机制注入您的 MyGridFsFile
,但是您会在此 POJO 中包含一些代码逻辑,这不太好,但它会起作用。
我仍然没有得到的是file.getId()
将如何匹配fs.files
中的文件ID?您是否将 MyGridFSFile
对象存储在普通的 Mongo 文档和 GridFS 中的文件中?如果是,那么它们是如何联系起来的?
第 1 部分: 好的,让我们从头开始! GridFS 基本上只是两个 MongoDB 集合:fs.files
和 fs.chunks
。 fs.files
存储 id
、filename
、md5
等内容,fs.chunks
存储文件内容。因此,当您使用 GridFS 存储文件时,它只会在 fs.files
中创建一个条目,并(取决于文件大小)在 fs.chunks
中创建一些条目。 GridFS 不是单独的数据存储,它只是那两个标准的 Mongo 集合。虽然使用gridFsTemplate
保存文件然后在fs.files
上进行正常查询是没有问题的。
第 2 部分: 示例:使用 gridFsOperations.store(inputStream, filename, contentType, metadata);
保存图像。然后查询fs.files
喜欢:mongoTemplate.find(new Query(), MyGridFsFile.class)
。它将返回存储在 GridFS 中的所有文件的列表(它查看 MyGridFsFile
的 @Document
注释以找到要查询的正确集合)。现在您可以在返回的MyGridFsFile
上调用getId()
。然后你可以通过GridFSDBFile file = gridFsOperations.findOne(Query.query(Criteria.where("_id").is(id)))
调用file.getInputStream()
来检索实际的文件内容。
第 3 部分: Mongo Java 驱动程序:查看com.mongodb.gridfs.GridFS
类的源代码。在那里你可以看到文件是如何被持久化的。它使用_bucketName+".files"
和_bucketName+".chunks"
,其中_bucketName
默认等于fs
。如果您查看com.mongodb.gridfs.GridFSDBFile
源代码,您可以看到它是如何将文件拆分成块并保存它们的(writeTo
方法)。以及它如何以正确的顺序流式传输块以生成InputStream
(getInputStream
方法)。那里发生的事情相当低级;)
【参考方案2】:
您可以使用 MongoTemplate 中的数据库创建一个 GridFS 对象,然后与之交互:
MongoTemplate mongoTemplate = new MongoTemplate(new Mongo(), "GetTheTemplateFromSomewhere");
GridFS gridFS = new GridFS(mongoTemplate.getDb());
GridFS 对象允许您创建、删除和查找等。
【讨论】:
以上是关于Spring Data + MongoDB GridFS 可以通过 Repository 访问吗?的主要内容,如果未能解决你的问题,请参考以下文章
Spring -Data MongoDB问题与作为接口的字段
使用Spring访问Mongodb的方法大全——Spring Data MongoDB
如何在 spring-boot 中禁用 spring-data-mongodb 自动配置