Spring OpenAPI生成GET请求客户端时DTO参数序列化问题求助
解决Spring Boot OpenAPI生成WebClient时GET请求DTO参数拆分问题
方案一:调整springdoc + openapi-generator核心配置
直接在项目里做两处配置修改,就能让生成的客户端自动支持DTO转拆分后的查询参数:
- 后端
application.yml里开启springdoc的对象参数聚合:springdoc: default-flat-param-object: false - 调整
openapi-generator-maven-plugin的配置,启用DTO作为查询参数并自动展开:
后端接口保持用<plugin> <groupId>org.openapitools</groupId> <artifactId>openapi-generator-maven-plugin</artifactId> <version>请替换为最新稳定版</version> <executions> <execution> <goals> <goal>generate</goal> </goals> <configuration> <inputSpec>${project.basedir}/target/openapi.json</inputSpec> <generatorName>spring</generatorName> <configOptions> <library>webclient</library> <useSpringBoot3>true</useSpringBoot3> <!-- 关键:指定查询参数风格为form,自动展开DTO属性 --> <queryParamStyle>form</queryParamStyle> <explodeFormParameters>true</explodeFormParameters> </configOptions> <additionalProperties> <!-- 强制用DTO作为查询参数,不拆成单个属性 --> <additionalProperty>useDtoForQueryParams=true</additionalProperty> </additionalProperties> </configuration> </execution> </executions> </plugin>@ParameterObject标注DTO,生成的客户端方法会直接接受DTO参数,自动把非空属性拆成URI查询参数,后端也能正常解析。
方案二:给DTO加Schema注解明确参数风格
如果不想改全局配置,直接在DTO类上标注参数风格:
@Data // 明确告诉OpenAPI用form风格展开参数 @Schema(style = "form", explode = true) public class TicketSearchFilterDTO { private String ticketNo; private LocalDate startDate; // 其他30+属性... }
后端接口依然用@ParameterObject:
@GetMapping("/tickets") public ResponseEntity<List<TicketVO>> searchTickets(@ParameterObject TicketSearchFilterDTO filter) { // 业务逻辑 }
同时在openapi-generator的configOptions里加上:
<configOptions> <library>webclient</library> <queryParamStyle>form</queryParamStyle> </configOptions>
生成的客户端会自动处理DTO到查询参数的拆分,只传非空属性。
方案三:WebClient过滤器手动处理(后备方案)
如果前两个方案不生效,直接给生成的WebClient加个过滤器,手动把DTO转成查询参数:
@Bean public ExchangeFilterFunction dtoToQueryParamsFilter() { return (request, next) -> { ClientRequest.Builder requestBuilder = ClientRequest.from(request); // 从请求属性里拿到DTO参数(根据实际参数名调整) Optional<TicketSearchFilterDTO> filterOpt = request.attributes() .getOrDefault("filter", null) instanceof TicketSearchFilterDTO dto ? Optional.of(dto) : Optional.empty(); if (filterOpt.isPresent()) { TicketSearchFilterDTO dto = filterOpt.get(); // 把DTO转成Map,过滤空值 ObjectMapper mapper = new ObjectMapper(); Map<String, Object> paramMap = mapper.convertValue(dto, new TypeReference<>() {}); paramMap.entrySet().removeIf(entry -> entry.getValue() == null); // 替换URI里的查询参数 requestBuilder.uri(uri -> UriComponentsBuilder.fromUri(uri) .replaceQueryParams(MultiValueMap.fromMap(paramMap)) .build()); } return next.exchange(requestBuilder.build()); }; }
然后在生成的WebClient配置类里注入这个过滤器,客户端传DTO时就会自动拆分非空属性为查询参数。
内容的提问来源于stack exchange,提问作者Roman Vottner
相关产品推荐
相关产品推荐

