How to get a binary stream by GridFS ObjectId with

2020-05-26 03:27发布

I can't figure out how to stream a binary file from GridFS with spring-data-mongodb and its GridFSTemplate when I already have the right ObjectId.

GridFSTemplate returns either GridFSResource (getResource()) or GridFSFile (findX()).

I can get the GridFSFile by ID:

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

but there is no obvious way how to get an InputStream for that GridFSFile.

Only GridFSResource allows me to get hold of the corresonding InputStream with InputStreamResource#getInputstream. But the only way to get a GridFSResource is by its filename.

// no way to get GridFSResource by ID?
GridFSResource resource = gridFsTemplate.getResource("test.jpeg");
return resource.getInputStream();

Somehow the GridFsTemplate API implies that filenames are unique - which they are not. The GridFsTemplate implementation just returns the first element.

Now I'm using the native MongoDB API and everything makes sense again:

GridFS gridFs = new GridFs(mongo);
GridFSDBFile nativeFile = gridFs.find(blobId);
return nativeFile.getInputStream();

It looks like I'm misunderstanding the fundamental concepts behind the Spring Data Mongo GridFS abstraction. I'd expect (at least) one of the following things to be possible/true:

  • get a GridFSResource by its ID
  • get a GridFSResource or InputStream for a GridFsFile I already have

Am I wrong or is there something odd with this particular piece of the Spring Data MongoDB API?

9条回答
手持菜刀,她持情操
2楼-- · 2020-05-26 04:21
@RequestMapping(value = "/api ")
public class AttachmentController {

private final GridFsOperations gridFsOperations;

@Autowired
public AttachmentController(GridFsOperations gridFsOperations) {
    this.gridFsOperations = gridFsOperations;
}

@GetMapping("/file/{fileId}")
public ResponseEntity<Resource> getFile(@PathVariable String fileId) {
GridFSFile file = 
gridFsOperations.findOne(Query.query(Criteria.where("_id").is(fileId)));

    return ResponseEntity.ok()
            .contentLength(file.getLength())
            .body(gridFsOperations.getResource(file));
}
查看更多
Animai°情兽
3楼-- · 2020-05-26 04:23

I stumbled upon this, too. And I am actually pretty shocked that the GridFsTemplate has been designed like this... Anyway, my ugly "solution" to this so far:

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);
}

Note: You have to inject the MongoDbFactory for this to work...

查看更多
等我变得足够好
4楼-- · 2020-05-26 04:26
GridFSDBFile file = ... 
ByteArrayOutputStream baos = new ByteArrayOutputStream();
file.writeTo(baos);
byte[] ba = baos.toByteArray()
查看更多
登录 后发表回答