当我已经拥有正确的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
不知何故,GridFsTemplate
API意味着文件名是唯一的 - 它们不是。 GridFS gridFs = new GridFs(mongo);
GridFSDBFile nativeFile = gridFs.find(blobId);
return nativeFile.getInputStream();
实现只返回第一个元素。
现在我使用本机MongoDB API,一切都有意义:
GridFSResource
看起来我误解了Spring Data Mongo GridFS抽象背后的基本概念。我希望(至少)以下事情之一是可能的/真实的:
GridFSResource
InputStream
获取GridFsFile
或group_by(id)
我错了,或者Spring Data MongoDB API的这个特定部分有什么奇怪的东西吗?
答案 0 :(得分:10)
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才能工作......
答案 1 :(得分:5)
这些类型有点乱:
来自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();
}
答案 2 :(得分:1)
我找到了解决这个问题的方法!
只需将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。
希望这会有所帮助!
问候 尼古拉斯
答案 3 :(得分:0)
您是否考虑过将Spring Content用于Mongo作为解决方案中的内容存储部分?
假设您正在使用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模块的依赖项,它将为GridFs注入MongonContenStore
存储的实现,以及支持完整CRUD功能的控制器实现并映射这些操作到底层商店界面。 REST端点将在/content
下提供。
即。
curl -X PUT /content/{entityId}
将创建或更新实体的图片
curl -X GET /content/{entityId}
将获取实体的图片
curl -X DELETE /content/{entityId}
将删除实体的图片
有几个入门指南here。他们将Spring Content用于文件系统,但模块可以互换。 Mongo参考指南是here。还有一个教程视频here。
HTH
答案 4 :(得分:0)
将GridFSFile包装在GridFsResource中或使用
!something -> 0
! -> 0
something! -> 9
"something!" -> -1
"some!thing"! -> 12
!"!"! -> 0
""! -> 2
""!"" -> 2
答案 5 :(得分:0)
getResource(com.mongodb.client.gridfs.model.GridFSFile文件)函数返回GridFSFile的GridFsResource。
GridFSFile gridfsFile= gridFsTemplate.findOne(new
Query(Criteria.where("filename").is(fileName)));
GridFsResource gridFSResource= gridFsTemplate.getResource(gridfsFile);
InputStream inputStream= gridFSResource.getInputStream();
如果以上版本在某些更高版本的Spring Boot中不起作用,请使用以下波纹管:
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));
答案 6 :(得分:0)
@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));
}
答案 7 :(得分:0)
我知道一个老问题,但是尝试在2019年使用WebFlux进行此操作,我必须执行以下操作
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
,可以在控制器中将其返回。我敢肯定有更好的解决方案。
答案 8 :(得分:0)
Spring Data 2.1.0向GridFsTemplate
添加了getResource()
的重载,该重载返回给定GridFsResource
的{{1}}。 GridFsFile
有一种获取GridFsResource
的方法。因此,如果您至少使用此版本的Spring Data,则可以通过两次调用InputStream
来获得InputStream
:
GridFsTemplate
答案 9 :(得分:-3)
<section id="events-list">
<div class="event">
<div class="event-date">
<p>MAR 30</p>
</div>
<div class="event-details">
<p class="event-city">City, US</p>
<p class="event-bus">Company HQ - Company Double Line</p>
<a class="register" href="#">RSVP</a>
</div>
</div>
<div class="event">
<div class="event-date">
<p>MAR 30</p>
</div>
<div class="event-details">
<p class="event-city">City, US</p>
<p class="event-bus">Company HQ</p>
<a class="register" href="#">RSVP on 4/13</a>
</div>
</div>
<div class="event">
<div class="event-date">
<p>MAR 30</p>
</div>
<div class="event-details">
<p class="event-city">City, US</p>
<p class="event-bus">Company HQ - Company Double Line</p>
<a class="register" href="#">RSVP</a>
</div>
</div>
</section>