如何在 Spring Webflux 中获取 FilePart 的大小
How to get the size of FilePart in Spring Webflux
无法弄清楚如何在 REST 端点中使用 FilePart 获取文件的实际大小:
@RestController
public class SomeController {
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Mono<Long> fileSize(Mono<FilePart> filePart) {
//How to get size of FilePart?
// I'm not plan to create a File saving content of FilePart.
// Maybe it's possible somehow calculate size of all bytes.
return Mono.empty();
}
}
更新
以下是我进行文件大小和图像分辨率验证的方式。
控制器:
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@ResponseStatus(HttpStatus.CREATED)
public Mono<Void> upload(Mono<FilePart> file) {
return file.flatMap(filepart -> fileService.upload(filepart));
}
服务层的验证方法:
private Mono<byte[]> validateFileSize(FilePart filePart) {
var maxSize = 1024;
return FilePartUtils.getByteArray(filePart)
.filter(bytes -> bytes.length <= maxSize)
.switchIfEmpty(Mono.error(() -> new InvalidStateException(MAX_FILE_SIZE_REACHED, Map.of("size", maxSize))));
}
private Mono<Resolution> validateResolution(byte[] fileBytes) {
// Use image.getWidth and image.getHeight to check resolution against you expectations
return convertToImage(fileBytes).map(image -> validateResolution(image));
}
public Mono<BufferedImage> convertToImage(byte[] byteArray) {
try {
// but ImageIO.read is blocking method
return Mono.just(ImageIO.read(new ByteArrayInputStream(byteArray)));
} catch (IOException e) {
return Mono.error(new InvalidStateException(UPLOAD_FILE_ABORTED, Map.of()));
}
}
我也不知道如何在不先将文件保存到文件或将其缩小为 InputStream 或类似的东西的情况下获取文件大小。
我最后做的是向请求添加自定义 header。然后,您可以在控制器中读取 header:
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Mono<Long> fileSize(Mono<FilePart> filePart, @RequestHeader("File-Size") Long fileSize) {
如果您将新参数的类型更改为 Map<String, String>
、MultiValueMap<String, String>
或 HttpHeaders
,您将获得所有 header,而不仅仅是您的自定义参数.
如果你不能改变客户端的请求headers,并且你不需要文件大小绝对精确,你可以使用默认的header Content-Length
, 已经发送了,但是会少几个字节。
当您将文件作为多部分表单数据上传时,会自动创建一个名为“Content-Length”的请求header,该请求是在发送请求时计算的.
但是请注意,多部分 content-length 略大于文件大小 由于创建了一些元数据,例如文件名、边界和所有内容。而且 没有办法 您可以估计此元数据的长度。解释是 here.
这样就可以得到尺寸(略微增大):
@RestController
public class SomeController {
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Mono<Long> fileSize(Mono<FilePart> filePart, @RequestHeader("Content-Length") long contentLength) {
System.out.println("Content length is:" + contentLength + "bytes");
return Mono.empty();
}
}
您可以使用 filePart.content()
访问文件部分中的 Flux<DataBuffer>
。使用这个。
filePart.content() // for one file, is a Flux with one element
.map(dataBuffer -> {
byte[] bytes = new byte[dataBuffer.readableByteCount()]; // <---- here you count the bytes you have.
dataBuffer.read(bytes);
DataBufferUtils.release(dataBuffer);
String content = new String(bytes, StandardCharsets.UTF_8);
if (log.isTraceEnabled()) log.trace("File name: {}, content: {}", filePart.filename(),
content.length() > CONTENT_LENGTH_LIMIT ? content.substring(0, CONTENT_LENGTH_LIMIT) + "..." : content);
return content;
})
无法弄清楚如何在 REST 端点中使用 FilePart 获取文件的实际大小:
@RestController
public class SomeController {
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Mono<Long> fileSize(Mono<FilePart> filePart) {
//How to get size of FilePart?
// I'm not plan to create a File saving content of FilePart.
// Maybe it's possible somehow calculate size of all bytes.
return Mono.empty();
}
}
更新 以下是我进行文件大小和图像分辨率验证的方式。
控制器:
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@ResponseStatus(HttpStatus.CREATED)
public Mono<Void> upload(Mono<FilePart> file) {
return file.flatMap(filepart -> fileService.upload(filepart));
}
服务层的验证方法:
private Mono<byte[]> validateFileSize(FilePart filePart) {
var maxSize = 1024;
return FilePartUtils.getByteArray(filePart)
.filter(bytes -> bytes.length <= maxSize)
.switchIfEmpty(Mono.error(() -> new InvalidStateException(MAX_FILE_SIZE_REACHED, Map.of("size", maxSize))));
}
private Mono<Resolution> validateResolution(byte[] fileBytes) {
// Use image.getWidth and image.getHeight to check resolution against you expectations
return convertToImage(fileBytes).map(image -> validateResolution(image));
}
public Mono<BufferedImage> convertToImage(byte[] byteArray) {
try {
// but ImageIO.read is blocking method
return Mono.just(ImageIO.read(new ByteArrayInputStream(byteArray)));
} catch (IOException e) {
return Mono.error(new InvalidStateException(UPLOAD_FILE_ABORTED, Map.of()));
}
}
我也不知道如何在不先将文件保存到文件或将其缩小为 InputStream 或类似的东西的情况下获取文件大小。
我最后做的是向请求添加自定义 header。然后,您可以在控制器中读取 header:
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Mono<Long> fileSize(Mono<FilePart> filePart, @RequestHeader("File-Size") Long fileSize) {
如果您将新参数的类型更改为 Map<String, String>
、MultiValueMap<String, String>
或 HttpHeaders
,您将获得所有 header,而不仅仅是您的自定义参数.
如果你不能改变客户端的请求headers,并且你不需要文件大小绝对精确,你可以使用默认的header Content-Length
, 已经发送了,但是会少几个字节。
当您将文件作为多部分表单数据上传时,会自动创建一个名为“Content-Length”的请求header,该请求是在发送请求时计算的.
但是请注意,多部分 content-length 略大于文件大小 由于创建了一些元数据,例如文件名、边界和所有内容。而且 没有办法 您可以估计此元数据的长度。解释是 here.
这样就可以得到尺寸(略微增大):
@RestController
public class SomeController {
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Mono<Long> fileSize(Mono<FilePart> filePart, @RequestHeader("Content-Length") long contentLength) {
System.out.println("Content length is:" + contentLength + "bytes");
return Mono.empty();
}
}
您可以使用 filePart.content()
访问文件部分中的 Flux<DataBuffer>
。使用这个。
filePart.content() // for one file, is a Flux with one element
.map(dataBuffer -> {
byte[] bytes = new byte[dataBuffer.readableByteCount()]; // <---- here you count the bytes you have.
dataBuffer.read(bytes);
DataBufferUtils.release(dataBuffer);
String content = new String(bytes, StandardCharsets.UTF_8);
if (log.isTraceEnabled()) log.trace("File name: {}, content: {}", filePart.filename(),
content.length() > CONTENT_LENGTH_LIMIT ? content.substring(0, CONTENT_LENGTH_LIMIT) + "..." : content);
return content;
})