Spring Web Reactive客户端 [英] Spring Web Reactive client

查看:367
本文介绍了Spring Web Reactive客户端的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Spring Reactive WebClient将文件上传到spring控制器.控制器非常简单,看起来像这样:

I'm trying to use the Spring Reactive WebClient to upload a file to a spring controller. The controller is really simple and looks like this:

@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一起使用时,一切正常

When I use this controller with cURL everything works fine

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.

The multipartFile goes to the correct parameter and the other parameters go in to the Map.

当我尝试从WebClient进行相同操作时,我陷入了困境.我的代码如下:

When I try to do the same from the WebClient I get stuck. My code looks like this:

    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"
}

有人知道如何解决这个问题吗?

Does anyone know how to solve this issue?

推荐答案

所以我自己找到了解决方案.事实证明,Spring确实需要Content-Disposition标头包含用于上传的文件名,以便将其序列化到Controller中的MultipartFile.

So i found a solution myself. Turns out that Spring really needs the Content-Disposition header to include a filename for a upload to be serialized to a MultipartFile in the Controller.

为此,我必须创建一个ByteArrayResource的子类,该子类支持设置文件名

To do this i had to create a subclass of ByteArrayResource that supports setting the filename

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;
  }
}

然后可以在此代码中将其用于客户端

Which can then be used in the client with this code

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 Web Reactive客户端的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆