springmvc 整合 swagger2 遇到的坑

缘起

公司最近做项目, 负责一个小组件的开发. 前端小姐姐需要我提供swagger.json 文档. 原先做过boot和swagger2整合,但是没整过 swagger.json. 其实就是swagger2框架暴露的一个以json格式描述api结构的http接口. 路径是 /v2/api-docs

但是整合之后发现 swagger-ui.html 可以妥妥的访问,但是 /v2/api-docs 死活出不来.

分析

代码见 DEMO【1】(更新见【2】,进一步丰富了swagger注解的写法,【3】增加了动态SQL 分页和排序)

百度了一圈, 说什么的都有,就是没有有用的. 于是只能去分析为什么这个接口没有启动? 因为访问

http://localhost/v2/api-docs 的时候,页面响应404,于是首先考虑该接口有没有被swagger暴露出来?

但是在控制台查看启动日志的时候,看到了

1
mapped /v2/api-docs to springfox.documentation.swagger2.web.Swagger2Controller.getDocumentation...

因此RESTful 接口是启动了的, 并且springmvc的DispatchServlet的配置也是正确的. 所以只能怀疑是不是此方法运行的过程中出了问题. 此方法的源码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@ApiIgnore
@RequestMapping(value={"${springfox.documentation.swagger.v2.path:/v2/api-docs}"}, method={org.springframework.web.bind.annotation.RequestMethod.GET}, produces={"application/json", "application/hal+json"})
@ResponseBody
public ResponseEntity<Json> getDocumentation(@RequestParam(value="group", required=false) String swaggerGroup, HttpServletRequest servletRequest)
{
String groupName = (String)Optional.fromNullable(swaggerGroup).or("default");
Documentation documentation = this.documentationCache.documentationByGroup(groupName);
if (documentation == null) {
return new ResponseEntity(HttpStatus.NOT_FOUND);
}
Swagger swagger = this.mapper.mapDocumentation(documentation);
if (Strings.isNullOrEmpty(swagger.getHost())) {
UriComponents uriComponents = HostNameProvider.componentsFrom(servletRequest);
swagger.basePath(Strings.isNullOrEmpty(uriComponents.getPath()) ? "/" : uriComponents.getPath());
swagger.host(hostName(uriComponents));
}
return new ResponseEntity(this.jsonSerializer.toJson(swagger), HttpStatus.OK);
}

看到了HttpStatus.NOT_FOUND没有? 所以 documentation为null, 但是documentation为什么是null? 因为groupName错了. 而groupName如果传入的参数swaggerGroup不存在的话就是default. 而swaggerGroup接受名为group的入参. 但是我没传入该入参! 我仅仅是 访问 /v2/api-docs 而不是 /v2/api-docs?group=xxx 但事实上我的SwaggerConfig是这样写的

1
2
3
4
5
6
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2).group("api").apiInfo(apiInfo()).select()
.apis(RequestHandlerSelectors.basePackage(Constants.SWAGGER2_BASEPACKAGE)).paths(PathSelectors.any())
.build();
}

并没有default的group. 所以自然返回NOT_FOUND了. 于是我将SwaggerConfig中的group(“api”)去掉, 再次访问 /v2/api-docs 对应的json文件就出来了

DEMO

【1】https://github.com/yfsyfs/backend/tree/master/swagger2-demo

【2】https://github.com/yfsyfs/backend/tree/master/swagger2-demo-enhance

【3】https://github.com/yfsyfs/backend/tree/master/ctm05acbms