搜索 K
Appearance
Appearance
SchemaBuilder、ExampleDataGenerator、SwaggerConstants 三个类承担「schema 怎么造、示例怎么填、常量从哪来」三件事。
三者都是 final class + 私有构造,禁止实例化。
public static ObjectSchema buildResultSchema(Schema<?> dataSchema, String originalName) {
ObjectSchema resultSchema = new ObjectSchema();
resultSchema.addProperty(SwaggerConstants.RESULT_SUCCESS_FIELD, new BooleanSchema());
resultSchema.addProperty(SwaggerConstants.RESULT_CODE_FIELD, new IntegerSchema());
resultSchema.addProperty(SwaggerConstants.RESULT_MESSAGE_FIELD, new StringSchema());
resultSchema.addProperty(SwaggerConstants.RESULT_DATA_FIELD,
dataSchema != null ? dataSchema : new ObjectSchema());
if (originalName != null && !originalName.isBlank()) {
resultSchema.setName(String.format(SwaggerConstants.RESULT_NAME_TEMPLATE, originalName));
}
return resultSchema;
}字段名全部来自 SwaggerConstants,与 Result.java 的实际字段一一对应。如果未来 Result 改字段名,只需改 SwaggerConstants 一处。
public static Schema<?> createEntityRefSchema(String entityName) {
return new Schema<>().$ref(SwaggerConstants.COMPONENTS_SCHEMAS_PREFIX + entityName);
}构造一个 $ref 引用,指向 #/components/schemas/<entityName>。OpenAPI 把所有命名 schema 集中放在 components.schemas,引用走 ref 而不是嵌入完整定义,避免文档膨胀。
public static ArraySchema createArraySchema(String itemType) {
ArraySchema arraySchema = new ArraySchema();
arraySchema.setItems(createEntityRefSchema(itemType));
return arraySchema;
}数组 schema 的 items 同样走 $ref。组合 Result«List<UserDTO>» 的层级会是:Result(data=Array(items=$ref UserDTO))。
public static ObjectSchema buildObjectSchemaFromConfig(Map<String, String> fieldConfig) {
ObjectSchema schema = new ObjectSchema();
for (Map.Entry<String, String> entry : fieldConfig.entrySet()) {
Schema<?> fieldSchema = createSchemaByType(entry.getValue());
schema.addProperty(entry.getKey(), fieldSchema);
}
return schema;
}createSchemaByType 支持 string / integer / boolean / array,遇到 array 默认填 UserDTO 引用。这是给框架自带演示场景用的,业务工程很少会直接调到。
public static Map<String, Object> generateCompleteResultExample(Object dataExample) {
Map<String, Object> example = generateBaseResultExample();
example.put(SwaggerConstants.RESULT_DATA_FIELD, dataExample != null ? dataExample : new LinkedHashMap<>());
return example;
}
public static Map<String, Object> generateBaseResultExample() {
Map<String, Object> example = new LinkedHashMap<>();
example.put(SwaggerConstants.RESULT_SUCCESS_FIELD, SwaggerConstants.DEFAULT_SUCCESS);
example.put(SwaggerConstants.RESULT_CODE_FIELD, SwaggerConstants.DEFAULT_SUCCESS_CODE);
example.put(SwaggerConstants.RESULT_MESSAGE_FIELD, SwaggerConstants.DEFAULT_SUCCESS_MESSAGE);
return example;
}用 LinkedHashMap 而非普通 HashMap,保证字段在 Swagger UI 中的渲染顺序固定为「success → code → message → data」。
public static Object generateEntityExample(String entityType) {
if (entityType == null || !SwaggerConstants.SUPPORTED_ENTITY_TYPES.contains(entityType)) {
return new LinkedHashMap<>();
}
switch (entityType) {
case SwaggerConstants.USER_DTO_TYPE:
return generateUserExample();
default:
return new LinkedHashMap<>();
}
}SUPPORTED_ENTITY_TYPES 当前只有 UserDTO。未识别的类型返回空对象,避免空指针、避免误生成误导性的示例数据。
| 分类 | 关键常量 |
|---|---|
| Result 字段 | RESULT_SUCCESS_FIELD / RESULT_CODE_FIELD / RESULT_MESSAGE_FIELD / RESULT_DATA_FIELD / RESULT_FIELDS |
| 媒体类型 | JSON_MEDIA_TYPE_KEY = "json" / APPLICATION_JSON |
| Schema 引用 | COMPONENTS_SCHEMAS_PREFIX = "#/components/schemas/" / RESULT_VOID_SUFFIX / RESULT_NAME_TEMPLATE = "Result«%s»" |
| 默认值 | DEFAULT_SUCCESS / DEFAULT_SUCCESS_CODE / DEFAULT_SUCCESS_MESSAGE |
| 方法名特化 | SEARCH_USERS_FIELDS / USER_STATS_FIELDS / METHOD_SCHEMA_CONFIG |
| 实体类型 | USER_DTO_TYPE / SUPPORTED_ENTITY_TYPES |
字段名与 forge-api 的 Result.java 字段保持手工同步,这是一个已知的耦合点:未来如果 Result 改字段,必须改这里。
业务方有 OrderDTO 想在文档里看到完整示例:
SwaggerConstants.SUPPORTED_ENTITY_TYPES 加入 "OrderDTO"ExampleDataGenerator.generateEntityExample 的 switch 里加一个 casegenerateOrderExample() 方法返回示例 Map理想情况下,框架应该让业务方在外部注入 Map<String, Supplier<Object>> 而无需修改源码。这是后续可演进的方向。
例如 PageResult<T> 这种「双层包装」的业务场景,文档里希望看到 Result«PageResult«UserDTO»»。需要改 GlobalResultOperationCustomizer.inferSchemaFromHandlerReturnType,识别 PageResult 类型并构造对应的嵌套 schema。
某些团队约定字段名是 snake_case。改动点:
SwaggerConstants 修改字段名常量Result.java 也必须同步改,因为字段名是序列化键名| 选项 | 选择 | 理由 |
|---|---|---|
| 工具类形态 | final + 私有构造 | 阻止实例化,符合阿里规范 |
| 字段名来源 | 集中在 SwaggerConstants | 改一处影响全模块;与 Result 的同步靠手工 |
| 示例数据 | 内置 + switch 分发 | 实现简单;扩展性差,待重构为可注入策略 |
| LinkedHashMap | 用 | 保证字段渲染顺序固定 |
| 类型推断兜底 | 不识别的类型用空对象 | 避免误导性示例,保持文档的「不知道就空着」原则 |