springdoc-openapi-webflux-ui 与 java.time.Duration 的问题(ISO 8601 持续时间格式)

问题描述 投票:0回答:3

Swagger 文档将持续时间显示为

  "duration": {
    "seconds": 0,
    "nano": 0,
    "zero": true,
    "negative": true,
    "units": [
      {
        "dateBased": true,
        "timeBased": true,
        "durationEstimated": true
      }
    ]
  },

但实际格式是 ISO 8601 持续时间格式(PT0S),以下是代码段。有没有办法正确格式化文档?

任务文档

@Document(collection = "tasks")
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder(toBuilder = true)
public class Task {

    public enum Status {
        todo, inprogress, done
    }

    @Id
    private String id;

    private String name;

    private String description;

    private Status status = Status.todo;

    private Duration estimatedDuration = Duration.ZERO;

    private Duration duration = Duration.ZERO;
    }

初始化

@SpringBootApplication
@OpenAPIDefinition(info = @Info(title = "APIs v1.0.2", version = "1.0.2", description = "Documentation APIs v1.0.2"))
public class SBApplication {
......

}

pom依赖

    <dependency>
        <groupId>org.springdoc</groupId>
        <artifactId>springdoc-openapi-webflux-ui</artifactId>
        <version>1.4.3</version>
    </dependency>
java spring-boot swagger duration springdoc-openapi-ui
3个回答
3
投票

尝试

    import io.swagger.v3.oas.annotations.media.Schema;

    ...

    @Schema(type = "string", format = "duration")
    private Duration estimatedDuration = Duration.ZERO;

    @Schema(type = "string", format = "duration")
    private Duration duration = Duration.ZERO;
  

1
投票

在 swagger-core issues中有一些关于这个主题的讨论。

对我来说,窍门是使用一个大摇大摆的 ModelConverter :

@Component public class DurationPropertyModelConverter implements ModelConverter { @Override public Schema resolve(AnnotatedType type, ModelConverterContext context, Iterator<ModelConverter> chain) { if (type.isSchemaProperty()) { JavaType _type = Json.mapper().constructType(type.getType()); if (_type != null) { Class<?> cls = _type.getRawClass(); if (Duration.class.isAssignableFrom(cls)) { return new StringSchema().format("duration"); } } } if (chain.hasNext()) { return chain.next().resolve(type, context, chain); } else { return null; } } }
    

0
投票
基于 Bob G 的答案,以下是如何将模式替换与“继承”结合起来(智能地将类型上的模式与属性上的模式合并)。

代码采用 Kotlin 语言。

/** * SwaggerDoc model converter for allowing basic schema inheritance. * * It achieves this by replacing known "problem" type schemas with the schema of a different type, * similar to [SpringDocUtils.replaceWithSchema]. * Unlike the built-in schema replacement, [SchemaReplacer] correctly overrides type schema values * with property schema values, rather than completely replacing one with the other. */ @Component class SchemaReplacer : ModelConverter { /** * Which type schemas to replace. */ private val replacements = mutableMapOf<Class<*>, KClass<*>>() /** * Add a type schema replacement. */ fun replace(target: Class<*>, replacement: KClass<*>) { replacements[target] = replacement } override fun resolve( target: AnnotatedType, context: ModelConverterContext, chain: MutableIterator<ModelConverter>, ): Schema<*>? { if (target.isSchemaProperty) { replacements[(target.type as JavaType).rawClass]?.also { replacementType -> val typeSchema = replacementType.findAnnotation<SchemaAnnotation>() val propSchema = target.ctxAnnotations.filterIsInstance<SchemaAnnotation>().singleOrNull() return Schema<Any>().apply { type = propSchema?.type.takeUnless { it.isNullOrBlank() } ?: typeSchema?.type.takeUnless { it.isNullOrBlank() } ?: StringSchema().type format = propSchema?.format.takeUnless { it.isNullOrBlank() } ?: typeSchema?.format.takeUnless { it.isNullOrBlank() } title = propSchema?.title.takeUnless { it.isNullOrBlank() } ?: typeSchema?.title.takeUnless { it.isNullOrBlank() } description = propSchema?.description.takeUnless { it.isNullOrBlank() } ?: typeSchema?.description.takeUnless { it.isNullOrBlank() } pattern = propSchema?.pattern.takeUnless { it.isNullOrBlank() } ?: typeSchema?.pattern.takeUnless { it.isNullOrBlank() } example = propSchema?.example.takeUnless { it.isNullOrBlank() } ?: typeSchema?.example.takeUnless { it.isNullOrBlank() } // ...etc } } } if (chain.hasNext()) return chain.next().resolve(target, context, chain) else return null } }
要使用它,请设置一个替换类,然后设置一个属性:

@Schema(title = "Duration", format = "duration", example = "PT3H4M2S") class DurationSchema //--- @Configuration class OpenApiConfig(replacer: SchemaReplacer) { init { replacer.replace(Duration::class.java, DurationSchema::class) } } //--- data class DTO( @field:Schema(title = "Total duration") val totalDuration: Duration, }
这将生成一个 OpenAPI 文档,其中 

totalDuration

 具有来自属性的标题以及来自 
DurationSchema
 类的所有其他架构属性。

© www.soinside.com 2019 - 2024. All rights reserved.