[英]Can Springfox 3 generate Integer boundaries based on JSR 303 @Min/@Max in OAS3 API docs?
我創建了一個帶有 RestController 的 Spring 引導應用程序,該應用程序根據 JSR 303 驗證注釋驗證傳遞給 POST 方法的 DTO。 API 文檔是使用 Springfox 生成的。
驗證已正確應用並顯示在 OAS2 API 文檔中。 然而,它們在 OAS3 API 文檔中是不完整的 - 沒有為 Integer 字段生成最小/最大邊界。
我正在使用 Spring Boot 2.5.2(這很重要,因為最新版本 2.6.2 與 Springfox 存在問題)和 Springfox 3.0.0。
由於我在文檔 + Springfox 問題跟蹤中沒有發現任何具體提示,並且 JSR303 支持大部分都在起作用,我認為這是 Springfox OAS3 支持中的錯誤或疏忽。 與此同時,我找到了一個解決方法,我將把它作為答案發布——如果我遺漏了什么或者有更好的解決方案,我會很高興聽到這個消息。
細節:
Controller
@Slf4j
@RestController
public class MyController {
@PostMapping
public void send(@Valid @RequestBody MyDTO dto) {
log.info("{}", dto);
}
}
DTO
@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)
{
"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 中提取)
{
"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"
}
}
}
}
}
調試 Springfox 后,我了解到 springfox- springfox.documentation.oas.mappers.SchemaMapper
中的 class springfox.documentation.oas.mappers.SchemaMapper 將“通用模型”轉換為 OAS3 的格式。 在“通用模型”中,字段邊界由“NumericElementFacet”表示。 正在映射的特定屬性是“Schema”的子類。
由“NumberSchema”表示的屬性被正確處理(例如 BigDecimal),它們來自“NumericElementFacet”的邊界被應用。 然而,Integer 字段(以及進一步的測試表明:也短和長)由“IntegerSchema”表示,它沒有在那里處理,因此邊界不適用於生成的 API。
所以我作為一種解決方法所做的是將 SchemaMapper 子類化,對mapProperties
的結果進行后處理並將子類注冊為 @Primary 以覆蓋 springfox 組件:
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;
}
}
就我而言,這很好用,所以也許它也可以幫助其他人。
旁注:每次我檢索 http://localhost:8080/v3/api-docs 時都會調用 SchemaMapper,這在考慮對模式進行其他耗時的修改時可能需要牢記。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.