我试图使用Spring反应式WebClient将文件上传到Spring控制器。控制器非常简单,看起来像这样:
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<String> uploadFile(
@RequestParam("multipartFile") MultipartFile multipartFile,
@RequestParam Map<String, Object> entityRequest
) {
entityRequest.entrySet().forEach(System.out::println);
System.out.println(multipartFile);
return ResponseEntity.ok("OK");
}
当我使用这个控制器与cURL一切正常
curl -X POST http://localhost:8080/upload -H 'content-type: multipart/form-data;' -F fileName=test.txt -F randomKey=randomValue -F multipartFile=@document.pdf
multipartFile转到正确的参数,其他参数进入Map。
当我尝试从WebClient做同样的事情时,我被卡住了。我的代码如下所示:
WebClient client = WebClient.builder().baseUrl("http://localhost:8080").build();
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.set("multipartFile", new ByteArrayResource(Files.readAllBytes(Paths.get("/path/to/my/document.pdf"))));
map.set("fileName", "test.txt");
map.set("randomKey", "randomValue");
String result = client.post()
.uri("/upload")
.contentType(MediaType.MULTIPART_FORM_DATA)
.syncBody(map)
.exchange()
.flatMap(response -> response.bodyToMono(String.class))
.flux()
.blockFirst();
System.out.println("RESULT: " + result);
这会导致400错误
{
"timestamp":1510228507230,
"status":400,
"error":"Bad Request",
"message":"Required request part 'multipartFile' is not present",
"path":"/upload"
}
有人知道如何解决这个问题吗?
提供内容处置的更简单方法
MultipartBodyBuilder builder = new MultipartBodyBuilder();
String header = String.format("form-data; name=%s; filename=%s", "paramName", "fileName.pdf");
builder.part("paramName", new ByteArrayResource(<file in byte array>)).header("Content-Disposition", header);
// in the request use
webClient.post().body(BodyInserters.fromMultipartData(builder.build()))
您需要在文件部分包含一个文件名以成功上传,并结合< code>asyncPart()以避免缓冲所有文件内容,然后您可以编写如下代码:
WebClient client = WebClient.builder().baseUrl("http://localhost:8080").build();
Mono<String> result = client.post()
.uri("/upload")
.contentType(MediaType.MULTIPART_FORM_DATA)
.body((outputMessage, context) ->
Mono.defer(() -> {
MultipartBodyBuilder bodyBuilder = new MultipartBodyBuilder();
Flux<DataBuffer> data = DataBufferUtils.read(
Paths.get("/tmp/file.csv"), outputMessage.bufferFactory(), 4096);
bodyBuilder.asyncPart("file", data, DataBuffer.class)
.filename("filename.csv");
return BodyInserters.fromMultipartData(bodyBuilder.build())
.insert(outputMessage, context);
}))
.exchange()
.flatMap(response -> response.bodyToMono(String.class));
System.out.println("RESULT: " + result.block());
所以我自己找到了解决办法。事实证明,Spring确实需要Content Disposition头来包含一个文件名,以便将上传序列化为控制器中的多部分文件。
为此,我必须创建一个支持设置文件名的ByteArrayResource子类
public class MultiPartResource extends ByteArrayResource {
private String filename;
public MultiPartResource(byte[] byteArray) {
super(byteArray);
}
public MultiPartResource(byte[] byteArray, String filename) {
super(byteArray);
this.filename = filename;
}
@Nullable
@Override
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
}
然后可以在客户机中使用这些代码
WebClient client = WebClient.builder().baseUrl("http://localhost:8080").build();
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.set("fileName", "test.txt");
map.set("randomKey", "randomValue");
ByteArrayResource resource = new MultiPartResource(Files.readAllBytes(Paths.get("/path/to/my/document.pdf")), "document.pdf");
String result = client.post()
.uri("/upload")
.contentType(MediaType.MULTIPART_FORM_DATA)
.body(BodyInserters.fromMultipartData(map))
.exchange()
.flatMap(response -> response.bodyToMono(String.class))
.flux()
.blockFirst();
System.out.println("RESULT: " + result);
我想在Spring WebClient请求链接中发送链接请求参数。例如: https://www.test.com/notification?con=41280440000097 我尝试了以下代码: 但是当我试图设置映射时,我在标记
在SpringJSFWeb应用程序中将Netty客户端处理程序配置为消息接收点,有没有具体的方法? 如果一些独立的Java应用程序充当Netty服务器,我如何接收到SpringJSFWeb应用程序的消息?
我试图测试Spring反应式Webclient的默认超时。为此,我创建了一个需要 10 小时才能返回响应的 rest endpoint。 我使用spring-reactive Webclient创建了一个rest客户端。但我看到,springReactiveWebclient一直在等待10个小时。 spring reactive Webclient没有任何默认超时吗?
在一节中,引入了接口,允许在请求中注入头,但必须返回同步响应。我们不能使用,这正是我的情况所需要的,因为我需要在头中添加一个令牌,而这个令牌是由返回的另一个restendpoint的请求检索的。 我如何在新的实现中实现这一点?如果不可能,有没有解决办法?
如何将响应从反应型HTTP客户机流式传输到控制器,而不在任何时候将整个响应主体放在应用程序内存中? 几乎所有project reactor客户机的示例都返回。据我所知,反应流是关于流,而不是加载它,然后发送响应。 是否可以返回,以便在不需要使用大量RAM内存来存储中间结果的情况下,将大文件从某个外部服务传输到应用程序客户机?
例如,在本文中,我试图理解为什么在流中使用flatmap()(直接从引用中粘贴副本) AFAIK,应用于流的平面图会为流中的每个输入值产生任意数量的值(0... n)。所以一个平面图需要一个产生流的函数。 通量发射0个或多个项目,然后可选地完成或偏离。 那么,响应流上到底发生了什么?这是接收响应流并发出0个或更多类警报对象的函数吗?因此,如果我们