Micronaut 文件上傳

2023-03-07 13:40 更新

文件上傳的處理在 Micronaut 中有特殊處理。支持通過流式上傳或完成的上傳以非阻塞方式流式上傳。

要從多部分請求接收數(shù)據(jù),請將方法注釋的消耗參數(shù)設(shè)置為 MULTIPART_FORM_DATA。例如:

@Post(consumes = MediaType.MULTIPART_FORM_DATA)
HttpResponse upload( ... )

路由參數(shù)

方法參數(shù)類型決定了文件的接收方式。數(shù)據(jù)可以一次接收一個塊,也可以在上傳完成時接收。

如果路由參數(shù)名稱不能或不應(yīng)與請求中的部件名稱相匹配,請將部件注釋添加到參數(shù)中并在請求中指定預(yù)期的名稱。

塊數(shù)據(jù)類型

PartData 表示在多部分請求中接收到的數(shù)據(jù)塊。 PartData 接口方法將數(shù)據(jù)轉(zhuǎn)換為 byte[]、InputStream 或 ByteBuffer。

數(shù)據(jù)只能從 PartData 中檢索一次。釋放底層緩沖區(qū),導(dǎo)致進(jìn)一步嘗試失敗。

Publisher 類型的路由參數(shù)被視為旨在接收單個文件,并且接收到的文件的每個塊都將發(fā)送到下游。如果泛型類型不是 PartData,將嘗試使用 Micronaut 的轉(zhuǎn)換服務(wù)進(jìn)行轉(zhuǎn)換。默認(rèn)支持轉(zhuǎn)換為 String 和 byte[]。

如果您需要有關(guān)上傳文件的元數(shù)據(jù)的知識,StreamingFileUpload 類是一個 Publisher,它還具有文件信息,例如內(nèi)容類型和文件名。

流式文件上傳

 Java Groovy  Kotlin 
import io.micronaut.http.HttpResponse;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Post;
import io.micronaut.http.multipart.StreamingFileUpload;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Mono;
import io.micronaut.core.async.annotation.SingleResult;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;

import static io.micronaut.http.HttpStatus.CONFLICT;
import static io.micronaut.http.MediaType.MULTIPART_FORM_DATA;
import static io.micronaut.http.MediaType.TEXT_PLAIN;

@Controller("/upload")
public class UploadController {
// end:class[]

    @Post(value = "/", consumes = MULTIPART_FORM_DATA, produces = TEXT_PLAIN) // (1)
    @SingleResult
    public Publisher<HttpResponse<String>> upload(StreamingFileUpload file) { // (2)

        File tempFile;
        try {
            tempFile = File.createTempFile(file.getFilename(), "temp");
        } catch (IOException e) {
            return Mono.error(e);
        }
        Publisher<Boolean> uploadPublisher = file.transferTo(tempFile); // (3)

        return Mono.from(uploadPublisher)  // (4)
            .map(success -> {
                if (success) {
                    return HttpResponse.ok("Uploaded");
                } else {
                    return HttpResponse.<String>status(CONFLICT)
                                       .body("Upload Failed");
                }
            });
    }

    @Post(value = "/outputStream", consumes = MULTIPART_FORM_DATA, produces = TEXT_PLAIN) // (1)
    @SingleResult
    public Mono<HttpResponse<String>> uploadOutputStream(StreamingFileUpload file) { // (2)

        OutputStream outputStream = new ByteArrayOutputStream(); // (3)

        Publisher<Boolean> uploadPublisher = file.transferTo(outputStream); // (4)

        return Mono.from(uploadPublisher)  // (5)
                .map(success -> {
                    if (success) {
                        return HttpResponse.ok("Uploaded");
                    } else {
                        return HttpResponse.<String>status(CONFLICT)
                                .body("Upload Failed");
                    }
                });
    }

}

@Post(value = "/", consumes = MULTIPART_FORM_DATA, produces = TEXT_PLAIN) // (1)
@SingleResult
public Publisher<HttpResponse<String>> upload(StreamingFileUpload file) { // (2)

    File tempFile;
    try {
        tempFile = File.createTempFile(file.getFilename(), "temp");
    } catch (IOException e) {
        return Mono.error(e);
    }
    Publisher<Boolean> uploadPublisher = file.transferTo(tempFile); // (3)

    return Mono.from(uploadPublisher)  // (4)
        .map(success -> {
            if (success) {
                return HttpResponse.ok("Uploaded");
            } else {
                return HttpResponse.<String>status(CONFLICT)
                                   .body("Upload Failed");
            }
        });
}

}
import io.micronaut.http.HttpResponse
import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Post
import io.micronaut.http.multipart.StreamingFileUpload
import org.reactivestreams.Publisher
import reactor.core.publisher.Mono

import static io.micronaut.http.HttpStatus.CONFLICT
import static io.micronaut.http.MediaType.MULTIPART_FORM_DATA
import static io.micronaut.http.MediaType.TEXT_PLAIN

@Controller("/upload")
class UploadController {

@Post(value = "/", consumes = MULTIPART_FORM_DATA, produces = TEXT_PLAIN) // (1)
Mono<HttpResponse<String>> upload(StreamingFileUpload file) { // (2)

    File tempFile = File.createTempFile(file.filename, "temp")
    Publisher<Boolean> uploadPublisher = file.transferTo(tempFile) // (3)

    Mono.from(uploadPublisher)  // (4)
        .map({ success ->
            if (success) {
                HttpResponse.ok("Uploaded")
            } else {
                HttpResponse.<String>status(CONFLICT)
                        .body("Upload Failed")
            }
        })
}

}
import io.micronaut.core.async.annotation.SingleResult
import io.micronaut.http.HttpResponse
import io.micronaut.http.HttpStatus.CONFLICT
import io.micronaut.http.MediaType.MULTIPART_FORM_DATA
import io.micronaut.http.MediaType.TEXT_PLAIN
import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Post
import io.micronaut.http.multipart.StreamingFileUpload
import org.reactivestreams.Publisher
import reactor.core.publisher.Mono
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.OutputStream

@Controller("/upload")
class UploadController {

@Post(value = "/", consumes = [MULTIPART_FORM_DATA], produces = [TEXT_PLAIN]) // (1)
fun upload(file: StreamingFileUpload): Mono<HttpResponse<String>> { // (2)

    val tempFile = File.createTempFile(file.filename, "temp")
    val uploadPublisher = file.transferTo(tempFile) // (3)

    return Mono.from(uploadPublisher)  // (4)
        .map { success ->
            if (success) {
                HttpResponse.ok("Uploaded")
            } else {
                HttpResponse.status<String>(CONFLICT)
                    .body("Upload Failed")
            }
        }
}

}
// end::endclass]
  1. 該方法使用 MULTIPART_FORM_DATA

  2. 方法參數(shù)匹配表單屬性名稱。在這種情況下,文件將匹配例如 <input type="file" name="file">

  3. StreamingFileUpload.transferTo(File) 方法將文件傳輸?shù)椒?wù)器。該方法返回一個發(fā)布者

  4. 返回的 Mono 訂閱 Publisher 并在上傳完成后輸出響應(yīng),不會阻塞。

也可以使用 transferTo 方法傳遞輸出流。

文件或流的讀取將被卸載到 IO 線程池,以防止阻塞事件循環(huán)的可能性。

流式文件上傳

 Java Groovy  Kotlin 
import io.micronaut.http.HttpResponse;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Post;
import io.micronaut.http.multipart.StreamingFileUpload;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Mono;
import io.micronaut.core.async.annotation.SingleResult;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;

import static io.micronaut.http.HttpStatus.CONFLICT;
import static io.micronaut.http.MediaType.MULTIPART_FORM_DATA;
import static io.micronaut.http.MediaType.TEXT_PLAIN;

@Controller("/upload")
public class UploadController {
// end:class[]

    @Post(value = "/", consumes = MULTIPART_FORM_DATA, produces = TEXT_PLAIN) // (1)
    @SingleResult
    public Publisher<HttpResponse<String>> upload(StreamingFileUpload file) { // (2)

        File tempFile;
        try {
            tempFile = File.createTempFile(file.getFilename(), "temp");
        } catch (IOException e) {
            return Mono.error(e);
        }
        Publisher<Boolean> uploadPublisher = file.transferTo(tempFile); // (3)

        return Mono.from(uploadPublisher)  // (4)
            .map(success -> {
                if (success) {
                    return HttpResponse.ok("Uploaded");
                } else {
                    return HttpResponse.<String>status(CONFLICT)
                                       .body("Upload Failed");
                }
            });
    }

    @Post(value = "/outputStream", consumes = MULTIPART_FORM_DATA, produces = TEXT_PLAIN) // (1)
    @SingleResult
    public Mono<HttpResponse<String>> uploadOutputStream(StreamingFileUpload file) { // (2)

        OutputStream outputStream = new ByteArrayOutputStream(); // (3)

        Publisher<Boolean> uploadPublisher = file.transferTo(outputStream); // (4)

        return Mono.from(uploadPublisher)  // (5)
                .map(success -> {
                    if (success) {
                        return HttpResponse.ok("Uploaded");
                    } else {
                        return HttpResponse.<String>status(CONFLICT)
                                .body("Upload Failed");
                    }
                });
    }

}

@Post(value = "/outputStream", consumes = MULTIPART_FORM_DATA, produces = TEXT_PLAIN) // (1)
@SingleResult
public Mono<HttpResponse<String>> uploadOutputStream(StreamingFileUpload file) { // (2)

    OutputStream outputStream = new ByteArrayOutputStream(); // (3)

    Publisher<Boolean> uploadPublisher = file.transferTo(outputStream); // (4)

    return Mono.from(uploadPublisher)  // (5)
            .map(success -> {
                if (success) {
                    return HttpResponse.ok("Uploaded");
                } else {
                    return HttpResponse.<String>status(CONFLICT)
                            .body("Upload Failed");
                }
            });
}

}
import io.micronaut.http.HttpResponse
import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Post
import io.micronaut.http.multipart.StreamingFileUpload
import org.reactivestreams.Publisher
import reactor.core.publisher.Mono

import static io.micronaut.http.HttpStatus.CONFLICT
import static io.micronaut.http.MediaType.MULTIPART_FORM_DATA
import static io.micronaut.http.MediaType.TEXT_PLAIN

@Controller("/upload")
class UploadController {

@Post(value = "/outputStream", consumes = MULTIPART_FORM_DATA, produces = TEXT_PLAIN) // (1)
@SingleResult
Mono<HttpResponse<String>> uploadOutputStream(StreamingFileUpload file) { // (2)

    OutputStream outputStream = new ByteArrayOutputStream() // (3)

    Publisher<Boolean> uploadPublisher = file.transferTo(outputStream) // (4)

    Mono.from(uploadPublisher)  // (5)
            .map({ success ->
                if (success) {
                    HttpResponse.ok("Uploaded")
                } else {
                    HttpResponse.<String>status(CONFLICT)
                            .body("Upload Failed")
                }
            })
}

}
import io.micronaut.core.async.annotation.SingleResult
import io.micronaut.http.HttpResponse
import io.micronaut.http.HttpStatus.CONFLICT
import io.micronaut.http.MediaType.MULTIPART_FORM_DATA
import io.micronaut.http.MediaType.TEXT_PLAIN
import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Post
import io.micronaut.http.multipart.StreamingFileUpload
import org.reactivestreams.Publisher
import reactor.core.publisher.Mono
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.OutputStream

@Controller("/upload")
class UploadController {

@Post(value = "/outputStream", consumes = [MULTIPART_FORM_DATA], produces = [TEXT_PLAIN]) // (1)
@SingleResult
fun uploadOutputStream(file: StreamingFileUpload): Mono<HttpResponse<String>> { // (2)
    val outputStream  = ByteArrayOutputStream() // (3)
    val uploadPublisher = file.transferTo(outputStream) // (4)

    return Mono.from(uploadPublisher) // (5)
        .map { success: Boolean ->
            return@map if (success) {
                HttpResponse.ok("Uploaded")
            } else {
                HttpResponse.status<String>(CONFLICT)
                    .body("Upload Failed")
            }
        }
}

}
// end::endclass]
  1. 該方法使用 MULTIPART_FORM_DATA

  2. 方法參數(shù)匹配表單屬性名稱。在這種情況下,文件將匹配例如 <input type="file" name="file">

  3. 創(chuàng)建流以將數(shù)據(jù)輸出到。在現(xiàn)實(shí)世界的場景中,這將來自其他來源。

  4. StreamingFileUpload.transferTo(OutputStream) 方法將文件傳輸?shù)椒?wù)器。該方法返回一個發(fā)布者

  5. 返回的 Mono 訂閱 Publisher 并在上傳完成后輸出響應(yīng),不會阻塞。

整個數(shù)據(jù)類型

不是發(fā)布者的路由參數(shù)會導(dǎo)致路由執(zhí)行延遲到上傳完成。收到的數(shù)據(jù)將嘗試轉(zhuǎn)換為請求的類型。默認(rèn)支持轉(zhuǎn)換為 String 或 byte[]。此外,如果注冊了支持文件媒體類型的媒體類型編解碼器,則可以將文件轉(zhuǎn)換為 POJO。默認(rèn)包含媒體類型編解碼器,允許將 JSON 文件轉(zhuǎn)換為 POJO。

接收字節(jié)數(shù)組

 Java Groovy  Kotlin 
import io.micronaut.http.HttpResponse;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Post;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import static io.micronaut.http.MediaType.MULTIPART_FORM_DATA;
import static io.micronaut.http.MediaType.TEXT_PLAIN;

@Controller("/upload")
public class BytesUploadController {

    @Post(value = "/bytes", consumes = MULTIPART_FORM_DATA, produces = TEXT_PLAIN) // (1)
    public HttpResponse<String> uploadBytes(byte[] file, String fileName) { // (2)
        try {
            File tempFile = File.createTempFile(fileName, "temp");
            Path path = Paths.get(tempFile.getAbsolutePath());
            Files.write(path, file); // (3)
            return HttpResponse.ok("Uploaded");
        } catch (IOException e) {
            return HttpResponse.badRequest("Upload Failed");
        }
    }
}
import io.micronaut.http.HttpResponse
import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Post

import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths

import static io.micronaut.http.MediaType.MULTIPART_FORM_DATA
import static io.micronaut.http.MediaType.TEXT_PLAIN

@Controller("/upload")
class BytesUploadController {

    @Post(value = "/bytes", consumes = MULTIPART_FORM_DATA, produces = TEXT_PLAIN) // (1)
    HttpResponse<String> uploadBytes(byte[] file, String fileName) { // (2)
        try {
            File tempFile = File.createTempFile(fileName, "temp")
            Path path = Paths.get(tempFile.absolutePath)
            Files.write(path, file) // (3)
            HttpResponse.ok("Uploaded")
        } catch (IOException e) {
            HttpResponse.badRequest("Upload Failed")
        }
    }
}
import io.micronaut.http.HttpResponse
import io.micronaut.http.MediaType
import io.micronaut.http.MediaType.MULTIPART_FORM_DATA
import io.micronaut.http.MediaType.TEXT_PLAIN
import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Post
import java.io.File
import java.io.IOException
import java.nio.file.Files
import java.nio.file.Paths

@Controller("/upload")
class BytesUploadController {

    @Post(value = "/bytes", consumes = [MULTIPART_FORM_DATA], produces = [TEXT_PLAIN]) // (1)
    fun uploadBytes(file: ByteArray, fileName: String): HttpResponse<String> { // (2)
        return try {
            val tempFile = File.createTempFile(fileName, "temp")
            val path = Paths.get(tempFile.absolutePath)
            Files.write(path, file) // (3)
            HttpResponse.ok("Uploaded")
        } catch (e: IOException) {
            HttpResponse.badRequest("Upload Failed")
        }
    }
}

如果您需要有關(guān)上傳文件的元數(shù)據(jù)的知識,CompletedFileUpload 類具有檢索文件數(shù)據(jù)以及內(nèi)容類型和文件名等文件信息的方法。

帶元數(shù)據(jù)的文件上傳

 Java Groovy  Kotlin 
import io.micronaut.http.HttpResponse;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Post;
import io.micronaut.http.multipart.CompletedFileUpload;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import static io.micronaut.http.MediaType.MULTIPART_FORM_DATA;
import static io.micronaut.http.MediaType.TEXT_PLAIN;

@Controller("/upload")
public class CompletedUploadController {

    @Post(value = "/completed", consumes = MULTIPART_FORM_DATA, produces = TEXT_PLAIN) // (1)
    public HttpResponse<String> uploadCompleted(CompletedFileUpload file) { // (2)
        try {
            File tempFile = File.createTempFile(file.getFilename(), "temp"); //(3)
            Path path = Paths.get(tempFile.getAbsolutePath());
            Files.write(path, file.getBytes()); //(3)
            return HttpResponse.ok("Uploaded");
        } catch (IOException e) {
            return HttpResponse.badRequest("Upload Failed");
        }
    }
}
import io.micronaut.http.HttpResponse
import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Post
import io.micronaut.http.multipart.CompletedFileUpload

import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths

import static io.micronaut.http.MediaType.MULTIPART_FORM_DATA
import static io.micronaut.http.MediaType.TEXT_PLAIN

@Controller("/upload")
class CompletedUploadController {

    @Post(value = "/completed", consumes = MULTIPART_FORM_DATA, produces = TEXT_PLAIN) // (1)
    HttpResponse<String> uploadCompleted(CompletedFileUpload file) { // (2)
        try {
            File tempFile = File.createTempFile(file.filename, "temp") //(3)
            Path path = Paths.get(tempFile.absolutePath)
            Files.write(path, file.bytes) //(3)
            HttpResponse.ok("Uploaded")
        } catch (IOException e) {
            HttpResponse.badRequest("Upload Failed")
        }
    }
}
import io.micronaut.http.HttpResponse
import io.micronaut.http.MediaType.MULTIPART_FORM_DATA
import io.micronaut.http.MediaType.TEXT_PLAIN
import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Post
import io.micronaut.http.multipart.CompletedFileUpload
import java.io.File
import java.io.IOException
import java.nio.file.Files
import java.nio.file.Paths

@Controller("/upload")
class CompletedUploadController {

    @Post(value = "/completed", consumes = [MULTIPART_FORM_DATA], produces = [TEXT_PLAIN]) // (1)
    fun uploadCompleted(file: CompletedFileUpload): HttpResponse<String> { // (2)
        return try {
            val tempFile = File.createTempFile(file.filename, "temp") //(3)
            val path = Paths.get(tempFile.absolutePath)
            Files.write(path, file.bytes) //(3)
            HttpResponse.ok("Uploaded")
        } catch (e: IOException) {
            HttpResponse.badRequest("Upload Failed")
        }
    }
}
  1. 該方法使用 MULTIPART_FORM_DATA

  2. 方法參數(shù)匹配表單屬性名稱。在這種情況下,文件將匹配例如 <input type="file" name="file">

  3. CompletedFileUpload 實(shí)例可以訪問有關(guān)上傳的元數(shù)據(jù)以及文件內(nèi)容。

如果不讀取文件,則必須調(diào)用文件對象的丟棄方法以防止內(nèi)存泄漏。

多次上傳

不同的名字

如果一個多部分請求有多個具有不同部分名稱的上傳,請為接收每個部分的路由創(chuàng)建一個參數(shù)。例如:

HttpResponse upload(String title, String name)

像上面這樣的路由方法簽名需要兩個不同的部分,一個名為“title”,另一個名為“name”。

一樣的名字

要接收具有相同部件名稱的多個部件,參數(shù)必須是 Publisher。當(dāng)以下列方式之一使用時,發(fā)布者為找到的具有指定名稱的每個部分發(fā)出一個項(xiàng)目。發(fā)布者必須接受以下類型之一:

例如:

HttpResponse upload(Publisher<StreamingFileUpload> files)
HttpResponse upload(Publisher<CompletedFileUpload> files)
HttpResponse upload(Publisher<MyObject> files)
HttpResponse upload(Publisher<Publisher<PartData>> files)
HttpResponse upload(Publisher<CompletedPart> attributes)

Whole Body Binding

當(dāng)事先不知道請求的部分名稱或讀取整個正文時,可以使用特殊類型來指示需要整個正文。

如果路由有一個類型為 MultipartBody 的參數(shù)(不要與客戶端的類混淆)并用 @Body 注釋,則請求的每個部分都將通過該參數(shù)發(fā)出。 MultipartBody 是 CompletedPart 實(shí)例的發(fā)布者。

例如:

綁定到整個多部分主體

 Java Groovy  Kotlin 
import io.micronaut.http.annotation.Body;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Post;
import io.micronaut.http.multipart.CompletedFileUpload;
import io.micronaut.http.multipart.CompletedPart;
import io.micronaut.http.server.multipart.MultipartBody;
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import reactor.core.publisher.Mono;
import io.micronaut.core.async.annotation.SingleResult;
import static io.micronaut.http.MediaType.MULTIPART_FORM_DATA;
import static io.micronaut.http.MediaType.TEXT_PLAIN;

@Controller("/upload")
public class WholeBodyUploadController {

    @Post(value = "/whole-body", consumes = MULTIPART_FORM_DATA, produces = TEXT_PLAIN) // (1)
    @SingleResult
    public Publisher<String> uploadBytes(@Body MultipartBody body) { // (2)

        return Mono.create(emitter -> {
            body.subscribe(new Subscriber<CompletedPart>() {
                private Subscription s;

                @Override
                public void onSubscribe(Subscription s) {
                    this.s = s;
                    s.request(1);
                }

                @Override
                public void onNext(CompletedPart completedPart) {
                    String partName = completedPart.getName();
                    if (completedPart instanceof CompletedFileUpload) {
                        String originalFileName = ((CompletedFileUpload) completedPart).getFilename();
                    }
                }

                @Override
                public void onError(Throwable t) {
                    emitter.error(t);
                }

                @Override
                public void onComplete() {
                    emitter.success("Uploaded");
                }
            });
        });
    }
}
import io.micronaut.http.annotation.Body
import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Post
import io.micronaut.http.multipart.CompletedFileUpload
import io.micronaut.http.multipart.CompletedPart
import io.micronaut.http.server.multipart.MultipartBody
import org.reactivestreams.Subscriber
import org.reactivestreams.Subscription
import reactor.core.publisher.Mono

import static io.micronaut.http.MediaType.MULTIPART_FORM_DATA
import static io.micronaut.http.MediaType.TEXT_PLAIN

@Controller("/upload")
class WholeBodyUploadController {

    @Post(value = "/whole-body", consumes = MULTIPART_FORM_DATA, produces = TEXT_PLAIN) // (1)
    Mono<String> uploadBytes(@Body MultipartBody body) { // (2)

        Mono.<String>create({ emitter ->
            body.subscribe(new Subscriber<CompletedPart>() {
                private Subscription s

                @Override
                void onSubscribe(Subscription s) {
                    this.s = s
                    s.request(1)
                }

                @Override
                void onNext(CompletedPart completedPart) {
                    String partName = completedPart.name
                    if (completedPart instanceof CompletedFileUpload) {
                        String originalFileName = completedPart.filename
                    }
                }

                @Override
                void onError(Throwable t) {
                    emitter.error(t)
                }

                @Override
                void onComplete() {
                    emitter.success("Uploaded")
                }
            })
        })
    }
}
import io.micronaut.http.MediaType.MULTIPART_FORM_DATA
import io.micronaut.http.MediaType.TEXT_PLAIN
import io.micronaut.http.annotation.Body
import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Post
import io.micronaut.http.multipart.CompletedFileUpload
import io.micronaut.http.multipart.CompletedPart
import io.micronaut.http.server.multipart.MultipartBody
import org.reactivestreams.Subscriber
import org.reactivestreams.Subscription
import reactor.core.publisher.Mono

@Controller("/upload")
class WholeBodyUploadController {

    @Post(value = "/whole-body", consumes = [MULTIPART_FORM_DATA], produces = [TEXT_PLAIN]) // (1)
    fun uploadBytes(@Body body: MultipartBody): Mono<String> { // (2)
        return Mono.create { emitter ->
            body.subscribe(object : Subscriber<CompletedPart> {
                private var s: Subscription? = null

                override fun onSubscribe(s: Subscription) {
                    this.s = s
                    s.request(1)
                }

                override fun onNext(completedPart: CompletedPart) {
                    val partName = completedPart.name
                    if (completedPart is CompletedFileUpload) {
                        val originalFileName = completedPart.filename
                    }
                }

                override fun onError(t: Throwable) {
                    emitter.error(t)
                }

                override fun onComplete() {
                    emitter.success("Uploaded")
                }
            })
        }
    }
}


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號