Spring MVC POST 请求包含多部分文件和其他 dto 的 dto
Spring MVC POST request with dto that contains multipart files and other dtos
我有一个包含其他 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));
}
}
这似乎是 springdoc-openapi-ui builds 表单数据请求的问题。我能够重现这一点并注意到它发送了一个多部分请求(通过浏览器的开发工具拦截):
-----------------------------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工单后,部分作者反馈如下:
[...] With spring, you can use @RequestPart spring annotation to describe
the different parts, with the related encoding media type. Note that
there is a limitation with the current swagger-ui implementation as
the encoding attribute is not respected on the request.[...]
他们还提供了一个可能的解决方法,如下所示:
@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;
}
我有一个包含其他 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));
}
}
这似乎是 springdoc-openapi-ui builds 表单数据请求的问题。我能够重现这一点并注意到它发送了一个多部分请求(通过浏览器的开发工具拦截):
-----------------------------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工单后,部分作者反馈如下:
[...] With spring, you can use @RequestPart spring annotation to describe the different parts, with the related encoding media type. Note that there is a limitation with the current swagger-ui implementation as the encoding attribute is not respected on the request.[...]
他们还提供了一个可能的解决方法,如下所示:
@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;
}