千家信息网

Spring Boot集成SpringFox Swagger的Pageable参数问题

发表于:2026-10-31 作者:千家信息网编辑
千家信息网最后更新 2026年10月31日,Spring Boot项目中常使用springfox-swagger来生成REST API文档,使用springfox-swagger-ui进行API测试。 io.springfox sp
千家信息网最后更新 2026年10月31日Spring Boot集成SpringFox Swagger的Pageable参数问题

Spring Boot项目中常使用springfox-swagger来生成REST API文档,使用springfox-swagger-ui进行API测试。

    io.springfox    springfox-swagger2    2.8.0    io.springfox    springfox-swagger-ui    2.8.0

REST API方法的参数含有org.springframework.data.domain.Pageable时,如未进行其它配置,Swagger根据接口Pageable的get/is方法生成了pageNumber、pageSize、offset、paged、unpaged、sort.sorted、sort.unsorted等参数,但实际上这些参数是无效的。

@ApiOperation(value = "Find airlines")@GetMapping(value = "/airlines")public Page searchAirlines(Airline airline, Pageable pageable) {    return repository.findAll(org.springframework.data.domain.Example.of(airline), pageable); }

Spring Boot解析Pageable参数的过程请查看org.springframework.data.web.PageableHandlerMethodArgumentResolver的resolveArgument()方法:

@Overridepublic Pageable resolveArgument(MethodParameter methodParameter, @Nullable ModelAndViewContainer mavContainer,        NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) {    assertPageableUniqueness(methodParameter);    Optional defaultOrFallback = getDefaultFromAnnotationOrFallback(methodParameter).toOptional();    String pageString = webRequest.getParameter(getParameterNameToUse(pageParameterName, methodParameter));    String pageSizeString = webRequest.getParameter(getParameterNameToUse(sizeParameterName, methodParameter));    Optional page = parseAndApplyBoundaries(pageString, Integer.MAX_VALUE, true);    Optional pageSize = parseAndApplyBoundaries(pageSizeString, maxPageSize, false);    if (!(page.isPresent() && pageSize.isPresent()) && !defaultOrFallback.isPresent()) {        return Pageable.unpaged();    }    int p = page.orElseGet(() -> defaultOrFallback.map(Pageable::getPageNumber).orElseThrow(IllegalStateException::new));    int ps = pageSize.orElseGet(() -> defaultOrFallback.map(Pageable::getPageSize).orElseThrow(IllegalStateException::new));    // Limit lower bound    ps = ps < 1 ? defaultOrFallback.map(Pageable::getPageSize).orElseThrow(IllegalStateException::new) : ps;    // Limit upper bound    ps = ps > maxPageSize ? maxPageSize : ps;    Sort sort = sortResolver.resolveArgument(methodParameter, mavContainer, webRequest, binderFactory);    return PageRequest.of(p, ps,            sort.isSorted() ? sort : defaultOrFallback.map(Pageable::getSort).orElseGet(Sort::unsorted));}

其中使用的参数名称为page、size、sort,因此通过Swagger传入的参数是无效的。解决方法有以下几种:

@ApiImplicitParams

使用@ApiImplicitParams隐式添加page、size、sort参数,使用@ApiIgnore忽略Pageable参数。缺点,每个方法都要添加,比较繁琐。

@ApiOperation(value = "Find airlines")@ApiImplicitParams({    @ApiImplicitParam(name = "page", dataType = "integer", paramType = "query", value = "Results page you want to retrieve (0..N)"),    @ApiImplicitParam(name = "size", dataType = "integer", paramType = "query", value = "Number of records per page."),    @ApiImplicitParam(name = "sort", allowMultiple = true, dataType = "string", paramType = "query",        value = "Sorting criteria in the format: property(,asc|desc). Default sort order is ascending. Multiple sort criteria are supported.")})@GetMapping(value = "/airlines")public Page searchAirlines(Airline airline, @ApiIgnore Pageable pageable) {    return repository.findAll(org.springframework.data.domain.Example.of(airline), pageable);}

OperationBuilderPlugin

添加OperationBuilderPlugin组件,遇到Pageable时自动添加page、size、sort参数,同时也需使用@ApiIgnore忽略Pageable参数。

import com.fasterxml.classmate.ResolvedType;import com.fasterxml.classmate.TypeResolver;import com.google.common.base.Function;import java.util.List;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.core.Ordered;import org.springframework.core.annotation.Order;import org.springframework.data.domain.Pageable;import org.springframework.stereotype.Component;import springfox.documentation.builders.ParameterBuilder;import springfox.documentation.schema.ResolvedTypes;import springfox.documentation.schema.TypeNameExtractor;import springfox.documentation.schema.ModelReference;import springfox.documentation.service.Parameter;import springfox.documentation.service.ResolvedMethodParameter;import springfox.documentation.spi.DocumentationType;import springfox.documentation.spi.schema.contexts.ModelContext;import springfox.documentation.spi.service.OperationBuilderPlugin;import springfox.documentation.spi.service.contexts.OperationContext;import springfox.documentation.spi.service.contexts.ParameterContext;import static com.google.common.collect.Lists.newArrayList;import static springfox.documentation.spi.schema.contexts.ModelContext.inputParam;@Component@Order(Ordered.LOWEST_PRECEDENCE)public class PageableParameterReader implements OperationBuilderPlugin {    private final TypeNameExtractor nameExtractor;    private final TypeResolver resolver;    private final ResolvedType pageableType;    @Autowired    public PageableParameterReader(TypeNameExtractor nameExtractor, TypeResolver resolver) {        this.nameExtractor = nameExtractor;        this.resolver = resolver;        this.pageableType = resolver.resolve(Pageable.class);    }    @Override    public void apply(OperationContext context) {        List methodParameters = context.getParameters();        List parameters = newArrayList();        for (ResolvedMethodParameter methodParameter : methodParameters) {            ResolvedType resolvedType = methodParameter.getParameterType();            if (pageableType.equals(resolvedType)) {                ParameterContext parameterContext = new ParameterContext(methodParameter,                        new ParameterBuilder(),                        context.getDocumentationContext(),                        context.getGenericsNamingStrategy(),                        context);                Function factory = createModelRefFactory(parameterContext);                ModelReference intModel = factory.apply(resolver.resolve(Integer.TYPE));                ModelReference stringModel = factory.apply(resolver.resolve(List.class, String.class));                parameters.add(new ParameterBuilder()                        .parameterType("query")                        .name("page")                        .modelRef(intModel)                        .description("Results page you want to retrieve (0..N)").build());                parameters.add(new ParameterBuilder()                        .parameterType("query")                        .name("size")                        .modelRef(intModel)                        .description("Number of records per page").build());                parameters.add(new ParameterBuilder()                        .parameterType("query")                        .name("sort")                        .modelRef(stringModel)                        .allowMultiple(true)                        .description("Sorting criteria in the format: property(,asc|desc). "                                + "Default sort order is ascending. "                                + "Multiple sort criteria are supported.")                        .build());                context.operationBuilder().parameters(parameters);            }        }    }    @Override    public boolean supports(DocumentationType delimiter) {        return true;    }    private Function createModelRefFactory(ParameterContext context) {        ModelContext modelContext = inputParam(                context.getGroupName(),                context.resolvedMethodParameter().getParameterType(),                context.getDocumentationType(),                context.getAlternateTypeProvider(),                context.getGenericNamingStrategy(),                context.getIgnorableParameterTypes());        return ResolvedTypes.modelRefFactory(modelContext, nameExtractor);    }}

AlternateTypeRuleConvention

import com.fasterxml.classmate.TypeResolver;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.core.Ordered;import org.springframework.data.domain.Pageable;import springfox.documentation.builders.AlternateTypeBuilder;import springfox.documentation.builders.AlternateTypePropertyBuilder;import springfox.documentation.schema.AlternateTypeRule;import springfox.documentation.schema.AlternateTypeRuleConvention;import java.lang.reflect.Type;import java.util.List;import static com.google.common.collect.Lists.newArrayList;import static springfox.documentation.schema.AlternateTypeRules.newRule;@Configuration@SuppressWarnings("SpringJavaAutowiringInspection")public class SpringDataConfiguration {    @Bean    public AlternateTypeRuleConvention pageableConvention(final TypeResolver resolver) {        return new AlternateTypeRuleConvention() {            @Override            public int getOrder() {                return Ordered.LOWEST_PRECEDENCE;            }            @Override            public List rules() {                return newArrayList(newRule(resolver.resolve(Pageable.class), resolver.resolve(pageableMixin())));            }        };    }    private Type pageableMixin() {        return new AlternateTypeBuilder()                .fullyQualifiedClassName(String.format("%s.generated.%s", Pageable.class.getPackage().getName(), Pageable.class.getSimpleName()))                .withProperties(newArrayList(property(Integer.class, "page"), property(Integer.class, "size"), property(String.class, "sort")))                .build();    }    private AlternateTypePropertyBuilder property(Class type, String name) {        return new AlternateTypePropertyBuilder()                .withName(name)                .withType(type)                .withCanRead(true)                .withCanWrite(true);    }}

这是springfox文档中介绍的方法,这种方法创建了一个in-memory type,但我未找到添加说明的方法。可以自定义一个Page class:

import com.fasterxml.classmate.TypeResolver;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.core.Ordered;import org.springframework.data.domain.Pageable;import springfox.documentation.schema.AlternateTypeRule;import springfox.documentation.schema.AlternateTypeRuleConvention;import java.util.List;import static com.google.common.collect.Lists.newArrayList;import static springfox.documentation.schema.AlternateTypeRules.newRule;@Configuration@SuppressWarnings("SpringJavaAutowiringInspection")public class SpringDataConfiguration {    @Bean    public AlternateTypeRuleConvention pageableConvention(final TypeResolver resolver) {        return new AlternateTypeRuleConvention() {            @Override            public int getOrder() {                return Ordered.HIGHEST_PRECEDENCE;            }            @Override            public List rules() {                return newArrayList(newRule(resolver.resolve(Pageable.class), resolver.resolve(Page.class)));            }        };    }    @ApiModel    static class Page {        @ApiModelProperty("Results page you want to retrieve (0..N)")        private Integer page;        @ApiModelProperty("Number of records per page")        private Integer size;        @ApiModelProperty("Sorting criteria in the format: property(,asc|desc). Default sort order is ascending. Multiple sort criteria are supported.")        private List sort;        public Integer getPage() {            return page;        }        public void setPage(Integer page) {            this.page = page;        }        public Integer getSize() {            return size;        }        public void setSize(Integer size) {            this.size = size;        }        public List getSort() {            return sort;        }        public void setSort(List sort) {            this.sort = sort;        }    }}

参考文档

Swagger IO
Swagger Github
Tools and Integrations
SpringFox

参数 方法 文档 生成 中常 繁琐 同时 名称 实际 实际上 接口 组件 缺点 过程 这是 项目 参考 测试 配置 问题 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 小米移动互联网科技园 广州百单互联网科技有限公司 科技服务与互联网 互联网科技股票 齐家互联网科技 时间互联网络科技 科技互联网创业计划书 汉立互联网科技有限公司联系电话 互联网科技公司的市场部门 银川新华互联网科技学校地址 深圳市运趣互联网科技有限公司 广州优美互联网科技 港股科技和互联网 彤创互联网科技有限公司 速维有品互联网信息科技(苏州)有限公司 燊美集互联网科技有限公司 互联网公司黑科技创始人 长沙茂晟互联网科技有限公司 互联网科技对化妆品行业 上海旺乐尼互联网科技有限公司 湖南永感互联网科技有限公司 金诺互联网科技 互联网最新的科技有限公司 互联网科技上市公司 国外互联网科技网站 富国互联网科技创新基金 互联网科技商业 宇信科技在杭州互联网排第几 广州有谷有贝互联网科技有限公司 科技互联网专业务虚会材料
0