Spring: данные и файл JSON в одном запросе

Я знаю, как создавать конечные точки, которые обрабатывают файлы с помощью MediaType.MULTIPART_FORM_DATA и @FormDataParam("file") FormDataBodyPart bodyPart, но мне было интересно, могу ли я также иметь данные JSON по этому запросу? Что-то вроде:

    @POST
    @Path("somepath")
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    public Response uploadFileAndJSON(@RequestBody SomeModel someModel,
                                      @FormDataParam("file") FormDataBodyPart bodyPart) { 
         return null;
    }

на данный момент, если я добавлю некоторые данные JSON на вкладке "raw" на следующий запрос почтальона, я получаю HTTP 415 Unsupported Media Type вероятно, потому, что я указал, что я потребляю MULTIPART_FORM_DATA но я также использую @RequestBody который ищет контент JSON, который является APPLICATION_JSON. Итак, как я могу обрабатывать данные JSON и файл в той же просьбе? Я знаю, что это можно сделать в двух запросах, я просто хочу сделать это в одном, если это возможно?

enter image description here

2 ответов


почему вы используете аннотации Spring и Jersey? Вы должны придерживаться использования аннотаций, предназначенных для фреймворка. Поскольку вы используете Джерси, следует придерживаться его его Примечание.

Итак, вот что нужно учитывать о вашем текущем коде и среде.

  1. не может быть двух отдельных телах. С вашим кодом, похоже, именно этого вы и ожидаете.
  2. вы can хотя поместите JSON как часть многосоставного тела. Для этого вы также должны аннотировать SomeModel С @FormDataParam

    @POST
    @Path("somepath")
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    public Response uploadFileAndJSON(
             @FormDataParam("model") SomeModel someModel,
             @FormDataParam("file") FormDataBodyPart bodyPart) { 
    }
    
  3. в конфигурации Джерси вам нужно обязательно зарегистрировать MultiPartFeature. Если вы этого не сделаете, тело не сможет быть десериализовано, и вы получите исключения и ответы на ошибки.

  4. теперь проблема почтальона. Вы можете увидеть похожие проблемы здесь. Проблема заключалась в том, что Content-Type был не установлен для части тела JSON. Например, тело может выглядеть как

    --AaB03x
    Content-Disposition: form-data; name="model"
    
    {"some":"model", "data":"blah"}
    --AaB03x
    Content-Disposition: form-data; name="file"; filename="file1.txt"
    Content-Type: text/plain
    
    ... contents of file1.txt ...
    --AaB03x--
    

    вы можете увидеть тело, если вы нажмете предварительный просмотр кнопка в почтальоне. Проблема в том, что нет Content-Type на "model" часть, как вы можете видеть в разделе "file" часть. Это происходит потому, что вы не можете установить отдельные части' Content-Type в почтальона. Тот, который вы увидите, будет обнаружен из расширения файла. Например,.txt файл заставит почтальона установить Content-Type to text/plain и до image/png.

    если вы посмотрите в ссылке выше, я предложил, возможно, вы могли бы использовать .json файл вместо ввода данных. Конечно, это была только теория. На самом деле я его не проверял.

    в любом случае Content-Type должны быть установлен для того, чтобы Джерси мог знать десериализовать его как JSON. Если .json теория расширения файлов не работает, тогда вы можете использовать другой клиент, например cURL, который Я показал пример в ссылке, или вы можете использовать клиент Джерси для тестирования, как видно здесь.

  5. не устанавливайте до multipart/form-data в почтальона. Он устанавливает его для вас, когда вы используете форма-Сведения. Я только что видел сообщение, где кто-то сказал, что есть ошибка, когда вы устанавливаете заголовок. Не могу найти сообщение сейчас, и не то, что я подтвердил, но я бы просто оставил его из.


обновление

Итак, ОП был возможность найти способ установить Content-Type: application/json "модели" часть. Но иногда бывает так, что с клиентом Javascript вы не можете его установить. Так что не будет Content-Type. Если это так, Джерси не сможет десериализовать JSON, поскольку он понятия не имеет, что на самом деле отправляется JSON. Если вы абсолютно не можете или не знаете, как установить Content-Type для индивидуального части, вы можете прибегнуть к следующему.

@POST
@Path("somepath")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFileAndJSON(@FormDataParam("model") FormDataBodyPart jsonPart,
                                  @FormDataParam("file") FormDataBodyPart bodyPart) { 
     jsonPart.setMediaType(MediaType.APPLICATION_JSON_TYPE);
     SomeModel model = jsonPart.getValueAs(SomeModel.class);
}

Да, вы можете получить это как данные составной формы.

вы получаете это в angularjs:

$scope.uploadFile = function () {
                var file = $scope.selectedFile[0];
                $scope.upload = $upload.upload({
                    url: 'api/upload',
                    method: 'POST',
                    data: angular.toJson($scope.model),
                    file: file
                }).progress(function (evt) {
                    $scope.uploadProgress = parseInt(100.0 * evt.loaded / evt.total, 10);
                }).success(function (data) {
                    //do something
                });
            };

            $scope.onFileSelect = function ($files) {
                $scope.uploadProgress = 0;
                $scope.selectedFile = $files;
            };
public Response uploadFileAndJSON(@RequestParam("data") String data,
                                      @MultiPartFile("file")File file) { 
  you can data as form data and convert it 
  like you want to your object using Gson jar.       
 return null;
    }

посмотреть код в AngularJS : Angularjs как загрузить данные многостраничной формы и файл?

https://puspendu.wordpress.com/2012/08/23/restful-webservice-file-upload-with-jersey/