swagger 如何配置springfox以展开React类型(如Mono和Flux),而无需在@ApiResponse中显式指定响应类型

1bqhqjot  于 2022-11-06  发布在  Spring
关注(0)|答案(3)|浏览(229)

我正在使用springfox 3.0.0进行响应式支持,并在我的swagger配置中使用@EnableSwagger2WebFlux
我的swagger配置如下:

@Bean
public Docket api() {
    return new Docket(DocumentationType.SWAGGER_2)
            .apiInfo(apiInfo())
            .select()
            .apis(RequestHandlerSelectors.basePackage(basePackage))
            .paths(PathSelectors.any())
            .build()
            .securityContexts(Lists.newArrayList(securityContext()))
            .securitySchemes(Lists.newArrayList(apiKey()))
            .globalOperationParameters(operationParameters());
}

我有一个简单的控制器,如下所示:

@CrossOrigin(origins = "*", allowedHeaders = "*", maxAge = 3600)
  @RestController
  @RequestMapping("/")
  public class ApiController {

    @ApiOperation(value = "get all partners", authorizations = {@Authorization(value = "Bearer")})
    @RequestMapping(value = "/partner",
            method = RequestMethod.GET,
            produces = {MediaType.APPLICATION_JSON_UTF8_VALUE}
    )
    @ApiResponses(value = {
            @ApiResponse(code = 200, message = "Request succeeded")
    })
    public Mono<ResponseEntity<Flux<PartnerDTO>>> getAllPartners(
            @ApiIgnore ServerHttpRequest httpRequest
    ) {
        return ...
    }

当springfox生成文档时,它具有以下类型:

而这种类型在我的API操作中是无用的:

我知道我可以通过在@ApiOperation中指定响应类型来解决这个问题,但我正在尝试避免这种情况,例如:

@ApiOperation(value = "get all partners", authorizations = {@Authorization(value = "Bearer")})
@RequestMapping(value = "/partner",
        method = RequestMethod.GET,
        produces = {MediaType.APPLICATION_JSON_UTF8_VALUE}
)
@ApiResponses(value = {
        @ApiResponse(code = 200, message = "Request succeeded", response = PartnerDTO.class)
})
public Mono<ResponseEntity<Flux<PartnerDTO>>> getAllPartners(
        @ApiIgnore ServerHttpRequest httpRequest
) {

我不喜欢这种方法,因为它是一个手动过程,因此容易出错。我想一些自动的方式来做下面的转换:

Flux<T> -> T[] (since flux emits 0...N elements)
Mono<T> -> T
ResponseEntity<T> -> T

当然,它必须是递归的(例如,Mono<ResponseEntity<Flux<T>>> -> T)。

gcxthw6b

gcxthw6b1#

我浏览了springfox的代码,试图找到一些自定义类型解析的入口点,幸运的是,它有一个可以从外部注入的HandlerMethodResolver
我在我的swagger config类中添加了这个解析器的自定义实现:

@Bean
@Primary
public HandlerMethodResolver fluxMethodResolver(TypeResolver resolver) {
    return new HandlerMethodResolver(resolver) {
        @Override
        public ResolvedType methodReturnType(HandlerMethod handlerMethod) {
            var retType = super.methodReturnType(handlerMethod);

            // we unwrap Mono, Flux, and as a bonus - ResponseEntity
            while (
                    retType.getErasedType() == Mono.class
                    || retType.getErasedType() == Flux.class
                    || retType.getErasedType() == ResponseEntity.class
            ) {
                if ( retType.getErasedType() == Flux.class ) {
                    // treat it as an array
                    var type = retType.getTypeBindings().getBoundType(0);
                    retType = new ResolvedArrayType(type.getErasedType(), type.getTypeBindings(), type);
                } else {
                    retType = retType.getTypeBindings().getBoundType(0);
                }
            }

            return retType;
        }
    };
}

这正是我所需要的。

它会自动将Mono<ResponseEntity<Flux<PartnerDTO>>>转换为PartnerDTO[],并将Mono<ResponseEntity<Mono<PartnerDTO>>>转换为PartnerDTO

EDIT::我更改了这个实现,将Flux转换为T[],因为它从一开始就应该是这样的。

7z5jn7bk

7z5jn7bk2#

你也可以按照Sprinfox的例子:

@Configuration
@EnableSwagger2WebFlux
public abstract class AbstractSwaggerConfiguration {

@Autowired
private TypeResolver resolver;

@Bean
public Docket api() {
    return new Docket(DocumentationType.SWAGGER_2) //
        .select().apis(RequestHandlerSelectors.any()).paths(PathSelectors.any()) //
        .build()
        .alternateTypeRules(new RecursiveAlternateTypeRule(resolver,
            Arrays.asList(AlternateTypeRules.newRule(resolver.resolve(Mono.class, WildcardType.class), resolver.resolve(WildcardType.class)),
                AlternateTypeRules.newRule(resolver.resolve(ResponseEntity.class, WildcardType.class), resolver.resolve(WildcardType.class)))))
        .alternateTypeRules(
            new RecursiveAlternateTypeRule(resolver, Arrays.asList(AlternateTypeRules.newRule(resolver.resolve(Flux.class, WildcardType.class), resolver.resolve(List.class, WildcardType.class)),
                AlternateTypeRules.newRule(resolver.resolve(ResponseEntity.class, WildcardType.class), resolver.resolve(WildcardType.class)))));
    }
}
m3eecexj

m3eecexj3#

Springfox,看起来是missed the boat。使用springdoc-openapi代替。我们还遇到了springfox的其他问题,不仅缺少webflux支持,而且我们很高兴地切换到了springdoc-openapi
对于webflux应用程序,您所需要的只是添加依赖项springdoc-openapi-webflux-ui

<dependency>
      <groupId>org.springdoc</groupId>
      <artifactId>springdoc-openapi-webflux-ui</artifactId>
      <version>1.6.9</version>
</dependency>

不需要额外的配置,MonoFlux将开箱即用。
还有一个如何从springfox迁移到springdoc-openapimanual
如果需要以编程方式自定义配置,请按如下方式定义OpenAPI Bean:

import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;

@Configuration
public class OpenApi30Config {
    @Bean
    public OpenAPI openApi() {
        return new OpenAPI()
           .info(new Info().title("My Application")
                .description("This is my application")
                .version("1.0")
            )
            // and lot of other configuration possible here
            ;
    }
}

相关问题