2017-11-09 10 views
1

Spring Reactive WebClientを使用してファイルをSpring Controllerにアップロードしようとしています。コントローラは本当に簡単で、次のようになります。私が使用した場合のcURLすべてと、このコントローラは正常に動作しますSpring Webリアクティブクライアント

@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 -X POST http://localhost:8080/upload -H 'content-type: multipart/form-data;' -F fileName=test.txt -F randomKey=randomValue -F [email protected] 

multipartFileが正しいパラメータに行き、他のパラメータは、地図に行きます。

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

誰もがこの問題を解決する方法を知っていますか?

+0

あなたは私がすでにあることでしたが、それは違いはありませんMultipartFile multipartFile – Yogi

+0

ため@RequestPartを使用して試すことができます。私は別の解決策を見つけ、それを掲示します。 – Ozzie

答えて

0

私は自分自身で解決策を見つけました。 Springは実際にアップロードのファイル名をコントローラ内のMultipartFileにシリアル化するために、Content-Dispositionヘッダが本当に必要であることが分かります。これを行うには

は、私は、この中にByteArrayResourceを使用して、このコード

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); 
0

とクライアントで使用することができ、ファイル名

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

設定をサポートByteArrayResourceのサブクラスを作成する必要がありました大文字小文字は効率的ではありません。ファイル全体の内容がメモリに読み込まれるためです。

接頭辞が"file:"UrlResourceを使用するか、ClassPathResourceを使用すると両方の問題が解決されます。

UrlResource resource = new UrlResource("file:///path/to/my/document.pdf"); 
+0

これはここのコードサンプルのみでした。実際のコードでは、リソースはすでにコンテンツリポジトリからのバイアレイです。ファイルシステムのファイルではありません。 – Ozzie

関連する問題