受到本教程的启发,我终于找到了一个解决方案:
https://www.vinsguru.com/spring-webflux-file-upload/
在我的控制器中:
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Mono<AudioDto>> saveAudioTrack(@RequestPart("file") Mono<FilePart> filePartMono) {
return new ResponseEntity<>(this.audioService.saveAudioTrack(filePartMono), HttpStatus.CREATED);
}
在我的服务层:
@Override
public Mono<AudioDto> saveAudioTrack(Mono<FilePart> filePartMono) {
Path basePath = Paths.get("./src/main/resources/upload/");
return filePartMono
.doOnNext(fp -> System.out.println("Received File : " + fp.filename()))
.flatMap(fp -> fp.transferTo(basePath.resolve(fp.filename())))
.then(
filePartMono
.flatMap(fp -> Mono.just(new File(String.valueOf(basePath.resolve(fp.filename())))))
.map(file -> {
try {
return getAudioMetadata(file);
} catch (InvalidDataException | UnsupportedTagException | IOException e) {
e.printStackTrace();
throw new RuntimeException(e.getLocalizedMessage());
}
})
);
}
我还设法获取元数据并将文件上传到S3 bucket:
我调用我的方法来创建元数据
private AudioDto getAudioMetadata(File file) throws InvalidDataException, UnsupportedTagException, IOException {
Mp3File mp3file = new Mp3File(file.getPath());
AudioDto audioDto = new AudioDto();
...
if (mp3file.hasId3v1Tag()) {
ID3v1 id3v1Tag = mp3file.getId3v1Tag();
audioDto.setTrack(id3v1Tag.getTrack());
...
}
if (mp3file.hasId3v2Tag()) {
ID3v2 id3v2Tag = mp3file.getId3v2Tag();
audioDto.setTrack(id3v2Tag.getTrack());
...
audioDto.setAlbumImage(id3v2Tag.getAlbumImage());
byte[] albumImageData = id3v2Tag.getAlbumImage();
if (albumImageData != null) {
audioDto.setAlbumImageSize(albumImageData.length);
audioDto.setAlbumImageMimeType(id3v2Tag.getAlbumImageMimeType());
}
}
//get file metadata
Map<String, String> metadata = new HashMap<>();
Tika tika = new Tika();
metadata.put("Content-Type", tika.detect(file));
metadata.put("Content-Length", String.valueOf(file.length()));
String path = String.format("%s/%s", environment.getProperty("amazon.aws.s3.audioBucket"), UUID.randomUUID());
//String fileName = String.format("%s", audioDto.getFile().getOriginalFilename());
try {
InputStream inputSteam = new FileInputStream(file);
fileStore.upload(path, file.getName(), Optional.of(metadata), inputSteam);
} catch (IOException e) {
throw new IllegalStateException("Failed to upload file", e);
}
audioDto.setFileName(file.getName());
...
ModelMapper modelMapper = new ModelMapper();
modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
AudioEntity audioFileEntity = modelMapper.map(audioDto, AudioEntity.class);
AudioEntity storedEntity = audioRepository.save(audioFileEntity);
return modelMapper.map(storedEntity, AudioDto.class);
}
以下是我的上传方法:
private final AmazonS3 amazonS3;
public void upload(String path,
String fileName,
Optional<Map<String, String>> optionalMetaData,
InputStream inputStream) {
ObjectMetadata objectMetadata = new ObjectMetadata();
optionalMetaData.ifPresent(map -> {
if (!map.isEmpty()) {
map.forEach(objectMetadata::addUserMetadata);
}
});
try {
amazonS3.putObject(path, fileName, inputStream, objectMetadata);
} catch (AmazonServiceException e) {
throw new IllegalStateException("Failed to upload the file", e);
}
}
不是最优雅的方式,而是功能性的。在告知其完全可操作之前,需要进行一些训练,但没有什么需要技巧的地方。:)