关于java:Spring:JSON数据和文件在同一个请求中

Spring: JSON data and file in the same request

我知道如何创建使用MediaType.MULTIPART_FORM_DATA@FormDataParam("file") FormDataBodyPart bodyPart处理文件的端点,但我想知道是否也可以在该请求中使用JSON数据?比如:

1
2
3
4
5
6
7
    @POST
    @Path("somepath")
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    public Response uploadFileAndJSON(@RequestBody SomeModel someModel,
                                      @FormDataParam("file") FormDataBodyPart bodyPart) {
         return null;
    }

现在,如果我在下面的邮差请求的"原始"选项卡上添加一些JSON数据,我将获取HTTP 415 Unsupported Media Type,可能是因为我指定使用MULTIPART_FORM_DATA,但我也使用@RequestBody,它正在查找APPLICATION_JSON的JSON内容。那么,如何在同一个请求中处理JSON数据和文件呢?我知道在两个请求中可以做到这一点,如果可能的话,我只想在一个请求中做到这一点?

enter image description here


为什么要同时使用Spring和Jersey注释?您应该坚持使用框架的注释。既然您使用的是泽西,那么应该坚持使用它的注释。

下面是关于当前代码和环境的一些考虑事项。

  • 不能有两个分开的身体。对于您的代码,这就是您期望发生的事情。
  • 您可以将JSON作为多部分主体的一部分。为此,您还应在SomeModel上加上泽西岛@FormDataParam

    1
    2
    3
    4
    5
    6
    7
    @POST
    @Path("somepath")
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    public Response uploadFileAndJSON(
             @FormDataParam("model") SomeModel someModel,
             @FormDataParam("file") FormDataBodyPart bodyPart) {
    }

  • 在Jersey配置中,您需要确保注册MultiPartFeature。如果不这样做,主体将无法反序列化,并且您将得到异常和错误响应。

  • 现在是邮递员的问题。你可以在这里看到类似的问题。问题是,没有为JSON主体部分设置Content-Type。例如,尸体可能看起来像

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    --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--

    如果你点击邮差中的preview按钮,你实际上可以看到尸体。问题是,正如你在"file"部分看到的那样,"model"部分没有Content-Type。这是因为您不能在Postman中设置单个零件的"EDOCX1"(3)。您将看到的那个将从文件扩展名中发现。例如,一个.txt文件将使postman将Content-Type设置为text/plain,一个.png文件设置为image/png

    如果您查看上面的链接,我建议您可以使用.json文件,而不是键入数据。当然,那只是一个理论。实际上我没有测试它。

    在任何情况下,为了让Jersey能够知道将其反序列化为JSON,必须设置Content-Type。如果.json文件扩展理论不适用,那么您可以使用不同的客户机,比如curl,我在链接中展示了一个示例,或者您可以使用Jersey客户机进行测试,如图所示。

  • 不要在Postman中将Content-Type头设置为multipart/form-data。当您使用form data时,它会为您设置它。我刚看到一个帖子,上面有人说当你设置标题时有bug。现在找不到这个帖子,也没有我确认的内容,但我还是把它放在一边。

  • 更新

    因此,操作人员能够找到一种方法将Content-Type: application/json设置为"模型"部分。但有时在使用JavaScript客户机时,您无法设置它。所以不会有Content-Type。如果是这种情况,Jersey将无法反序列化JSON,因为它不知道实际发送的是JSON。如果您完全不知道或不知道如何为单个部件设置Content-Type,您可以采取以下操作。

    1
    2
    3
    4
    5
    6
    7
    8
    @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);
    }


    是的,您可以将其作为多部分表单数据。

    在安古拉吉斯你会得到这样的结果:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    $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如何上传多部分表单数据和文件?

    RESTFul Webservice: File Upload with Jersey