既に正しいGridFSTemplate
を持っているのに、spring-data-mongodbとそのObjectId
を使用してGridFSからバイナリファイルをストリーミングする方法がわかりません。
GridFSTemplateは、GridFSResource
(getResource()
)またはGridFSFile
(findX()
)のいずれかを返します。
IDでGridFSFile
を取得できます。
// no way to get the InputStream?
GridFSFile file = gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(id)))
しかし、そのInputStream
のGridFSFile
を取得する明確な方法はありません。
GridFSResource
のみが、対応するInputStream
をInputStreamResource#getInputstream
。ただし、GridFSResource
を取得する唯一の方法は、filename
を使用することです。
// no way to get GridFSResource by ID?
GridFSResource resource = gridFsTemplate.getResource("test.jpeg");
return resource.getInputStream();
どういうわけかGridFsTemplate
APIは、ファイル名が一意であることを意味しますが、一意ではありません。 GridFsTemplate
実装は、最初の要素を返すだけです。
今、私はネイティブMongoDB APIを使用していますが、すべてが再び理にかなっています。
GridFS gridFs = new GridFs(mongo);
GridFSDBFile nativeFile = gridFs.find(blobId);
return nativeFile.getInputStream();
Spring Data Mongo GridFSの抽象化の背後にある基本的な概念を誤解しているようです。私は、(少なくとも)次のいずれかが可能/真実であることを期待しています:
GridFSResource
を取得しますGridFSResource
のInputStream
またはGridFsFile
を取得するこの間違ったSpring Data MongoDB APIの特定の部分に何か変なことはありますか?
私もこれにつまずいた。そして実際、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を挿入する必要があります...
これらのタイプには少し混乱があります。
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();
}
この問題の解決策を発見しました!
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に直接渡すことができることです。
お役に立てれば!
ごあいさつニクラス
私が知っている古い質問ですが、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
を提供します。しかし、もっと良い解決策があると確信しています。
GridFSFileをGridFsResourceにラップするか、これを使用します
GridFSFile file = gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(fileId)));
GridFsResource resource = gridFsTemplate.getResource(file);
return resource.getInputStream();
ソリューションのコンテンツストレージピースに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
@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));
}
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));