首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Springfox 3能否在OAS3 API文档中基于JSR 303 @Min/@Max生成整数边界?

Springfox 3能否在OAS3 API文档中基于JSR 303 @Min/@Max生成整数边界?
EN

Stack Overflow用户
提问于 2022-01-14 09:49:15
回答 1查看 151关注 0票数 0

我创建了一个Spring应用程序,它使用RestController验证传递给POST方法的DTO,该方法基于JSR 303验证注释。API文档是使用Springfox生成的。

验证是正确应用的,并显示在OAS2 API文档中。然而,它们在OAS3 API文档中是不完整的--不为Integer字段生成最小/最大边界。

我正在使用SpringBoot2.5.2(这很重要,因为最新版本2.6.2与Springfox有问题)和Springfox 3.0.0。

由于我在文档+ Springfox问题跟踪和JSR303支持中没有发现具体的提示,所以我认为这是Springfox OAS3支持中的一个bug或疏忽。与此同时,我找到了一个解决办法,如果我错过了什么,或者有更好的解决方案,我会很高兴听到这个答案的。

详细信息:

控制器

代码语言:javascript
复制
@Slf4j
@RestController
public class MyController {

    @PostMapping
    public void send(@Valid @RequestBody MyDTO dto) {
        log.info("{}", dto);
    }
}

DTO

代码语言:javascript
复制
@Value
public class MyDTO {
    @Size(max = 200)
    String text;

    @Max(2)
    @Min(1)
    Integer number;

    @Max(4)
    @Min(3)
    int number2;

    @Max(6)
    @Min(5)
    BigDecimal decimal;
}

OAS2 DTO模式(从http://localhost:8080/v2/api-docs中提取)

代码语言:javascript
复制
{
  "MyDTO": {
    "type": "object",
    "properties": {
      "decimal": {
        "type": "number",
        "minimum": 5,
        "maximum": 6,
        "exclusiveMinimum": false,
        "exclusiveMaximum": false
      },
      "number": {
        "type": "integer",
        "format": "int32",
        "minimum": 1,
        "maximum": 2,
        "exclusiveMinimum": false,
        "exclusiveMaximum": false
      },
      "number2": {
        "type": "integer",
        "format": "int32",
        "minimum": 3,
        "maximum": 4,
        "exclusiveMinimum": false,
        "exclusiveMaximum": false
      },
      "text": {
        "type": "string",
        "minLength": 0,
        "maxLength": 200
      }
    },
    "title": "MyDTO"
  }
}

OAS3 DTO模式(从http://localhost:8080/v3/api-docs中提取)

代码语言:javascript
复制
{
  "schemas": {
    "MyDTO": {
      "title": "MyDTO",
      "type": "object",
      "properties": {
        "decimal": {
          "maximum": 6,
          "exclusiveMaximum": false,
          "minimum": 5,
          "exclusiveMinimum": false,
          "type": "number",
          "format": "bigdecimal"
        },
        "number": {
          "type": "integer",
          "format": "int32"
        },
        "number2": {
          "type": "integer",
          "format": "int32"
        },
        "text": {
          "maxLength": 200,
          "minLength": 0,
          "type": "string"
        }
      }
    }
  }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-01-14 09:49:15

调试Springfox之后,我了解到springfox中的类springfox.documentation.oas.mappers.SchemaMapper将“通用模型”转换为OAS3格式。在“一般模型”中,字段边界由"NumericElementFacet“表示。正在映射的特定属性是"Schema“的子类。

问题似乎发生在这里:https://github.com/springfox/springfox/blob/bc9d0cad83e5dfdb30ddb487594fbc33fc1ba28c/springfox-oas/src/main/java/springfox/documentation/oas/mappers/SchemaMapper.java#L385

由"NumberSchema“表示的属性被正确地处理(例如BigDecimal),它们与"NumericElementFacet”的边界被应用。但是,整数字段(以及进一步的测试显示:也是短的和长的)是由"IntegerSchema“表示的,因为在那里不处理它,所以边界不会应用到结果的API中。

因此,作为解决办法,我所做的是子类SchemaMapper,对mapProperties的结果进行后处理,并将子类注册为@Primary来覆盖springfox组件:

代码语言:javascript
复制
import io.swagger.v3.oas.models.media.Schema;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import springfox.documentation.oas.mappers.*;
import springfox.documentation.schema.*;
import springfox.documentation.service.ModelNamesRegistry;

import java.util.*;

@Primary
@Component
@Slf4j
public class IntegerBoundarySupportingOasSchemaMapper extends SchemaMapper {
    @Override
    @SuppressWarnings("rawtypes")
    protected Map<String, Schema> mapProperties(
            Map<String, PropertySpecification> properties,
            ModelNamesRegistry modelNamesRegistry) {
        var result = super.mapProperties(properties, modelNamesRegistry);

        result.values()
                .stream()
                // "integer" seems to cover at least Java Short, Integer and Long.
                .filter(property -> "integer".equals(property.getType()))
                .forEach(property -> properties.get(property.getName())
                        .getFacets()
                        .stream()
                        .filter(NumericElementFacet.class::isInstance)
                        .map(NumericElementFacet.class::cast)
                        .findFirst()
                        .ifPresent(f -> {
                            log.trace("Adding boundaries to API field {} (min={}, max={})",
                                    property.getName(),
                                    f.getMinimum(),
                                    f.getMaximum());

                            property.setMaximum(f.getMaximum());
                            property.exclusiveMaximum(f.getExclusiveMaximum());
                            property.setMinimum(f.getMinimum());
                            property.exclusiveMinimum(f.getExclusiveMinimum());
                        }));

        return result;
    }
}

在我的例子中,这是很好的工作,所以也许它也能帮助别人。

附带注意:每次我检索SchemaMapper时都会调用http://localhost:8080/v3/api-docs,在考虑对模式进行其他耗时的修改时,可能要记住这一点。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70708724

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档