Java 如何将文件上传集成到SpringDataREST存储库中?
我想将文件上传和下载集成到SpringDataREST存储库中Java 如何将文件上传集成到SpringDataREST存储库中?,java,spring,http,file-upload,spring-data-rest,Java,Spring,Http,File Upload,Spring Data Rest,我想将文件上传和下载集成到SpringDataREST存储库中 @BasePathAwareController @ExposesResourceFor(Tutor.class) public class TutorRepositoryController { private AttachmentAssembler attachmentAssembler; private AttachmentRepository attachmentRepository; priva
@BasePathAwareController
@ExposesResourceFor(Tutor.class)
public class TutorRepositoryController {
private AttachmentAssembler attachmentAssembler;
private AttachmentRepository attachmentRepository;
private TutorRepository tutorRepository;
private RepositoryEntityLinks entityLinks;
@Autowired
public TutorRepositoryController(AttachmentAssembler attachmentAssembler,
AttachmentRepository attachmentRepository,
TutorRepository tutorRepository,
RepositoryEntityLinks entityLinks) {
this.attachmentAssembler = attachmentAssembler;
this.attachmentRepository = attachmentRepository;
this.tutorRepository = tutorRepository;
this.entityLinks = entityLinks;
}
@PostMapping(value = "/tutors/{id}/attachments/{name}")
public ResponseEntity<EntityModel<Attachment>> saveAttachment(@RequestParam("data") MultipartFile file,
@PathVariable long id,
@PathVariable String name) {
Tutor thisTutor = tutorRepository.findById(id);
File tempFile;
try {
tempFile = File.createTempFile(FilenameUtils.getBaseName(file.getOriginalFilename()),
FilenameUtils.getExtension(file.getOriginalFilename()));
StreamUtils.copy(file.getResource().getInputStream(), new FileOutputStream(tempFile));
} catch (IOException e) {
throw new RuntimeException("Could not create temporary file of uploaded file.");
}
Attachment saved =
attachmentRepository.save(new Attachment(name, thisTutor, tempFile, file.getOriginalFilename()));
return ResponseEntity.created(entityLinks.linkForItemResource(Attachment.class, saved.getIdentifier())
.toUri()).body(attachmentAssembler.toModel(saved));
}
}
我有一个DataFile
类(参见下面的实现),它总是伴随着一些元数据。有一个DataFileRepository
来存储元数据和文件之间关系的信息
用户应该能够上传web应用程序表单中的文件以及元数据。元数据应该存储在数据库表中,而文件被上传到某个文件存储中时,文件的路径将再次存储在实体中
我想使用SpringDataREST来实现这一点。我的方法是在数据文件
实体中包含一个多部分文件
,并将其标记为@Transient
和@RestResource(exported=false)
,因此它不在实体的任何表示形式中,但可以上载。
上载时,AbstractRepositoryEventListener
会覆盖onBeforeCreate
,并在此步骤中上载文件
但使用这种方法,我很难将该文件包含在HTTP请求主体中(数据文件的JSON表示形式)
其他方法包括实现@RestRepositoryController
来扩充DataFileRepository
,但前面提到的方法是我最喜欢的
使用SpringDataREST(存储库)上传文件的最佳实践是什么
我没有找到只使用SpringDataREST来实现这一点的方法,但是这个解决方案很好地集成到了存储库中,并且不需要太多的手写代码 下面是一个不同于问题的解决方案的示例,但您应该了解这个想法 基本上创建一个
@BasePathAwareController
,这样它就可以适应您可能为Spring数据REST设置的基本路径。然后使用适当的路径在控制器内创建映射。在本例中,存在一个@PostMapping
,其中包含指向导师
存储库的路径以及上载到此处的相关附件的子路径
您可以使用此方法进行验证,也可以在存储库的save方法中引入一个方面
@BasePathAwareController
@ExposesResourceFor(Tutor.class)
public class TutorRepositoryController {
private AttachmentAssembler attachmentAssembler;
private AttachmentRepository attachmentRepository;
private TutorRepository tutorRepository;
private RepositoryEntityLinks entityLinks;
@Autowired
public TutorRepositoryController(AttachmentAssembler attachmentAssembler,
AttachmentRepository attachmentRepository,
TutorRepository tutorRepository,
RepositoryEntityLinks entityLinks) {
this.attachmentAssembler = attachmentAssembler;
this.attachmentRepository = attachmentRepository;
this.tutorRepository = tutorRepository;
this.entityLinks = entityLinks;
}
@PostMapping(value = "/tutors/{id}/attachments/{name}")
public ResponseEntity<EntityModel<Attachment>> saveAttachment(@RequestParam("data") MultipartFile file,
@PathVariable long id,
@PathVariable String name) {
Tutor thisTutor = tutorRepository.findById(id);
File tempFile;
try {
tempFile = File.createTempFile(FilenameUtils.getBaseName(file.getOriginalFilename()),
FilenameUtils.getExtension(file.getOriginalFilename()));
StreamUtils.copy(file.getResource().getInputStream(), new FileOutputStream(tempFile));
} catch (IOException e) {
throw new RuntimeException("Could not create temporary file of uploaded file.");
}
Attachment saved =
attachmentRepository.save(new Attachment(name, thisTutor, tempFile, file.getOriginalFilename()));
return ResponseEntity.created(entityLinks.linkForItemResource(Attachment.class, saved.getIdentifier())
.toUri()).body(attachmentAssembler.toModel(saved));
}
}
在本例中,我使用了一个方面将处理应用于存储库的save()
方法的每个调用
@BasePathAwareController
@ExposesResourceFor(Tutor.class)
public class TutorRepositoryController {
private AttachmentAssembler attachmentAssembler;
private AttachmentRepository attachmentRepository;
private TutorRepository tutorRepository;
private RepositoryEntityLinks entityLinks;
@Autowired
public TutorRepositoryController(AttachmentAssembler attachmentAssembler,
AttachmentRepository attachmentRepository,
TutorRepository tutorRepository,
RepositoryEntityLinks entityLinks) {
this.attachmentAssembler = attachmentAssembler;
this.attachmentRepository = attachmentRepository;
this.tutorRepository = tutorRepository;
this.entityLinks = entityLinks;
}
@PostMapping(value = "/tutors/{id}/attachments/{name}")
public ResponseEntity<EntityModel<Attachment>> saveAttachment(@RequestParam("data") MultipartFile file,
@PathVariable long id,
@PathVariable String name) {
Tutor thisTutor = tutorRepository.findById(id);
File tempFile;
try {
tempFile = File.createTempFile(FilenameUtils.getBaseName(file.getOriginalFilename()),
FilenameUtils.getExtension(file.getOriginalFilename()));
StreamUtils.copy(file.getResource().getInputStream(), new FileOutputStream(tempFile));
} catch (IOException e) {
throw new RuntimeException("Could not create temporary file of uploaded file.");
}
Attachment saved =
attachmentRepository.save(new Attachment(name, thisTutor, tempFile, file.getOriginalFilename()));
return ResponseEntity.created(entityLinks.linkForItemResource(Attachment.class, saved.getIdentifier())
.toUri()).body(attachmentAssembler.toModel(saved));
}
}
我有完全相同的问题,你找到解决方案了吗?不是一个纯粹使用SpringDataREST的解决方案,而是结合aspects的解决方案,它工作得很好,是一个与REST很好集成的解决方案。我会添加一个答案,也许其他人会给出一个更好的答案。我只是针对一个类似的问题问了一个新问题,如果你能在这里或那里添加答案(任何一个),那就太好了!!请参阅下面的我的实现。在您的回答中,文件被放入附件,然后存储库保存它。它到底去了哪里?SDR能处理吗?它是否像附件的其他属性一样写入数据库?文件将传递给附件对象。然后将其上载到方面中的服务。如果您愿意,也可以在控制器中执行此操作。我选择在任何附件创建之前在相位中这样做。您希望我将此添加到答案中吗?是的,这将非常有用,谢谢,因为我不知道如何保留已保存文件与实体本身的关系。您是否从服务中获得某种文件句柄,然后将该句柄保存在附件实体中?添加了我的方面代码。基本上是这样的:用户单击upload,然后调用
BasePathAwareController
的@PostMapping
,然后将多部分文件
存储到磁盘上的临时文件中-将文件
添加到附件
对象中。然后调用repository save函数。此方法已通过aspect进行了扩展,aspect获取此临时文件,将其上载到AWS S3服务,并将S3 bucket中的路径保存到附件
对象。在aspect之后,调用正常的存储库代码(保存到数据库等)。