【问题标题】:Spring MVC POST request with dto that contains multipart files and other dtos带有包含多部分文件和其他 dto 的 dto 的 Spring MVC POST 请求
【发布时间】:2022-01-20 08:13:23
【问题描述】:

我有一个包含其他 DTO 和多部分文件列表的 DTO。我正在尝试处理该 DTO,但我似乎无法读取请求。

class TeacherDTO {
   private SpecializationDto specializationDto;
   private List<MultipartFile> files;
}

@PostMapping(consumes = {MediaType.MULTIPART_FORM_DATA_VALUE},
            produces = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<Object> saveNewTeacher(@ModelAttribute @Valid TeacherDTO teacherDto){

//process request

}

从 Swagger UI 创建示例请求时,我收到以下异常:

type 'java.lang.String' to required type 'SpecializationDto' for property 'specializationDto': no matching editors or conversion strategy found

如果我把 @RequestBody 而不是 @ModelAttribute 然后我得到

Content type 'multipart/form-data;boundary=----WebKitFormBoundaryVEgYwEbpl1bAOjAs;charset=UTF-8' not supported]

Swagger 依赖项:

<dependency>
   <groupId>org.springdoc</groupId>
   <artifactId>springdoc-openapi-ui</artifactId>
   <version>1.5.2</version>
</dependency>
<dependency>
   <groupId>org.springdoc</groupId>
   <artifactId>springdoc-openapi-data-rest</artifactId>
   <version>1.5.2</version>
</dependency>

OpenAPI3.0 配置:



@Configuration
public class OpenApi30Config {

  private final String moduleName;
  private final String apiVersion;

  public OpenApi30Config(
      @Value("${spring.application.name}") String moduleName,
      @Value("${api.version}") String apiVersion) {
    this.moduleName = moduleName;
    this.apiVersion = apiVersion;
  }

  @Bean
  public OpenAPI customOpenAPI() {
    final var securitySchemeName = "bearerAuth";
    final var apiTitle = String.format("%s API", StringUtils.capitalize(moduleName));
    return new OpenAPI()
        .addSecurityItem(new SecurityRequirement().addList(securitySchemeName))
        .components(
            new Components()
                .addSecuritySchemes(securitySchemeName,
                    new SecurityScheme()
                        .name(securitySchemeName)
                        .type(SecurityScheme.Type.HTTP)
                        .scheme("bearer")
                        .bearerFormat("JWT")
                )
        )
        .info(new Info().title(apiTitle).version(apiVersion));
  }
}

【问题讨论】:

  • 你是不是只从swagger客户端遇到这个问题?
  • 是的,我想让它与 swagger UI 一起工作
  • 您需要提供更多详细信息,包括招摇版本等,否则很难描述问题(如果有)。
  • @harry 更新了开放的 api 配置。我使用 Open API 3.0
  • 你在这里混合了两件事。发布 JSON 对象并发布多部分数据。我建议不要这样做。仅将多部分数据发布到某个端点

标签: java spring spring-boot spring-mvc multipartfile


【解决方案1】:

这似乎是 springdoc-openapi-ui 如何构建表单数据请求的问题。我能够重现这一点,并注意到它发送了一个多部分请求,例如(通过浏览器的开发工具拦截):

-----------------------------207598777410513073071314493349
Content-Disposition: form-data; name="specializationDto"\r\n\r\n{\r\n  "something": "someValue"\r\n}


-----------------------------207598777410513073071314493349
Content-Disposition: form-data; name="files"; filename="somefile.txt"
Content-Type: application/octet-stream

<content>

-----------------------------207598777410513073071314493349
Content-Disposition: form-data; name="files"; filename="somefile.txt"
Content-Type: application/octet-stream

<content>

使用该有效负载,Spring 无法反序列化 specializationDto,从而导致您观察到“未找到匹配的编辑器或转换策略”异常。但是,如果您通过邮递员或 curl 发送请求(请注意 specializationDto 对象的点符号)

curl --location --request POST 'http://localhost:8080/upload' \
--form 'files=@"/path/to/somefile"' \
--form 'files=@"/path/to/somefile"' \
--form 'specializationDto.something="someValue"'

然后 Spring 能够正确解析它。这是我的休息映射,它将按预期记录以下内容:

    @RequestMapping(value = "/upload", method = RequestMethod.POST, 
                    consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
    public void upload(@ModelAttribute TeacherDto requestDto) {
        System.out.println(requestDto);
    }


// logs:
TeacherDto(specializationDto=SpecializationDto(something=someValue), files=[org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile@78186ea6, org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile@461c9cbc])

我建议你在他们的 github page 上打开一个错误。

编辑:

OP开通github票后,以下是作者的部分反馈:

[...] 有了spring,可以使用@RequestPart spring注解来描述 不同的部分,具有相关的编码媒体类型。注意 当前的 swagger-ui 实​​现存在一个限制,因为 请求中不考虑编码属性。[...]

他们还提供了一种可能的解决方法,如下所示:

@PostMapping(consumes =  MediaType.MULTIPART_FORM_DATA_VALUE,
        produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Object> saveNewTeacher( @RequestPart(value = "specializationDto") @Parameter(schema =@Schema(type = "string", format = "binary"))  final SpecializationDto specializationDto,
        @RequestPart(value = "files")  final List<MultipartFile> files){
    return null;
}

【讨论】:

  • 感谢您的回复。我在他们的 github repo 上创建了一个错误,他们的回复在这里。鉴于您将其推向正确的方向,您能否用他们的回复编辑您的回复,以便我可以批准您的消息作为正确答案? github.com/springdoc/springdoc-openapi/issues/1416
  • 完成 :) 很高兴听到至少有一种解决方法。
猜你喜欢
  • 2020-06-23
  • 2017-01-04
  • 2019-10-04
  • 2014-02-15
  • 1970-01-01
  • 2020-06-26
  • 2023-01-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多