web-dev-qa-db-ja.com

混合マルチパートリクエストを伴う@ RequestPart、Spring MVC 3.2

Spring 3.2に基づいてRESTfulサービスを開発しています。混合マルチパートHTTPリクエストを処理するコントローラーの問題に直面しています。XMLまたはJSON形式のデータを含む2番目の部分と、画像ファイルを含む2番目の部分です。

リクエストの受信に @ RequestPartアノテーション を使用しています

@RequestMapping(value = "/User/Image", method = RequestMethod.POST,  consumes = {"multipart/mixed"},produces="applcation/json")

public
ResponseEntity<List<Map<String, String>>> createUser(
        @RequestPart("file") MultipartFile file, @RequestPart(required=false) User user) {

    System.out.println("file" + file);

    System.out.println("user " + user);

    System.out.println("received file with original filename: "
            + file.getOriginalFilename());

    // List<MultipartFile> files = uploadForm.getFiles();
    List<Map<String, String>> response = new ArrayList<Map<String, String>>();
    Map<String, String> responseMap = new HashMap<String, String>();

    List<String> fileNames = new ArrayList<String>();

    if (null != file) {
        // for (MultipartFile multipartFile : files) {

        String fileName = file.getOriginalFilename();
        fileNames.add(fileName);

        try {
            file.transferTo(new File("C:/" + file.getOriginalFilename()));
        } catch (IllegalStateException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    responseMap.put("displayText", file.getOriginalFilename());
    responseMap.put("fileSize", "" + file.getSize());
    response.add(responseMap);

    HttpHeaders httpHeaders = new HttpHeaders();
    httpHeaders.add("Accept", "application/json");
    return new ResponseEntity<List<Map<String, String>>>(response,
            httpHeaders, HttpStatus.OK);

}

User.Javaは次のようになります-

@XmlRootElement(name = "User")


public class User implements Serializable { 
    private static final long serialVersionUID = 1L;

    private int userId;
    private String name;
    private String email;

    private String company;
    private String gender;

    //getter setter of the data members
}

私の理解では、@ RequestPartアノテーションを使用すると、XMLマルチパートセクションがそのContent-Typeに応じて評価され、最後にユーザークラスに非整列化されることが期待されます(私はJaxb2を使用しており、marshaller/unmarhallerは本文としてXMLデータを渡して@RequestBodyアノテーションを使用すると、アプリケーションコンテキストとプロシージャが他のすべてのコントローラーメソッドで正常に機能します。

しかし実際に起こっていることは、ファイルが正しく検出され、MultipartFileとして解析されても、「ユーザー」の部分は表示されず、リクエストは常に失敗し、コントローラーのメソッドシグネチャと一致しないということです。

複数のクライアントタイプで問題を再現しましたが、マルチパートリクエストのフォーマットは問題ないと確信しています。

この問題を解決するために私を助けてください、多分混合/マルチパートのリクエストを受け取るための回避策があるかもしれません。

よろしくお願いいたします。

ラグベンドラ

16
Raghvendra

私はなんとか問題を解決しました

エンドポイントの例:

@PostMapping("/")
public Document create(@RequestPart Document document,
                       @RequestPart(required = false) MultipartFile file) {
    log.debug("#create: document({}), file({})", delegation, file);
    //custom logic
    return document;
}

例外:

"error_message": "Content type 'application/octet-stream' not supported"

次のメソッドから例外がスローされます:

org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(HttpInputMessage,MethodParameter,Type)

ソリューション:

HttpMessageConverterまたはHttpMessageConverterを実装し、MediaTypeを認識するカスタムコンバーター@Componentを作成する必要があります。 APPLICATION_OCTET_STREAM。単純な回避策については、を拡張するだけで十分です。AbstractJackson2HttpMessageConverter

@Component
public class MultipartJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter {

/**
 * Converter for support http request with header Content-Type: multipart/form-data
 */
public MultipartJackson2HttpMessageConverter(ObjectMapper objectMapper) {
    super(objectMapper, MediaType.APPLICATION_OCTET_STREAM);
}

@Override
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
    return false;
}

@Override
public boolean canWrite(Type type, Class<?> clazz, MediaType mediaType) {
    return false;
}

@Override
protected boolean canWrite(MediaType mediaType) {
    return false;
}
}
14
Maksim

問題を修正したかどうかはわかりませんが、@ RequestPartとMultipartFileを混在させると、JSONオブジェクトがコントローラーに取得されないという同様の問題も発生しました。

呼び出しのメソッドシグネチャは正しいように見えます。

public ResponseEntity<List<Map<String, String>>> createUser(
        @RequestPart("file") MultipartFile file, @RequestPart(required=false) User user) {

// ... CODE ... 
}

ただし、リクエストが次のようになっていることを確認してください。

POST /createUser
Content-Type: multipart/mixed; boundary=B0EC8D07-EBF1-4EA7-966C-E492A9F2C36E

--B0EC8D07-EBF1-4EA7-966C-E492A9F2C36E
Content-Disposition: form-data; name="user";
Content-Type: application/xml; charset=UTF-8

<user><!-- your user xml --></user>
--B0EC8D07-EBF1-4EA7-966C-E492A9F2C36E
Content-Disposition: form-data; name="file"; filename="A551A700-46D4-470A-86E7-52AD2B445847.dat"
Content-Type: application/octet-stream

/// FILE DATA
--B0EC8D07-EBF1-4EA7-966C-E492A9F2C36E--

私は問題を解決することができました:

    @SuppressWarnings("rawtypes")
@RequestMapping(value = "/DataTransfer", method = RequestMethod.POST, produces = {
        MediaType.APPLICATION_JSON_UTF8_VALUE }, consumes = {  MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_JSON_UTF8_VALUE} )
@ApiOperation(value = "Sbm Data Transfer Service", response = Iterable.class)
@ApiResponses(value = { @ApiResponse(code = 200, message = "Successfully find."),
        @ApiResponse(code = 400, message = "There has been an error."),
        @ApiResponse(code = 401, message = "You are not authorized to save the resource"),
        @ApiResponse(code = 403, message = "Accessing the resource you were trying to reach is forbidden"),
        @ApiResponse(code = 404, message = "The resource you were trying to reach is not found") })
ResponseEntity processDataTransfer(@RequestPart(name="file") MultipartFile  file, @RequestPart(name="param") DataTransferInputDto param);
0

Org.springframework.web.bind.annotation.RequestPartの@RequestPartを使用できます。 @RequestBodyとファイルアップロードの組み合わせとして使用されます。

このような@RequestParam( "file")MultipartFileファイルを使用すると、ファイルと複数の単一データ(キー値)のみをアップロードできます

    @RequestMapping(value = "/uploadFile", method = RequestMethod.POST,  consumes = { MediaType.MULTIPART_FORM_DATA_VALUE }, produces = { MediaType.APPLICATION_JSON_VALUE })
    public void saveFile(
                         @RequestParam("userid") String userid,
                         @RequestParam("file") MultipartFile file) {

    }

あなたは@RequestPartを使用してJSONオブジェクトデータとファイルの両方を投稿することができます

    @RequestMapping(value = "/patientp", method = RequestMethod.POST,  consumes = { MediaType.MULTIPART_FORM_DATA_VALUE }, produces = { MediaType.APPLICATION_JSON_VALUE })
public ResponseEntity<?> insertPatientInfo(
                                            @RequestPart PatientInfoDTO patientInfoDTO,
                                            @RequestPart("file") MultipartFile file) {
}

マルチパートファイルのアップロードをコントローラーメソッドのパラメーターとして直接使用することに限定されません。フォームオブジェクトにはPartフィールドまたはMultipartFileフィールドを含めることができ、Springはファイルパーツから値を取得し、値を適切に変換する必要があることを自動的に認識します。

上記のメソッドは、単一のファイルを含む以前に示されたマルチパート要求に応答できます。これは、Springにファイルパーツを認識するHTTPメッセージコンバーターが組み込まれているため機能します。 javax.servlet.http.Partタイプに加えて、ファイルのアップロードをorg.springframework.web.multipart.MultipartFileに変換することもできます。 2番目のマルチパートリクエストで示されているように、ファイルフィールドで複数のファイルのアップロードが許可されている場合は、配列またはパーツのコレクションまたはマルチパートファイルを使用するだけです。

        @RequestMapping(value = "/patientp", method = RequestMethod.POST,  consumes = { MediaType.MULTIPART_FORM_DATA_VALUE }, produces = { MediaType.APPLICATION_JSON_VALUE })
    public ResponseEntity<?> insertPatientInfo(
                                                @RequestPart PatientInfoDTO patientInfoDTO,
                                                @RequestPart("files") List<MultipartFile> files) {
    }

お力になれて、嬉しいです...

0
Pramod Wayabase