首先我们回顾一下
swagger2自定义注解 —你还在为每一个api创建一个ApiModel类而烦恼吗?
通过swagger的插件机制 我们可以对同一个类型在不同接口进行属性的显示和隐藏,但是当我们真正使用的时候,会发现一个奇怪的现象,总会有一个Model不能正常生成…如下图
是什么导致了这个现象
通过不断测试我们会发现 丢失的永远是最后一个被SwaggerModelReader 扫描到的model一切问题的根源在于下面这2行代码
springfox.documentation.spring.web.scanners.ApiListingScanner#scan 132行
for (RequestMappingContext each : sortedByMethods(requestMappings)) {
// 首先swagger机制会读取全局的model 并且将它加入到一个容器内
models.putAll(apiModelReader.read(each.withKnownModels(models)));
// 然后swagger 逐个读取RequestMappingContext 进入我们SwaggerModelReader的入口也是下面这行函数
apiDescriptions.addAll(apiDescriptionReader.read(each));
}
然后我们回顾SwaggerModelReader中我们做了什么
- 分析当前执行的方法,根据方法上的注解重新构建一个类对象。
- 将类对象add到文档中
// 向文档内容中添加新的模型对象 parameterContext.getDocumentationContext() .getAdditionalModels() //像documentContext的Models中添加我们新生成的Class .add(typeResolver.resolve(createRefModelIgp(properties, name, originClass, ignore)));
- 重新绑定当前参数上下文中使用的model
//修改model参数的ModelRef为我们动态生成的class parameterContext.parameterBuilder() .parameterType("body") .modelRef(modelRef) .name(name);
分析完成之后 再结合前面的实际表现,我们不难发现 问题的根本原因是swagger 没有重新读取
documentationContext.additionalModels 内新添加的model
解决方案
-
我们在项目的根目录创建一个文件夹
springfox.documentation.spring.web.scanners -
将swagger中的ApiListingScanner类拷贝到这个文件夹内
-
调整132行 scan方法内for循环的执行顺序
// 调整前: for (RequestMappingContext each : sortedByMethods(requestMappings)) { models.putAll(apiModelReader.read(each.withKnownModels(models))); apiDescriptions.addAll(apiDescriptionReader.read(each)); } // 调整后: for (RequestMappingContext each : sortedByMethods(requestMappings)) { // 使用循环外面再重新收集一次也可以 apiDescriptions.addAll(apiDescriptionReader.read(each)); models.putAll(apiModelReader.read(each.withKnownModels(models))); }