Spring boot SpringWebFlux文件部分如何验证mime类型?
考虑到下面的控制器映射,我想知道如何验证提供的文件是否是具有最大文件大小的图像Spring boot SpringWebFlux文件部分如何验证mime类型?,spring-boot,spring-webflux,Spring Boot,Spring Webflux,考虑到下面的控制器映射,我想知道如何验证提供的文件是否是具有最大文件大小的图像 @PostMapping("/users/avatar") suspend fun uploadAvatar(@RequestPart("file") filePartMono: Mono<FilePart>) { filePartMono.map{ part -> part.content().map{ it.asInputStream().readAl
@PostMapping("/users/avatar")
suspend fun uploadAvatar(@RequestPart("file") filePartMono: Mono<FilePart>) {
filePartMono.map{ part -> part.content().map{ it.asInputStream().readAllBytes() }
.map { it /* ??? */ }
}
// ...
}
@PostMapping(“/users/avatar”)
暂停乐趣上传化身(@RequestPart(“文件”)filePartMono:Mono){
filePartMono.map{part->part.content().map{it.asInputStream().readAllBytes()}
.map{it/*???*/}
}
// ...
}
在非反应性堆栈上,我是这样做的:
uploadAvatar(@RequestParam("file") MultipartFile file) {
String contentType = file.getContentType().toLowerCase();
List<String> valid = Arrays.asList("image/jpg", "image/jpeg", "image/png");
if (file.isEmpty() || !valid.contains(contentType)) {
throw new UploadException("Invalid image format or empty file", HttpStatus.UNPROCESSABLE_ENTITY);
}
if (file.getSize() > IMAGE_MAX_FILE_SIZE) {
throw new UploadException("Image too big (max " + (IMAGE_MAX_FILE_SIZE / 1000) + " kB )", HttpStatus.UNPROCESSABLE_ENTITY);
}
try {
// try to read file as image to ensure it is an image
ImageIO.read(file.getInputStream());
} catch (IOException e) {
throw new UploadException("Invalid image", HttpStatus.UNPROCESSABLE_ENTITY);
}
try {
byte[] bytes = file.getBytes();
userService.storeAvatar(bytes);
} catch (IOException e) {
throw new UploadException("Could not store image", HttpStatus.INTERNAL_SERVER_ERROR);
}
}
uploadAvatar(@RequestParam(“文件”)多部分文件){
字符串contentType=file.getContentType().toLowerCase();
List valid=Arrays.asList(“image/jpg”、“image/jpeg”、“image/png”);
if(file.isEmpty()| |!valid.contains(contentType)){
抛出新的UploadException(“无效的图像格式或空文件”,HttpStatus.UNPROCESSABLE_ENTITY);
}
if(file.getSize()>IMAGE\u MAX\u file\u SIZE){
抛出新的UploadException(“图像太大(最大”+(图像最大文件大小/1000)+“kB)”,HttpStatus.UNPROCESSABLE_ENTITY);
}
试一试{
//尝试将文件作为图像读取,以确保它是图像
read(file.getInputStream());
}捕获(IOE异常){
抛出新的UploadException(“无效图像”,HttpStatus.UNPROCESSABLE_实体);
}
试一试{
byte[]bytes=file.getBytes();
userService.storeAvatar(字节);
}捕获(IOE异常){
抛出新的上载异常(“无法存储映像”,HttpStatus.INTERNAL\u SERVER\u错误);
}
}
但是FilePart不提供相同的API(例如contentType)
如何从
FilePart
中获取contentType和文件大小?FilePart
具有您可以这样访问的标题
@PostMapping(value = ["/upload"], consumes = [MediaType.MULTIPART_FORM_DATA_VALUE])
suspend fun upload(@RequestPart(name = "file") file: Mono<FilePart>) {
val filePart = file.awaitFirstOrNull() ?: throw Exception()
println(filePart.headers().contentType)
println(filePart.headers().contentLength)
}
@PostMapping(value = ["/upload"], consumes = [MediaType.MULTIPART_FORM_DATA_VALUE])
suspend fun upload(@RequestPart(name = "file") file: Mono<FilePart>) : Response {
val filePart = file.awaitFirstOrNull() ?: throw Exception()
val inputStream = filePart.content().awaitFirst().asInputStream()
val detectedFileTye = getFilePartFileType(filePart.filename(), inputStream)
...
}
private suspend fun getFilePartFileType(fileName: String, inputStream: InputStream): String? = coroutineScope {
val mimeTypeDeferred = async(Dispatchers.IO) {
Tika().detect(inputStream, fileName)
}
mimeTypeDeferred.await()
}
然而,Tika
detect正在阻止调用,所以您需要这样做
@PostMapping(value = ["/upload"], consumes = [MediaType.MULTIPART_FORM_DATA_VALUE])
suspend fun upload(@RequestPart(name = "file") file: Mono<FilePart>) {
val filePart = file.awaitFirstOrNull() ?: throw Exception()
println(filePart.headers().contentType)
println(filePart.headers().contentLength)
}
@PostMapping(value = ["/upload"], consumes = [MediaType.MULTIPART_FORM_DATA_VALUE])
suspend fun upload(@RequestPart(name = "file") file: Mono<FilePart>) : Response {
val filePart = file.awaitFirstOrNull() ?: throw Exception()
val inputStream = filePart.content().awaitFirst().asInputStream()
val detectedFileTye = getFilePartFileType(filePart.filename(), inputStream)
...
}
private suspend fun getFilePartFileType(fileName: String, inputStream: InputStream): String? = coroutineScope {
val mimeTypeDeferred = async(Dispatchers.IO) {
Tika().detect(inputStream, fileName)
}
mimeTypeDeferred.await()
}
@PostMapping(值=[“/upload”],使用=[MediaType.MULTIPART\u FORM\u DATA\u value])
暂停趣味上传(@RequestPart(name=“file”)文件:Mono):响应{
val filePart=file.waitingfirstornull()?:抛出异常()
val inputStream=filePart.content().awaitFirst().asInputStream()
val detectedFileTye=getFilePartFileType(filePart.filename(),inputStream)
...
}
private suspend fun getFilePartFileType(文件名:String,inputStream:inputStream):String?=共线镜{
val mimetypederferred=async(Dispatchers.IO){
Tika().detect(inputStream,文件名)
}
mimetypedereferred.await()
}
我唯一不明白的是private helper函数的返回类型
FileType?
。它指的是哪个包裹?mimetypederferred
的类型为Deferred
。很抱歉,它应该是字符串
错误的复制/粘贴。我正在使用文件类型
,但它是一个与此处无关的自定义对象。谢谢!我学到了很多。您能告诉我您是如何通过tearray获得实际的数据的吗?根据我所读的,tika将重置inputstream,以便我们可以重用它,我现在将使用相同的模式val bytes=coroutineScope{val bytesderferred=async(Dispatchers.IO){inputstream.readAllBytes()}bytesderferred.wait()}
是的,这是一种方法。就我而言,没有必要使用ByteArray。