如何使用Spring Data MongoDB通过GridFS ObjectId获取二进制流

问题描述 投票:12回答:8

当我已经拥有正确的GridFSTemplate时,我无法弄清楚如何使用spring-data-mongodb及其ObjectId从GridFS流式传输二进制文件。

GridFSTemplate返回GridFSResourcegetResource())或GridFSFilefindX())。

我可以通过ID获得GridFSFile

// no way to get the InputStream?
GridFSFile file = gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(id)))

但没有明显的方法如何为InputStream获得GridFSFile

只有qazxsw poi允许我用GridFSResource获得相应的qazxsw poi。但获得InputStream的唯一途径是它的InputStreamResource#getInputstream

GridFSResource

不知何故,filename API意味着文件名是唯一的 - 它们不是。 // no way to get GridFSResource by ID? GridFSResource resource = gridFsTemplate.getResource("test.jpeg"); return resource.getInputStream(); 实现只返回第一个元素。

现在我正在使用本机MongoDB API,一切都有意义:

GridFsTemplate

看起来我误解了Spring Data Mongo GridFS抽象背后的基本概念。我希望(至少)以下事情之一是可能的/真实的:

  • 通过其ID获取GridFsTemplate
  • 得到一个GridFS gridFs = new GridFs(mongo); GridFSDBFile nativeFile = gridFs.find(blobId); return nativeFile.getInputStream(); GridFSResource为我已经拥有的GridFSResource

我错了,或者这个特定的Spring Data MongoDB API有什么奇怪的东西?

mongodb spring-data spring-data-mongodb
8个回答
10
投票

我也偶然发现了这一点。我真的很震惊的是,GridFsTemplate的设计是这样的...无论如何,到目前为止,我的丑陋“解决方案”:

InputStream

注意:你必须注入MongoDbFactory才能工作......


5
投票

这些类型有点乱:

  • GridFsFile是来自MongoDB驱动程序的类型
  • public GridFsResource download(String fileId) { GridFSFile file = gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(fileId))); return new GridFsResource(file, getGridFs().openDownloadStream(file.getObjectId())); } private GridFSBucket getGridFs() { MongoDatabase db = mongoDbFactory.getDb(); return GridFSBuckets.create(db); } 是Spring的类型
  • GridFSFile是BSON API的类型

来自Spring GridFsTemplate GridFsResource

ObjectId

有一个丑陋的解决方案:

source

1
投票

我发现了这个问题的解决方案!

只需将GridFSFile包装在GridFsResource中!这旨在使用GridFSFile进行实例化。

public getResource(String location) {

    GridFSFile file = findOne(query(whereFilename().is(location)));
    return file != null ? new GridFsResource(file, getGridFs().openDownloadStream(location)) : null;
}

这样做的最大好处是,你可以直接将GridFsResource传递给ResponseEntity,因为GridFsResource扩展了一个InputStreamResource。

希望这可以帮助!

问候尼克拉斯


0
投票

您是否考虑过将@Autowired private GridFsTemplate template; @Autowired private GridFsOperations operations; public InputStream loadResource(ObjectId id) throws IOException { GridFSFile file = template.findOne(query(where("_id").is(id))); GridFsResource resource = template.getResource(file.getFilename()); GridFSFile file = operations.findOne(query(where("_id").is(id))); GridFsResource resource = operations.getResource(file.getFilename()); return resource.getInputStream(); } 用于Mongo作为解决方案中的内容存储部分?

假设您使用的是Spring Boot以及Spring Data Mongo,那么它可能如下所示:

pom.hml

public GridFsResource getUploadedFileResource(String id) {
    var file = this.gridFsTemplate.findOne(new Query(Criteria.where("_id").is(id)));
    return new GridFsResource(file);
}

@GetMapping("/{userId}/files/{id}")
public ResponseEntity<InputStreamResource> getUploadedFile(
    @PathVariable Long userId,
    @PathVariable String id
){
    var user = userService
        .getCurrentUser()
        .orElseThrow(EntityNotFoundException::new);

    var resource = userService.getUploadedFileResource(id);

    try {
        return ResponseEntity
            .ok()
            .contentType(MediaType.parseMediaType(resource.getContentType()))
            .contentLength(resource.contentLength())
            .body(resource);
    } catch (IOException e) {
        return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
    }


}

使用以下属性更新Spring Data Mongo实体:

Spring Content

添加商店界面:

<dependency>
    <groupId>com.github.paulcwarren</groupId>
    <artifactId>spring-content-mongo-boot-starter</artifactId>
    <version>0.0.10</version>
</dependency>
<dependency>
    <groupId>com.github.paulcwarren</groupId>
    <artifactId>spring-content-rest-boot-starter</artifactId>
    <version>0.0.10</version>
</dependency>

这就是你所需要的一切。当应用程序启动时,Spring Content将看到Spring Content Mongo / REST模块的依赖项,它将为GridFs注入@ContentId private String contentId; @ContentLength private long contentLength = 0L; @MimeType private String mimeType; 存储的实现,以及支持完整CRUD功能的控制器的实现,并将这些操作映射到底层商店界面。 REST端点将在@StoreRestResource(path="content") public interface MongoContentStore extends ContentStore<YourEntity, String> { } 下提供。

MongonContenStore将创建或更新实体的图像

/content将获取实体的图像

curl -X PUT /content/{entityId}将删除实体的图像

有一些入门指南curl -X GET /content/{entityId}。他们将Spring Content用于文件系统,但模块可以互换。 Mongo参考指南是curl -X DELETE /content/{entityId}。还有一个教程视频here

HTH


0
投票

将GridFSFile包装在GridFsResource中或使用它

here

0
投票

GridFsTemplate的getResource(com.mongodb.client.gridfs.model.GridFSFile文件)函数返回GridFSFile的GridFsResource。

here

如果上面的一个不能在某些更高版本的Spring启动版中工作,请使用下面的代码:

GridFSFile file = gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(fileId)));
GridFsResource resource = gridFsTemplate.getResource(file);
return resource.getInputStream();

0
投票
GridFSFile gridfsFile= gridFsTemplate.findOne(new 
Query(Criteria.where("filename").is(fileName)));
GridFsResource gridFSResource= gridFsTemplate.getResource(gridfsFile);
InputStream inputStream= gridFSResource.getInputStream();

-3
投票
GridFSFile gridfsFile= gridFsTemplate.findOne(new 
Query(Criteria.where("filename").is(fileName)));
//or
GridFSFile  gridfsFile = 
gridFsOperations.findOne(Query.query(Criteria.where("filename").is(fileName)));
 return ResponseEntity.ok()
                .contentLength(gridFsdbFile.getLength())
                .contentType(MediaType.valueOf("image/png"))
                .body(gridFsOperations.getResource(gridFsdbFile));
© www.soinside.com 2019 - 2024. All rights reserved.