Swagger初体验

这世间 没有 不相交的平行线

Posted by MatthewHan on 2019-07-16

Swagger…现在好像又多了一层台味…

前言

以前刚接触到Swagger,不知道他还能导出成Word、PDF文档,就觉得Postman+文档够用了,现在觉得代码中集成这样的框架,在初期能够方便很多。

  • 功能丰富 :支持多种注解,自动生成接口文档界面,支持在界面测试API接口功能;
  • 条理清晰 :开发过程中花一点写注释的时间,就可以及时的更新API文档,省心省力;
  • 整合简单 :通过添加pom依赖和简单配置,内嵌于应用中就可同时发布API接口文档界面,不需要部署独立服务。

Swagger集成项目

Swagger本身是一种规范,而SpringFox-Swagger是专注于Spring生态的实现,Spring-Swagger-UI则是对Swagger-UI的封装。

代码整整合也非常的简单,首先是pom引入:

pom引入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.github.swagger2markup</groupId>
<artifactId>swagger2markup</artifactId>
<version>1.3.1</version>
</dependency>

其中swagger2markup是用于Swagger导出PDF/HTML的依赖,离线文档之后再更新,目前还有点问题。

application.properties中加这么一句spring.resources.static-locations=classpath:/static/,不然swagger-ui.html这个页面会被拦截。

Configuration注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* @ClassName SwaggerConfiguration
* @Description TODO
* @Author MatthewHan
* @Date 2019/7/16 16:15
* @Version 1.0
**/
@Configuration
public class SwaggerConfiguration {

@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
// 这是注意的代码
.apis(RequestHandlerSelectors.basePackage("com.zrtg.ldapsync.common.action"))
.paths(PathSelectors.any())
.build();
}

private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("ldap-sync接口文档")
.description("用于大院LDAP服务器同步无纸化办公组织架构")
.termsOfServiceUrl("http://gitlab.zrtg.com/996team/ldap-sync")
.version("1.0")
.build();
}

}
  • 其中basePackage中的一般配置controller的路径,paths属性进行过滤,apis属性可以设置扫描包,或者通过注解的方式标识;通过enable属性,可以在application-{profile}.properties文件中设置相应值,主要用于控制生产环境不生成接口文档。另外还有groupName()进行分组,比如高级客户、低端人口(雾)之类的分组。
  • apiInfo中包装了文档的titledescriptionversion这些信息。

然后在Springboot的入口类中加上@EnableSwagger2表示开启Swagger2。

完成这些步骤后,发现其实访问https://localhost/swagger-ui.html并没有swagger页面,原因是在所映射的地址在SpringBoot静态资源文件夹下找不到。所以需要定义一个拦截器来放行。

实现WebMvcConfigurer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* @ClassName WebMvcConfiguration
* @Description 用于Swagger UI显示
* @Author MatthewHan
* @Date 2019/7/16 16:37
* @Version 1.0
**/
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {

registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");

registry.addResourceHandler("/templates/**")
.addResourceLocations("classpath:/META-INF/resources/templates/");
}
}

我们只需要重写addResourceHandlers方法即可,通过addResourceHandler添加映射路径,然后再通过addResourceLocations来指定路径。addResourceLocations指的是文件放置的目录,addResoureHandler指的是对外暴露的访问路径。

在controller中集成注解

注解 描述
@Api 修饰整个类,描述Controller的作用
@ApiOperation 描述一个类的一个方法,或者说一个接口
@ApiParam 单个参数描述
@ApiModel 用对象来接收参数
@ApiProperty 用对象接收参数时,描述对象的一个字段
@ApiResponse HTTP响应其中1个描述
@ApiResponses HTTP响应整体描述
@ApiIgnore 使用该注解忽略这个API
@ApiError 发生错误返回的信息
@ApiImplicitParam 一个请求参数
@ApiImplicitParams 多个请求参数

最后通过浏览器来访问https://localhost/swagger-ui.html如下图:

Swagger-UI

Method类型、相关描述、Example、StatusCode都会自动帮你生成。

小问题记录

注解问题

直接在通过@PathVariable注解的参数在Swagger中用了@ApiImplicitParam,发现在页面中请求是有问题的,这个注解应该对应的是func(@Param("arg") String arg)方法,实际上正确的用法是@ApiParam。类似下图代码:

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 测试
* 用于添加一个ou,例如:department,employee
* @param ou
* @return
*/
@ApiOperation(value = "添加一个OU")
@ApiParam(name = "ou", value = "组织单元", required = true)
@PostMapping("/add-ldap-ou/{ou}")
public BaseResult<String> addLdapOu(@PathVariable("ou")String ou){
...
}

与Shiro集成的问题

通过无拦截测试总结了如下的资源路径是swagger在渲染页面时的必需。如果工程中包含了Shiro安全框架,需要对swagger进行放行。

1
2
3
4
5
6
7
8
9
10
11
// 设置拦截器
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
// swagger放行
filterChainDefinitionMap.put("/swagger-ui.html", "anon");
filterChainDefinitionMap.put("/swagger-resources/**", "anon");
filterChainDefinitionMap.put("/v2/**", "anon");
filterChainDefinitionMap.put("/webjars/**", "anon");
filterChainDefinitionMap.put("/configuration/**", "anon");

ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

在你的Shiro配置类中添加如上路径即可。

离线文档(后续更新)