JSONを使用したSpringMVCマルチパートリクエスト


84

SpringMVCを使用してJSONデータを含むファイルを投稿したいと思います。だから私は休憩サービスを開発しました

@RequestMapping(value = "/servicegenerator/wsdl", method = RequestMethod.POST,consumes = { "multipart/mixed", "multipart/form-data" })
@ResponseBody
public String generateWSDLService(@RequestPart("meta-data") WSDLInfo wsdlInfo,@RequestPart("file") MultipartFile file) throws WSDLException, IOException,
        JAXBException, ParserConfigurationException, SAXException, TransformerException {
    return handleWSDL(wsdlInfo,file);
}

を使用して残りのクライアントからリクエストを送信すると content-Type = multipart/form-data or multipart/mixed、次の例外が発生します。 org.springframework.web.multipart.support.MissingServletRequestPartException

誰かがこの問題を解決するのを手伝ってくれますか?

@RequestPartマルチパートとJSONの両方をサーバーに送信するために使用できますか?


org.springframework.web.multipart.commons.CommonsMultipartResolverサーブレットコンテキストでを指定しましたか?
2014年

はい、spring.xmlに追加されています。<bean id = "multipartResolver" class = "org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name = "maxUploadSize" value = "300000000" /> </ bean>
Sunil Kumar

回答:


199

これが、JSONデータを使用してSpringMVCマルチパートリクエストを実装した方法です。

JSONデータを使用したマルチパートリクエスト(混合マルチパートとも呼ばれます):

Spring 4.0.2リリースのRESTfulサービスに基づいて、最初の部分をXMLまたはJSON形式のデータとして、2番目の部分をファイルとして使用するHTTPリクエストは、@ RequestPartを使用して実現できます。以下はサンプル実装です。

Javaスニペット:

ControllerのRESTサービスでは、@ RequestPartとMultipartFileを組み合わせて、このようなMultipart + JSONリクエストを処理します。

@RequestMapping(value = "/executesampleservice", method = RequestMethod.POST,
    consumes = {"multipart/form-data"})
@ResponseBody
public boolean executeSampleService(
        @RequestPart("properties") @Valid ConnectionProperties properties,
        @RequestPart("file") @Valid @NotNull @NotBlank MultipartFile file) {
    return projectService.executeSampleService(properties, file);
}

フロントエンド(JavaScript)スニペット:

  1. FormDataオブジェクトを作成します。

  2. 以下のいずれかの手順を使用して、ファイルをFormDataオブジェクトに追加します。

    1. 「file」タイプの入力要素を使用してファイルがアップロードされている場合は、それをFormDataオブジェクトに追加します。 formData.append("file", document.forms[formName].file.files[0]);
    2. ファイルをFormDataオブジェクトに直接追加します。 formData.append("file", myFile, "myfile.txt");またはformData.append("file", myBob, "myfile.txt");
  3. 文字列化されたJSONデータを使用してblobを作成し、FormDataオブジェクトに追加します。これにより、マルチパートリクエストの2番目のパートのコンテンツタイプがファイルタイプではなく「application / json」になります。

  4. サーバーにリクエストを送信します。

  5. リクエストの詳細:
    Content-Type: undefined。これにより、ブラウザはContent-Typeをmultipart / form-dataに設定し、境界を正しく埋めます。Content-Typeをmultipart / form-dataに手動で設定すると、リクエストの境界パラメーターを入力できなくなります。

Javascriptコード:

formData = new FormData();

formData.append("file", document.forms[formName].file.files[0]);
formData.append('properties', new Blob([JSON.stringify({
                "name": "root",
                "password": "root"                    
            })], {
                type: "application/json"
            }));

リクエストの詳細:

method: "POST",
headers: {
         "Content-Type": undefined
  },
data: formData

ペイロードのリクエスト:

Accept:application/json, text/plain, */*
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryEBoJzS3HQ4PgE1QB

------WebKitFormBoundaryvijcWI2ZrZQ8xEBN
Content-Disposition: form-data; name="file"; filename="myfile.txt"
Content-Type: application/txt


------WebKitFormBoundaryvijcWI2ZrZQ8xEBN
Content-Disposition: form-data; name="properties"; filename="blob"
Content-Type: application/json


------WebKitFormBoundaryvijcWI2ZrZQ8xEBN--

1
よくできました。私はprocessData: false, contentType: false一緒に使用しなければなりJQuery $ajax()
ませんでした

1
@ SunilKumar、ファイルのアップロードをオプションとして指定する必要がある場合..?フォームデータを使用します。これを行うにはどうすればよいですか。画像が選択されていない場合は取得中Required request part file is not present
Hema 2017年

1
私にとっては、「新しいBlob([JSON.stringify(...)]」の部分でそれができました。他のすべてが整っていました。Thx。
Ostati18年

4
@SunilKumar ConnectionPropertiesにConverterを指定する必要がありましたか?上記のようにConnectionPropertiesにpojoを使用すると、次のようになります... HttpMediaTypeNotSupportedException:コンテンツタイプ 'application / octet-stream'はサポートされていませんPOJOをStringに変更すると機能します。では、POJOへの変換がどのように行われているのか明確ではありませんか?
user24123 9819年

1
これを明確にするために:@NotBlankMultipartFileメソッドパラメーターの注釈は、ファイルが空であるかどうかを実際にはチェックしません。0バイトのドキュメントをアップロードすることは引き続き可能です。
sn 4219

14

これはうまくいくはずです!

クライアント(角度):

$scope.saveForm = function () {
      var formData = new FormData();
      var file = $scope.myFile;
      var json = $scope.myJson;
      formData.append("file", file);
      formData.append("ad",JSON.stringify(json));//important: convert to JSON!
      var req = {
        url: '/upload',
        method: 'POST',
        headers: {'Content-Type': undefined},
        data: formData,
        transformRequest: function (data, headersGetterFunction) {
          return data;
        }
      };

バックエンド-SpringBoot:

@RequestMapping(value = "/upload", method = RequestMethod.POST)
    public @ResponseBody
    Advertisement storeAd(@RequestPart("ad") String adString, @RequestPart("file") MultipartFile file) throws IOException {

        Advertisement jsonAd = new ObjectMapper().readValue(adString, Advertisement.class);
//do whatever you want with your file and jsonAd

1

ドキュメントが言うように:

名前で識別される「multipart / form-data」リクエストの一部が見つからない場合に発生します。

これは、パーツがリクエストに存在しないか、Webアプリケーションがマルチパートリクエストを処理するように正しく構成されていないため(MultipartResolverがないなど)、リクエストがマルチパート/フォームデータではないことが原因である可能性があります。


0

私たちのプロジェクトでは、JSONとファイルを使用したPOSTリクエストにより、フロントエンド開発者とバックエンド開発者の間で多くの混乱が生じ、不必要な時間の浪費につながることがわかりました。

より良いアプローチは次のとおりです。ファイルバイト配列をBase64文字列に変換し、JSONで送信します。

public Class UserDTO {
    private String firstName;
    private String lastName;
    private FileDTO profilePic; 
}

public class FileDTO {
    private String base64;
    // just base64 string is enough. If you want, send additional details
    private String name;
    private String type;
    private String lastModified;
}

@PostMapping("/user")
public String saveUser(@RequestBody UserDTO user) {
    byte[] fileBytes = Base64Utils.decodeFromString(user.getProfilePic().getBase64());
    ....
}

ファイルをbase64文字列に変換するJSコード:

var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function () {

  const userDTO = {
    firstName: "John",
    lastName: "Wick",
    profilePic: {
      base64: reader.result,
      name: file.name,
      lastModified: file.lastModified,
      type: file.type
    }
  }
  
  // post userDTO
};
reader.onerror = function (error) {
  console.log('Error: ', error);
};
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.