web-dev-qa-db-ja.com

Spring Data MongoDBを使用してGridFS ObjectIdでバイナリストリームを取得する方法

既に正しい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)))

しかし、そのInputStreamGridFSFileを取得する明確な方法はありません。

GridFSResourceのみが、対応するInputStreamInputStreamResource#getInputstream。ただし、GridFSResourceを取得する唯一の方法は、filenameを使用することです。

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

どういうわけかGridFsTemplate AP​​Iは、ファイル名が一意であることを意味しますが、一意ではありません。 GridFsTemplate実装は、最初の要素を返すだけです。

今、私はネイティブMongoDB APIを使用していますが、すべてが再び理にかなっています。

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

Spring Data Mongo GridFSの抽象化の背後にある基本的な概念を誤解しているようです。私は、(少なくとも)次のいずれかが可能/真実であることを期待しています:

  • iDでGridFSResourceを取得します
  • GridFSResourceInputStreamまたはGridFsFileを取得する

この間違ったSpring Data MongoDB APIの特定の部分に何か変なことはありますか?

12
atamanroman

私もこれにつまずいた。そして実際、GridFsTemplateが次のように設計されていることにかなりショックを受けています...とにかく、これまでの私のmyい「解決策」:

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

注:これを機能させるには、MongoDbFactoryを挿入する必要があります...

10
Steffen Jacobs

これらのタイプには少し混乱があります。

Spring GridFsTemplateから source

public getResource(String location) {

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

い解決策があります:

@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();
}
5
deii

この問題の解決策を発見しました!

GridFSFileをGridFsResourceにラップするだけです!これは、GridFSFileでインスタンス化されるように設計されています。

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


}

これの大きな利点は、GridFsResourceがInputStreamResourceを拡張するという事実により、GridFsResourceをResponseEntityに直接渡すことができることです。

お役に立てれば!

ごあいさつニクラス

1
Niklas

私が知っている古い質問ですが、WebFluxを使用して2019年にこれをしようとして、私は次のことをしなければなりませんでした

  public Mono<GridFsResource> getImageFromDatabase(final String id) {

    return Mono.fromCallable(
        () ->
            this.gridFsTemplate.getResource(
                Objects.requireNonNull(
                        this.gridFsTemplate.findOne(new Query(Criteria.where("_id").is(id))))
                    .getFilename()));
  }

これは、コントローラーで返されるMonoを提供します。しかし、もっと良い解決策があると確信しています。

0
Chris Turner

GridFSFileをGridFsResourceにラップするか、これを使用します

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

ソリューションのコンテンツストレージピースにMongoの Spring Content を使用することを検討しましたか?

Spring BootとSpring Data Mongoを使用していると仮定すると、次のようになります。

pom.xml

<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 Data Mongoエンティティを更新します。

@ContentId
private String contentId;

@ContentLength 
private long contentLength = 0L;

@MimeType
private String mimeType;

ストアインターフェイスを追加します。

@StoreRestResource(path="content")
public interface MongoContentStore extends ContentStore<YourEntity, String> {
}

必要なのはそれだけです。アプリケーションを起動すると、Spring ContentはSpring Content Mongo/RESTモジュールへの依存関係を確認し、GridFのMongonContenStoreストアの実装と、完全なCRUD機能とマップをサポートするコントローラーの実装を挿入します。これらの操作は、基礎となるストアインターフェースに到達します。 RESTエンドポイントは/content

つまり.

curl -X PUT /content/{entityId}は、エンティティの画像を作成または更新します

curl -X GET /content/{entityId}は、エンティティの画像を取得します

curl -X DELETE /content/{entityId}は、エンティティの画像を削除します

いくつかの入門ガイドがあります こちら 。ファイルシステムにSpring Contentを使用していますが、モジュールは交換可能です。 Mongoリファレンスガイドは here です。また、チュートリアルビデオ こちら があります。

HTH

0
Paul Warren
@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));
}
0
Rohit Basu

gridFsTemplateのgetResource(com.mongodb.client.gridfs.model.GridFSFile file)関数は、GridFSFileのGridFsResourceを返します。

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

上記のいずれかがSpringブートのより高いバージョンで動作しない場合、以下を使用します。

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));
0
Rohit Basu