我想将文件上传和下载集成到Spring Data REST存储库中。
我有一个DataFile
类(请参见下面的实现),该类总是伴随着一些元数据。 DataFileRepository
用于存储有关元数据和文件之间的关系的信息。
用户应该能够以网络应用程序的形式与元数据一起上传文件。当文件上传到文件存储时,元数据应存储在数据库表中,然后将文件路径再次存储在实体中。
我想使用Spring Data REST做到这一点。我的方法是在MultipartFile
实体中包含DataFile
并将其标记为@Transient
和@RestResource(exported = false)
,这样它就没有实体的任何表示形式,但可以上载。当上传时,AbstractRepositoryEventListener
会覆盖onBeforeCreate
并在此步骤中上传文件。
但是用这种方法,我努力将文件包含在HTTP请求正文中(DataFile
的JSON表示。
[其他方法将包括实现@RestRepositoryController
以增强DataFileRepository
,但前面提到的方法将是我的最爱。
使用Spring Data REST(存储库)上传文件的最佳实践是什么?
@Data
@Entity
@Table(name = "data_files")
public class DataFile {
@Id
@GeneratedValue
@Setter(AccessLevel.NONE)
private long identifier;
@NotBlank
@Column(name = "path")
@RestResource(exported = false)
private String path;
@Embedded
private Metadata metadata;
public DataFile() {
metadata = new Metadata();
}
public DataFile(Metadata metadata) {
this.metadata = metadata;
}
}
我没有找到一种仅通过使用Spring Data REST来做到这一点的方法,但是该解决方案很好地集成到了存储库中,并且不需要太多的手写代码。
以下是针对与问题不同的项目的此类解决方案的示例,但您应该明白这一点。
基本上创建一个@BasePathAwareController
,使其适应您可能已为Spring Data REST设置的基本路径。然后使用适当的路径在控制器内部创建映射。在这种情况下,存在一个@PostMapping
,其中包含tutors
存储库的路径,以及相关附件的子路径,该子路径在此处上传。
您可以使用此方法进行验证,也可以介绍存储库的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));
}
}