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

Ant*_*lev 9 java rest spring json multipartform-data

我知道如何创建使用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;
    }
Run Code Online (Sandbox Code Playgroud)

目前,如果我在以下邮递员请求的"原始"选项卡上添加一些JSON数据,我HTTP 415 Unsupported Media Type可能因为我指定我消费MULTIPART_FORM_DATA但我也在使用@RequestBody哪个正在寻找JSON内容APPLICATION_JSON.那么如何在同一个请求中处理JSON数据和文件呢?我知道可以在两个请求中执行此操作,如果可能,我只想在一个请求中执行此操作?

在此输入图像描述

Pau*_*tha 6

你为什么同时使用Spring和Jersey注释?您应该坚持使用适用于框架的注释.既然你使用泽西岛,应该坚持它注释.

因此,以下是您当前的代码和环境需要考虑的事项.

  1. 不能有两个独立的机构.使用您的代码,这就是您期望发生的事情.
  2. 可以将JSON作为多部分主体的一部分.为此,你还应该SomeModel用泽西岛注释@FormDataParam

    @POST
    @Path("somepath")
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    public Response uploadFileAndJSON(
             @FormDataParam("model") SomeModel someModel,
             @FormDataParam("file") FormDataBodyPart bodyPart) { 
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 在Jersey配置中,您需要确保注册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--
    
    Run Code Online (Sandbox Code Playgroud)

    如果Preview按下Postman中的按钮,您实际上可以看到身体.问题是,没有Content-Type"model"一部分,你可以在看"file"的部分.这是因为您无法Content-Type在Postman中设置单个部件.您将看到的那个将从文件扩展名中发现.例如,一个.txt文件将使Postman设置为Content-Typeto text/plain和一个.png文件image/png.

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

    在任何情况下,都Content-Type 必须设置,以便Jersey能够知道将其反序列化为JSON.如果.json文件扩展名理论并没有成功,那么你可以使用不同的客户端,像袅袅,这是我的链接显示一个例子,也可以使用Jersey客户端测试,因为看到这里.

  5. 不要在邮差中设置Content-Type标题multipart/form-data.当你使用它时它会为你设置form-data.我刚看到一个帖子,有人说你设置标题时有bug.现在找不到帖子,而不是我已经确认的帖子,但我只是把它留了出来.


UPDATE

所以OP 能够找到一种方法来设置Content-Type: application/json到"模式"的一部分.但有时使用Javascript客户端的情况下,您无法设置它.所以没有Content-Type.如果是这种情况,Jersey将无法反序列化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);
}
Run Code Online (Sandbox Code Playgroud)