Spring Boot集成SpringFox 3.0与Pageable参数处理

Springfox 3.0有多个模块,提供了spring boot starter,与Spring Boot集成时仅需引入springfox-boot-starter,如下:

java 复制代码
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-boot-starter</artifactId>
    <version>3.0.0</version>
</dependency>

如果您以前使用了Springfox 2.x,需要修改一下Swagger配置:

删除@EnableSwagger2注解,改为@EnableOpenApi

将Docket中的参数DocumentationType.SWAGGER_2改为DocumentationType.OAS_30

Springfox 3.0删除了一些第三方模块,如有引用需要替换

修改后的配置如下:

java 复制代码
package com.ys.config;
import com.fasterxml.classmate.TypeResolver;
import org.itrunner.heroes.exception.ErrorMessage;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.ResponseEntity;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;

import java.time.LocalDate;
import java.util.List;

import static java.util.List.of;

@EnableOpenApi
@Configuration
public class SwaggerConfig {

    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.OAS_30)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.ys.controller"))
                .paths(PathSelectors.any())
                .build()
                .apiInfo(apiInfo())
                .pathMapping("/")
                .directModelSubstitute(LocalDate.class, String.class)
                .genericModelSubstitutes(ResponseEntity.class)
                .additionalModels(new TypeResolver().resolve(ErrorMessage.class))
                .useDefaultResponseMessages(false)
                .securitySchemes(of(authenticationScheme()))
                .securityContexts(of(securityContext()))
                .enableUrlTemplating(false);
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Api Documentation")
                .description("Api Documentation")
                .contact(new Contact("xx", "http://xxxxxx", "xxxxx@163.com"))
                .version("1.0.0")
                .build();
    }

    private HttpAuthenticationScheme authenticationScheme() {
        return HttpAuthenticationScheme.JWT_BEARER_BUILDER.name("BearerToken").build();
    }

    private SecurityContext securityContext() {
        return SecurityContext.builder()
                .securityReferences(defaultAuth())
                .operationSelector(operationContext ->
                        operationContext.requestMappingPattern().startsWith("/api/")
                )
                .build();
    }

    private List<SecurityReference> defaultAuth() {
        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        return of(new SecurityReference("BearerToken", authorizationScopes));
    }
}

上面我们使用了HttpAuthenticationScheme构建Bearer Token Authentication,在Swagger UI界面点击Authorize时直接输出token值即可。

Springfox 3.0的Swagger UI地址,从http://host/context-path/swagger-ui.html 改成了 http://host/context-path/swagger-ui/ ,OAS 3.0的api docs地址默认为/v3/api-docs,因此Security中的ignore path要进行相应修改。

Pageable参数

当REST API的方法含有org.springframework.data.domain.Pageable参数时,Springfox根据接口生成pageNumber、pageSize、offset、paged、unpaged、sort.sorted、sort.unsorted等参数,这与Spring Boot实际使用的参数是不一致的,因此需要针对Pageable参数进行特殊处理。

我们使用OperationBuilderPlugin处理Pageable参数,如下:

java 复制代码
package com.ys.config;
import com.fasterxml.classmate.ResolvedType;
import com.fasterxml.classmate.TypeResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;
import springfox.documentation.builders.RequestParameterBuilder;
import springfox.documentation.schema.ScalarType;
import springfox.documentation.service.ParameterType;
import springfox.documentation.service.RequestParameter;
import springfox.documentation.service.ResolvedMethodParameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.OperationBuilderPlugin;
import springfox.documentation.spi.service.contexts.OperationContext;

import java.util.ArrayList;
import java.util.List;

@Component
@Order
public class PageableParameterReader implements OperationBuilderPlugin {
    private final TypeResolver resolver;

    @Autowired
    public PageableParameterReader(TypeResolver resolver) {
        this.resolver = resolver;
    }

    @Override
    public void apply(OperationContext context) {
        List<ResolvedMethodParameter> methodParameters = context.getParameters();
        ResolvedType pageableType = resolver.resolve(Pageable.class);
        List<RequestParameter> parameters = new ArrayList<>();

        for (ResolvedMethodParameter methodParameter : methodParameters) {
            ResolvedType resolvedType = methodParameter.getParameterType();

            if (pageableType.equals(resolvedType)) {

                parameters.add(new RequestParameterBuilder()
                        .in(ParameterType.QUERY)
                        .name("page")
                        .query(q -> q.model(m -> m.scalarModel(ScalarType.INTEGER)))
                        .description("Results page you want to retrieve (0..N)").build());
                parameters.add(new RequestParameterBuilder()
                        .in(ParameterType.QUERY)
                        .name("size")
                        .query(q -> q.model(m -> m.scalarModel(ScalarType.INTEGER)))
                        .description("Number of records per page").build());
                parameters.add(new RequestParameterBuilder()
                        .in(ParameterType.QUERY)
                        .name("sort")
                        .query(q -> q.model(m -> m.collectionModel(c -> c.model(cm -> cm.scalarModel(ScalarType.STRING)))))
                        .description("Sorting criteria in the format: property(,asc|desc). "
                                + "Default sort order is ascending. "
                                + "Multiple sort criteria are supported.")
                        .build());
                context.operationBuilder().requestParameters(parameters);
            }
        }
    }

    @Override
    public boolean supports(DocumentationType delimiter) {
        return true;
    }

}

方案一:在Controller分页方法的Pageable参数前添加@ApiIgnore,忽略默认的参数解析:

复制代码
public ResponseEntity<List<DeviceDTO>> getAllDevices(@ApiIgnore @PageableDefault(sort = {"id"}, direction = Sort.Direction.DESC) Pageable pageable,
                                                     @RequestParam(required = false) @ApiParam(value = "关键字(序列号,地址,归属单位)") String keyword,

方案二:全局配置,在SwaggerConfig类的createRestApi方法中添加:.ignoredParameterTypes(Pageable.class)

java 复制代码
@EnableOpenApi
@Configuration
public class SwaggerConfig {

    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.OAS_30)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.ys.controller"))
                .paths(PathSelectors.any())
                .build()
                .apiInfo(apiInfo())
                .ignoredParameterTypes(Pageable.class)
                .pathMapping("/")
                .directModelSubstitute(LocalDate.class, String.class)
                .genericModelSubstitutes(ResponseEntity.class)
                .additionalModels(new TypeResolver().resolve(ErrorMessage.class))
                .useDefaultResponseMessages(false)
                .securitySchemes(of(authenticationScheme()))
                .securityContexts(of(securityContext()))
                .enableUrlTemplating(false);
    }

修改后Swagger UI中显示的Pageable参数如下:

相关推荐
WeiXin_DZbishe8 小时前
基于springboot宠物领养系统-计算机毕设 附源码【课程设计】94217
vue.js·spring boot·python·django·php·课程设计
架构技术专栏9 小时前
Agent 工具调用:从工具声明到执行反馈
前端·人工智能·后端
vx_bisheyuange9 小时前
基于SpringBoot的体育商品推荐系统
spring boot·毕业设计
码事漫谈9 小时前
你让AI干的活,它可能只干了十分之一——而你根本看不出来
后端
Wx-bishekaifayuan9 小时前
express皖美特色农产品网售系统53118-计算机课程设计、毕业设计
人工智能·spring boot·后端·python·课程设计·express·旅游
Wx-bishekaifayuan10 小时前
springboot汉中旅游服务平台41442-计算机课程设计、毕业设计
spring boot·后端·python·django·课程设计·express·旅游
WeiXin_DZbishe10 小时前
基于springboot城市公交实时运营与调度系统-计算机毕设 附源码【课程设计】66173
java·vue.js·spring boot·后端·python·php·课程设计
WeiXin_DZbishe11 小时前
基于Springboot+AI的kuall音乐广场的设计与实现-计算机毕设 附源码【课程设计】12715
vue.js·人工智能·spring boot·后端·python·php·课程设计
A接拉起00711 小时前
2026 年 JavaScript 开发者需要了解的知识
前端·javascript·后端
Bazingga11 小时前
RAG评测体系保姆级教程:生产级实践指南
后端