Swagger2文档导出为HTML或markdown等格式离线阅读
网上有很多《使用swagger2构建API文档》的文章,swagger2文档是一个在线文档,需要使用HTTP访问。但是在我们日常使用swagger接口文档的时候,有的时候需要接口文档离线访问,如将文档导出为html、markdown格式。又或者我们不希望应用系统与swagger接口文档使用同一个服务,而是导出HTML之后单独部署,这样做保证了对接口文档的访问不影响业务系统,也一定程度提高了接口文档的安全性。核心的实现过程就是:
注意:adoc是一种文件格式,不是我的笔误。不是doc文件也不是docx文件。
在已经集成了swagger2的应用内,通过maven坐标引入相关依赖类库,pom.xml代码如下:
<dependency> <groupId>io.github.swagger2markup</groupId> <artifactId>swagger2markup</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>io.swagger</groupId> <artifactId>swagger-core</artifactId> <version>1.5.16</version> </dependency> <dependency> <groupId>io.swagger</groupId> <artifactId>swagger-models</artifactId> <version>1.5.16</version> </dependency>
swagger2markup用于将swagger2在线接口文档导出为html,markdown,adoc等格式文档,用于静态部署或离线阅读。其中第一个maven坐标是必须的。后两个maven坐标,当你在执行后面的代码过程中报下图中的ERROR,或者有的类无法import的时候使用。
swagger2markup过程可能抛出的异常
产生异常的原因已经有人在github的issues上给出解释了:当你使用swagger-core版本大于等于1.5.11,并且swagger-models版本小于1.5.11就会有异常发生。所以我们显式的引入这两个jar,替换掉swagger2默认引入的这两个jar。
swagger2markup异常的解决方案
下面的代码是通过编码方式实现的生成adoc格式文件的方式
@RunWith(SpringRunner.class) @SpringBootTest(webEnvironment=SpringBootTest.WebEnvironment.DEFINED_PORT) public class DemoApplicationTests { @Test public void generateAsciiDocs() throws Exception { // 输出Ascii格式 Swagger2MarkupConfig config=new Swagger2MarkupConfigBuilder() .withMarkupLanguage(MarkupLanguage.ASCIIDOC) //设置生成格式 .withOutputLanguage(Language.ZH) //设置语言中文还是其他语言 .withPathsGroupedBy(GroupBy.TAGS) .withGeneratedExamples() .withoutInlineSchema() .build(); Swagger2MarkupConverter.from(new URL("http://localhost:8888/v2/api-docs")) .withConfig(config) .build() .toFile(Paths.get("src/main/resources/docs/asciidoc")); } }
@Test public void generateMarkdownDocsToFile() throws Exception { // 输出Markdown到单文件 Swagger2MarkupConfig config=new Swagger2MarkupConfigBuilder() .withMarkupLanguage(MarkupLanguage.MARKDOWN) .withOutputLanguage(Language.ZH) .withPathsGroupedBy(GroupBy.TAGS) .withGeneratedExamples() .withoutInlineSchema() .build(); Swagger2MarkupConverter.from(new URL("http://localhost:8888/v2/api-docs")) .withConfig(config) .build() .toFile(Paths.get("src/main/resources/docs/markdown")); }
上面的这一段代码是生成markdown格式接口文件的代码。执行上面的2段单元测试代码,就可以生产对应格式的接口文件。
还有一种方式是通过maven插件的方式,生成adoc和markdown格式的接口文件。笔者不常使用这种方式,没有使用代码生成的方式配置灵活,很多配置都放到pom.xml感觉很臃肿。但还是介绍一下,首先配置maven插件swagger2markup-maven-plugin。
<plugin> <groupId>io.github.swagger2markup</groupId> <artifactId>swagger2markup-maven-plugin</artifactId> <version>1.3.1</version> <configuration> <swaggerInput>http://localhost:8888/v2/api-docs</swaggerInput><!---swagger-api-json路径--> <outputDir>src/main/resources/docs/asciidoc</outputDir><!---生成路径--> <config> <swagger2markup.markupLanguage>ASCIIDOC</swagger2markup.markupLanguage><!--生成格式--> </config> </configuration> </plugin>
然后运行插件swagger2markup就可以了,如下图:
插件运行方式(点击可放大)
<plugin> <groupId>org.asciidoctor</groupId> <artifactId>asciidoctor-maven-plugin</artifactId> <version>1.5.6</version> <configuration> <!--asciidoc文件目录--> <sourceDirectory>src/main/resources/docs</sourceDirectory> <!---生成html的路径--> <outputDirectory>src/main/resources/html</outputDirectory> <backend>html</backend> <sourceHighlighter>coderay</sourceHighlighter> <attributes> <!--导航栏在左--> <toc>left</toc> <!--显示层级数--> <!--<toclevels>3</toclevels>--> <!--自动打数字序号--> <sectnums>true</sectnums> </attributes> </configuration> </plugin>
adoc的sourceDirectory路径必须和第三小节中生成的adoc文件路径一致。然后按照下图方式运行插件。
asciidoctor:process-asciidoc插件运行
HTMl接口文档显示的效果如下,有了HTML接口文档你想转成其他各种格式的文档就太方便了,有很多工具可以使用。这里就不一一介绍了。
HTML显示结果
wagger介绍
前后端分离是目前一种非常流行的开发模式,前端和后端开发人员通过接口进行数据交换,因此接口文档显得尤为重要,借助swagger在线接口文档,可以方便查看接口相关信息及进行接口测试,极大地提高了开发效率。swagger是API文档自动生成工具,用于生成、描述、调用和可视化Restful风格的web服务。
1、pom文件中添加依赖
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
2、创建配置类SwaggerConfig
@Configuration
@EnableSwagger2
public class Swagger2Config {
@Bean
public Docket createApi(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
//是否开启 (默认开启, false关闭,生产环境建议关闭)
//.enable(false)
.select()
//扫描的路径包,设置basePackage会将包下的所有被@Api标记类的所有方法作为api
.apis(RequestHandlerSelectors.basePackage("com.xx.controller"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo(){
return new ApiInfoBuilder()
//设置文档标题(API名称)
.title("测试API")
//文档描述
.description("测试API说明")
//版本号
.version("1.0")
.build();
}
}
3、编写controller,添加注解
@RestController
@RequestMapping("user")
@Api(tags="用户管理")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("users")
@ApiOperation("用户列表")
public Result<List<User>> user() {
List<User> users=userService.findAll();
return Result.success(users);
}
@GetMapping("{id}")
@ApiOperation("根据id查询")
public Result<User> user(@PathVariable Long id) {
User user=userService.findById(id);
return Result.success(user);
}
...
4、在线访问测试: http://ip:port/swagger-ui.html
swagger在线访问
5、接口测试及返回结果
接口测试
@Api:用在请求的类上,表示对类的说明
tags="说明该类的作用,可以在UI界面上看到的注解"
value="该参数没什么意义"
@ApiOperation:用在请求的方法上
value="说明方法的作用"
notes="方法的备注说明"
@ApiImplicitParams:用在请求的方法上,表示一组参数说明
@ApiImplicitParam:用在@ApiImplicitParams注解中,
指定一个请求参数的各个方面
name:参数名
value:参数的汉字说明、解释
required:参数是否必须传
paramType:参数放在哪个地方
· header --> 请求参数的获取:@RequestHeader
· query --> 请求参数的获取:@RequestParam
· path(用于restful接口)--> 请求参数的获取:@PathVariable
· body(不常用)
· form(不常用)
dataType:参数类型,默认String,其它值dataType="Integer"
defaultValue:参数的默认值
@ApiResponses:用在请求的方法上,表示一组响应
@ApiResponse:用在@ApiResponses中,一般用于表达一个错误的响应信息
code:数字,例如400
message:信息,例如"请求参数没填好"
response:抛出异常的类
@ApiModel:用于响应类上,表示一个返回响应数据的信息
(这种一般用在post创建的时候,使用@RequestBody这样的场景,
请求参数无法使用@ApiImplicitParam注解进行描述的时候)
@ApiModelProperty:用在属性上,描述响应类的属性
Swagger 接口导出成 Word 格式如何实现?需要使用一个 Swagger 的增强工具Knife4j。
1、添加依赖
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>2.0.9</version>
</dependency>
2、在线访问地址 http://ip:port/doc.html
Knife4j 在线访问
Knife4j 提供了 4 种格式的离线文档下载:Markdown、Html、Word、OpenAPI 等方式,如图:
word下载
Knife4j 还可以实现过滤某一类型的接口、接口搜索、设置公共的请求参数等。
前后端分离,前端和后端api沟通目前企业中几乎都是使用Swagger2。本文主要讲解一下几个案例,基本上工作中都会用到:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.8.0</version>
</dependency>
2. Swagger2Config
@Configuration
@EnableSwagger2
public class Swagger2Config {
@Bean
public Docket docket() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("demo")
.apiInfo(apiInfo())
.select()
// 设置basePackage会将包下的所有类的所有方法作为api
// .apis(RequestHandlerSelectors.basePackage("com.example.demo2.controller"))
// 只有标记@ApiOperation才会暴露出给swagger
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(PathSelectors.regex("/api/.*"))
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("API接口文档")
.description("RESTful风格接口")
.termsOfServiceUrl("https://blog.csdn.net/vbirdbest") // 服务条款网址
.version("1.0")
.contact(new Contact("mengday", "httphttp://wwww.xxx.com", "xxx@gmail.com"))
.build();
}
}
@RestController
@RequestMapping("/api/v1/users")
@Api(value="User API接口", tags="user", description="User API接口")
public class UserController {
@ApiOperation(value="用户登录", notes="用户登录接口")
@ApiResponses({
@ApiResponse(code=0, message="success"),
@ApiResponse(code=10001, message="用户名错误", response=IllegalArgumentException.class),
@ApiResponse(code=10002, message="密码错误")
})
@PostMapping(value="/login")
public String login(@ApiParam(name="username", value="用户名", required=true) @RequestParam String username,
@ApiParam(name="password", value="密码", required=true) @RequestParam String password){
return "{'username':'" + username + "', 'password':'" + password + "'}";
}
@ApiOperation(value="修改用户信息", notes="修改用户信息")
@ApiImplicitParams({
@ApiImplicitParam(dataTypeClass=String.class, paramType="header", name="phone", required=true, value="手机号"),
@ApiImplicitParam(dataTypeClass=String.class, paramType="query", name="nickname", required=true, value="nickname", defaultValue="双击666"),
@ApiImplicitParam(dataTypeClass=String.class, paramType="path", name="platform", required=true, value="平台", defaultValue="PC"),
@ApiImplicitParam(dataTypeClass=String.class, paramType="body", name="password", required=true, value="密码")
})
@PutMapping(value="/{platform}/regist")
public String regist(@RequestHeader String phone, @RequestParam String nickname, @PathVariable String platform, @RequestBody String password){
return "{'username':'" + phone + "', 'nickname':'" + nickname + "', 'platform': '" + platform + "', 'password':'"+password+"'}";
}
@ApiOperation(value="用户列表", notes="查询用户列表")
@GetMapping(value="/list")
public String getUserList(PagerIDto pager){
return "[{'id': "+pager.getPage()+", 'username': 'zhangsan"+pager.getSize()+"'}]";
}
@ApiOperation(value="删除用户", notes="删除用户")
@DeleteMapping("/{id}")
public String removeUser(@PathVariable Long id){
return "success";
}
@ApiIgnore
@RequestMapping("/ignoreApi")
public String ignoreApi(){
return "docs";
}
}
4. 启动应用程序并访问swagger-ui.html
5. 为swagger-ui增加密码
5.1 pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
5.2 application.yml
spring:
security:
basic:
path: /swagger-ui.html
enabled: true
user:
name: admin
password: 123456
5.3 WebSecurityConfigurerAdapter
/**
* Spring Security 会拦截swagger-ui.html 同样也会拦截api,这里将或略掉/api/下的所有子路径
*/
@EnableWebSecurity
@Configuration
public class CustomWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) throws Exception {
super.configure(web);
web.ignoring().antMatchers("/api/v1/**");
}
}
5.4 重启项目再次访问swagger-ui
访问 http://localhost:8080/swagger-ui.html 会跳转到 http://localhost:8080/login 输入application.yml配置的用户名密码即可跳转到到swagger-ui.html
apis(RequestHandlerSelectors.basePackage(“com.example.demo2.controller”)) 会将包下的所有Controller类带有@RequestMapping或者XxxMapping都会给暴露给swagger,如果想部分类暴露出去部分不暴露出去,只能将不暴露的controller放到其他package中,放在同一个package是做不到的。
apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)): 只有在类上使用@Api注解标注并且在方法上使用@ApiOperation注解才会暴露给swagger,这种方式没有包名的限制,可以将需要暴露的接口分散到各个包里,只要类上有@Api注解方法上有@ApiOperation注解就能暴露出来,如果不想暴露出来就不用使用这两个注解。
现在的项目一般都是微服务,swagger可以做到将多个项目合并到一个swagger上,这样便于接口的使用。
本示例只使用了Spring Boot, 后面可以结合spring-cloud-zuul来使用。
首先准备两个api项目(platform-user-server、platform-order-server),并且每个项目都配置好swagger,然后再使用一个聚合的api项目(platform-api-gateway)来聚合这两个api,这样只需查看聚合api上对应的swagger ui即可。
1. maven
<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>
2. application.properties
server.port=8081
3. Configuration
@Configuration
public class CORSConfiguration {
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source=new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration=new CorsConfiguration();
// 1 设置访问源地址
corsConfiguration.addAllowedOrigin("*");
// 2 设置访问源请求头
corsConfiguration.addAllowedHeader("*");
// 3 设置访问源请求方法
corsConfiguration.addAllowedMethod("*");
// 4 对接口配置跨域设置
source.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(source);
}
}
@Configuration
public class Swagger2Configuration {
@Bean
public Docket shopRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.example.platform.user"))
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
Contact contact=new Contact("mengday", "https://blog.csdn.net/vbirdbest", "mengday.zhang@gmail.com");
return new ApiInfoBuilder()
.title("用户API")
.description("用户API")
.termsOfServiceUrl("http://localhost:8081/swagger-ui.html")
.contact(contact)
.version("1.0")
.build();
}
4. Application
@EnableSwagger2
@SpringBootApplication
public class PlatformUserServerApplication {
public static void main(String[] args) {
SpringApplication.run(PlatformUserServerApplication.class, args);
}
}
5. controller
@RestController
@RequestMapping("/user")
@Api(description="用户API")
public class UserController {
@ApiOperation(value="用户登录", notes="用户登录", produces=MediaType.APPLICATION_JSON_UTF8_VALUE)
@ApiImplicitParams({
@ApiImplicitParam(name="username", value="用户名", required=true, paramType="body", dataType="String"),
@ApiImplicitParam(name="password", value="密码", required=true, paramType="body", dataType="String")
})
@PostMapping("/login")
public String login(String username, String password) {
return "success";
}
}
6. 访问swagger
http://localhost:8081/swagger-ui.html
注意:swagger不要使用太高的版本,不建议使用2.8.0以上的版本,不然很可能会报如下错误,即使低版本也可能会报该错误。Chrome报错,遇到这个错误可以尝试清除缓存或者使用其他浏览器,这个问题很多人都遇到了,也没找到有效的解决方案,自己在测试的时候就一会好使,一会又不好使,祝你好运。
1. maven
<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>
2. application.properties
server.port=8082
3. Configuration
@Configuration
public class CORSConfiguration {
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source=new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration=new CorsConfiguration();
// 1 设置访问源地址
corsConfiguration.addAllowedOrigin("*");
// 2 设置访问源请求头
corsConfiguration.addAllowedHeader("*");
// 3 设置访问源请求方法
corsConfiguration.addAllowedMethod("*");
// 4 对接口配置跨域设置
source.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(source);
}
}
@Configuration
public class Swagger2Configuration {
@Bean
public Docket shopRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.example.platform.order"))
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
Contact contact=new Contact("mengday", "https://blog.csdn.net/vbirdbest", "mengday.zhang@gmail.com");
return new ApiInfoBuilder()
.title("订单API")
.description("订单API")
.termsOfServiceUrl("http://localhost:8082/swagger-ui.html")
.contact(contact)
.version("1.0")
.build();
}
}
4. Application
@EnableSwagger2
@SpringBootApplication
public class PlatformOrderServerApplication {
public static void main(String[] args) {
SpringApplication.run(PlatformOrderServerApplication.class, args);
}
}
5. controller
@RestController
@RequestMapping("/shoppingcart")
@Api(description="购物车API")
public class ShoppingCartController {
@ApiOperation(value="加入购物车", notes="加入购物车", produces=MediaType.APPLICATION_JSON_UTF8_VALUE)
@ApiImplicitParams({
@ApiImplicitParam(name="barcode", value="条形码", required=true, paramType="body", dataType="String"),
@ApiImplicitParam(name="quantity", value="数量", required=true, paramType="body", dataType="Integer")
})
@PostMapping("/add")
public String addShoppingCart(String barcode, Integer quantity) {
return "success";
}
}
6. 访问swagger
1. maven
<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>
2. application.properties
server.port=8080
3. Application
@EnableSwagger2
@SpringBootApplication
public class PlatformApiGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(PlatformApiGatewayApplication.class, args);
}
}
4. configuration
@Configuration
public class CORSConfiguration {
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source=new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration=new CorsConfiguration();
// 1 设置访问源地址
corsConfiguration.addAllowedOrigin("*");
// 2 设置访问源请求头
corsConfiguration.addAllowedHeader("*");
// 3 设置访问源请求方法
corsConfiguration.addAllowedMethod("*");
// 4 对接口配置跨域设置
source.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(source);
}
}
@Configuration
public class SwaggerConfiguration {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo());
}
private ApiInfo apiInfo() {
Contact contact=new Contact("mengday", "https://blog.csdn.net/vbirdbest", "mengday.zhang@gmail.com");
return new ApiInfoBuilder()
.title("项目名称")
.description("Swagger多项目聚合")
.termsOfServiceUrl("http://localhost:8080")
.contact(contact)
.version("1.0")
.build();
}
}
@Component
@Primary
public class DocumentationConfiguration implements SwaggerResourcesProvider {
@Override
public List<SwaggerResource> get() {
List resources=new ArrayList<>();
resources.add(swaggerResource("用户API", "http://localhost:8081/v2/api-docs", "2.0"));
resources.add(swaggerResource("购物车API", "http://localhost:8082/v2/api-docs", "2.0"));
return resources;
}
private SwaggerResource swaggerResource(String name, String location, String version) {
SwaggerResource swaggerResource=new SwaggerResource();
swaggerResource.setName(name);
swaggerResource.setLocation(location);
swaggerResource.setSwaggerVersion(version);
return swaggerResource;
}
}
5. 访问swagger
*请认真填写需求信息,我们会在24小时内与您取得联系。