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 字段可能有用。其余字段有点静态。

您应该能够简单地使用您自定义的MyGridFsFileRepoupdate 方法。我建议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.filesfs.chunksfs.files 存储 idfilenamemd5 等内容,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 方法)。以及它如何以正确的顺序流式传输块以生成InputStreamgetInputStream 方法)。那里发生的事情相当低级;)【参考方案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 data查询mongodb的问题,求解答

使用Spring访问Mongodb的方法大全——Spring Data MongoDB

如何在 spring-boot 中禁用 spring-data-mongodb 自动配置

将 Spring 安全 ACL 与 spring-data-mongodb 一起使用

spring data mongodb Query 及分页