Spring Pageable接口

时间:2016-02-15 08:12:36

标签: json spring rest swagger

我使用Spring Boot开发了一个微服务。 REST API的文档是使用Swagger完成的。一些REST资源利用Spring概念免费提供分页。以下是一个例子:

@RequestMapping(value = "/buckets", method = GET)
public PagedResources list(Pageable pageable, PagedResourcesAssembler assembler) {
    return bucketService.listBuckets(pageable, assembler);
}

如果我打开Swagger页面,则资源可以使用以下表单:

enter image description here

我遇到的问题是使用内容类型 application / json 检测到可分页参数,并且我不知道如何传递值以更改页面大小。所有数值似乎都被忽略了。

是否可以将查询参数作为JSON对象传递?或者是否可以配置Swagger为Pageable接口包含的getter生成独立的查询参数字段?

请注意我使用的是带有Gradle的Springfox:

compile 'io.springfox:springfox-spring-web:2.3.1'
compile 'io.springfox:springfox-swagger2:2.3.1'
compile 'io.springfox:springfox-swagger-ui:2.3.1'

11 个答案:

答案 0 :(得分:24)

这是Spring-Fox的一个已知问题。请参阅问题#755。根据zdila的评论2,此时替代方法是添加@ApiImplicitParams,这不是理想的但它确实有效。

Process p = Runtime.getRuntime().exec("execution.exe --login user");
BufferedWriter writer = new BufferedWriter(
                    new OutputStreamWriter(p.getOutputStream()));
writer.write("mypassword\n");
writer.flush();
writer.close();
BufferedReader stdInput = new BufferedReader(new 
InputStreamReader(p.getInputStream()));

BufferedReader stdError = new BufferedReader(new 
                     InputStreamReader(p.getErrorStream()));

// read the output from the command
System.out.println("System returns message:\n");
String s = null;
while ((s = stdInput.readLine()) != null) {
        System.out.println(s);
}
// read any errors from the attempted command
    System.out.println("System returns error message:\n");
while ((s = stdError.readLine()) != null) {
    System.out.println(s);
}

[Swagger UI showing @ApiImplicitParams for Pageable]

1 https://github.com/springfox/springfox/issues/755

2 https://github.com/springfox/springfox/issues/755#issuecomment-135059871

答案 1 :(得分:7)

在Vineet Bhatia的回答基础上,您可以将解决方案包装在自定义注释中以获得可重用性:

@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@ApiImplicitParams({
    @ApiImplicitParam(name = "page", dataType = "int", paramType = "query", value = "Results page you want to retrieve (0..N)"),
    @ApiImplicitParam(name = "size", dataType = "int", 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.") })
@interface ApiPageable {
}

然后可以这样使用:

@ApiPageable
public Page<Data> getData(Pageable pageRequest) {

答案 2 :(得分:5)

Vineet Bhatia对@ApiImplicitParams的回答看起来不错。但是我遇到了情况,当@ApiIgnor@ApiParam(hidden = true)不起作用时,您仍然可以观察到整体和可分页的参数。我通过添加下一行

解决了这个问题
docket.ignoredParameterTypes(Pageable.class, PagedResourcesAssembler.class);

到我的SwaggerConfig中的Docket bean。

答案 3 :(得分:2)

如果您没有在localhost上运行,Vineet Bhatia的答案会有验证问题。它将争论整数参数,它们与json模式不对应。

所以我将整数更改为字符串:

    @ApiImplicitParams({
        @ApiImplicitParam(name = "page", dataType = "string", paramType = "query",
                value = "Results page you want to retrieve (0..N)"),
        @ApiImplicitParam(name = "size", dataType = "string", 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.")
})

答案 4 :(得分:2)

这是已集成到OpenAPI v3的springdoc-openapi-data-rest中的注释版本:

@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Parameter(in = ParameterIn.QUERY
        , description = "Zero-based page index (0..N)"
        , name = "page"
        , content = @Content(schema = @Schema(type = "integer", defaultValue = "0")))
@Parameter(in = ParameterIn.QUERY
        , description = "The size of the page to be returned"
        , name = "size"
        , content = @Content(schema = @Schema(type = "integer", defaultValue = "20")))
@Parameter(in = ParameterIn.QUERY
        , description = "Sorting criteria in the format: property(,asc|desc). "
        + "Default sort order is ascending. " + "Multiple sort criteria are supported."
        , name = "sort"
        , content = @Content(array = @ArraySchema(schema = @Schema(type = "string"))))
public @interface PageableAsQueryParam {

}

请参见https://springdoc.github.io/springdoc-openapi-demos/faq.html#how-can-i-map-pageable-spring-date-commons-object-to-correct-url-parameter-in-swagger-ui

答案 5 :(得分:1)

答案 6 :(得分:0)

尽管使用隐式参数的解决方案有效,但它引入了许多额外的易碎代码。最后,我们采用了以下解决方案:

@GetMapping(value = "/")
public HttpEntity<PagedResources<Item>> getItems(
    @RequestParam(value = "page", required = false) Integer page,
    @RequestParam(value = "size", required = false) Integer size,
    PagedResourcesAssembler assembler) {
    Page<Item> itemPage = itemService.listItems(PageRequest.of(page, size, Sort.unsorted()));
    return new ResponseEntity<>(assembler.toResource(itemPage), HttpStatus.OK);
}

我们将PageRequest(实现Pageable)传递给我们的服务,该服务返回一个Page。 (全部来自org.springframework.data.domain)。

org.springframework.data.web.PagedResourcesAssembler通过控制器方法自动注入,并允许将项目映射到org.springframework.hateoas.PagedResources

我们不需要动态排序,因此我们省略了它;由于springfox无法与org.springframework.data.domain.Sort配合使用,因此添加排序带来了一些挑战。

答案 7 :(得分:0)

Evgeny指出的验证问题的答案。

使用

@ApiImplicitParams({
    @ApiImplicitParam(name = "page", dataType = "int", paramType = "query", value = "Results page you want to retrieve (0..N)"),
    @ApiImplicitParam(name = "size", dataType = "int", 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.") })

引发异常:

Illegal DefaultValue  for parameter type integer
java.lang.NumberFormatException: For input string: ""
    at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:68)
    at java.base/java.lang.Long.parseLong(Long.java:709)
    at java.base/java.lang.Long.valueOf(Long.java:1151)
    at io.swagger.models.parameters.AbstractSerializableParameter.getExample(AbstractSerializableParameter.java:412)
    at jdk.internal.reflect.GeneratedMethodAccessor366.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:688)
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719)
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
    at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:119)
    at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serialize(IndexedListSerializer.java:79)

(至少它与springfox-swagger2和springfox-swagger2-ui版本2.9.2兼容)

您可以通过遵循Evgeny的回答或通过为整数参数添加默认值和示例值来避免异常:

@ApiImplicitParams({
    @ApiImplicitParam(name = "page", dataType = "int", paramType = "query", value = "Results page you want to retrieve (0..N)", defaultValue = "0", example = "2"),
    @ApiImplicitParam(name = "size", dataType = "int", paramType = "query", value = "Number of records per page.", defaultValue = "20", example = "10"),
    @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.") })

答案 8 :(得分:0)

此解决方案无需注释每个控制器中的每个API方法即可工作。首先,我们用正确的属性名称和描述({Kotlin代码,您可以使用Java接口)来创建Pageable类的替换:

data class SwaggerPageable(
        @ApiModelProperty("Number of records per page", example = "20")
        val size: Int?,

        @ApiModelProperty("Results page you want to retrieve (0..N)", example = "0")
        val page: Int?,

        @ApiModelProperty("Sorting criteria in the format: property(,asc|desc)." +
                "Default sort order is ascending. Multiple sort criteria are supported.")
        var sort: String?
)

然后在Swagger配置中,只需将Pageable的直接替代项添加到此类(同样是Kotlin代码,但是Java应该非常相似):

@Bean
fun api(): Docket {
    return Docket(DocumentationType.SWAGGER_2)
            .select()
            .paths(PathSelectors.any())
            .build()
            .directModelSubstitute(Pageable::class.java, SwaggerPageable::class.java)
}

结果如下:

enter image description here

缺点是无法在ApiModelProperty中定义默认值,但这对于我的项目已经足够了。

答案 9 :(得分:0)

Java示例:

Bean:

@Bean
public Docket api() {
    return new Docket(DocumentationType.SWAGGER_2)
        .select()
        .paths(PathSelectors.any())
        .build()
        .directModelSubstitute(Pageable.class, SwaggerPageable.class);
}

SwaggerPageable:

@Getter
private static class SwaggerPageable {

    @ApiParam(value = "Number of records per page", example = "0")
    @Nullable
    private Integer size;

    @ApiParam(value = "Results page you want to retrieve (0..N)", example = "0")
    @Nullable
    private Integer page;

    @ApiParam(value = "Sorting criteria in the format: property(,asc|desc). Default sort order is ascending. Multiple sort criteria are supported.")
    @Nullable
    private String sort;

}

大摇大摆:

enter image description here

答案 10 :(得分:0)

Open API 3.0 具有无缝集成。

例如

@GetMapping("/filter")
public Page<Employee> filterEmployees(Pageable pageable) {
     return repository.getEmployees(pageable);
}

添加 springdoc-openapi-data-rest 依赖

implementation 'org.springdoc:springdoc-openapi-data-rest:1.5.2'

注意:如果有多个参数,可以添加'@ParameterObject'

public Page<Employee> filterEmployees(@ParameterObject Pageable pageable)