使用springfox+swagger2书写API文档
springfox是通过注解的形式自动生成API文档,利用它,可以很方便的书写restful
API,swagger主要用于展示springfox生成的API文档,笔者将主要介绍springfox的配置与使用,文中spring版本为4.2.6.RELEASE,springfox版本为2.6.1,使用Maven进行项目依赖管理。
Maven依赖配置
下面是Maven pom.xml配置信息
<properties>
<springfoxversion>2.6.1</springfoxversion>
</properties>
<dependencies>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${springfoxversion}</version>
<scope>compile</scope>
</dependency>
</dependencies>
如果启动项目时出现com/fasterxml/jackson/databind/ObjectMapper
类找不到,请加入下面依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.6.6</version>
</dependency>
Configuration类配置
下面是基础配置类,下面类中的.apiInfo()
可以去掉,不使用也可以。
/*
省略 package name
*/
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration //必须存在
@EnableSwagger2 //必须存在
@EnableWebMvc //必须存在
@ComponentScan(basePackages = {"org.blog.controller"}) //必须存在 扫描的API Controller package name 也可以直接扫描class (basePackageClasses)
public class WebAppConfig{
@Bean
public Docket customDocket() {
//
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo());
}
private ApiInfo apiInfo() {
Contact contact = new Contact("周发扬", "https://cc520.me", "[email protected]");
return new ApiInfo("Blog前台API接口",//大标题 title
"Blog前台API接口",//小标题
"0.0.1",//版本
"www.fangshuoit.com",//termsOfServiceUrl
contact,//作者
"Blog",//链接显示文字
"https://cc520.me"//网站链接
);
}
}
注意:当前类一定要让spring在加载时候能扫描到配置类。
springfox使用
添加了配置类,我们开始创建一个Controller类(一定要让上一步配置类中的@ComponentScan扫描到),并在类中使用注解配置API信息。
下面类中没有添加全局异常处理,如果传递的参数类型和接收类型不匹配等情况,会抛出异常信息,请自行添加全局异常处理。
/*
*省略package 和 部分 improt
*/
import io.swagger.annotations.*;
@Controller
@RequestMapping(value = "/v1/api")
public class HomeApiController{
//这里使用POST @RequestBody必须使用POST才能接收,这里方便讲解
@ApiOperation(value = "一个测试API", notes = "第一个测试API")
@ResponseBody
@RequestMapping(value = "/test/{path}", method = RequestMethod.POST)
@ApiImplicitParams({
@ApiImplicitParam(name = "blogArticleBeen", value = "文档对象", required = true, paramType = "body", dataType = "BlogArticleBeen"),
@ApiImplicitParam(name = "path", value = "url上的数据", required = true, paramType = "path", dataType = "Long"),
@ApiImplicitParam(name = "query", value = "query类型参数", required = true, paramType = "query", dataType = "String"),
@ApiImplicitParam(name = "apiKey", value = "header中的数据", required = true, paramType = "header", dataType = "String")
})
public JSONResult test(@RequestBody BlogArticleBeen blogArticleBeen,
@PathVariable Long path,
String query,
@RequestHeader String apiKey,
PageInfoBeen pageInfoBeen){
System.out.println("blogArticleBeen.getLastUpdateTime():"+blogArticleBeen.getLastUpdateTime());
System.out.println("blogArticleBeen.getSorter():"+blogArticleBeen.getSorter());
System.out.println("path:"+path);
System.out.println("query:"+query);
System.out.println("apiKey:"+apiKey);
System.out.println("pageInfoBeen.getNowPage():"+pageInfoBeen.getNowPage());
System.out.println("pageInfoBeen.getPageSize():"+pageInfoBeen.getPageSize());
JSONResult jsonResult = new JSONResult();
jsonResult.setMessage("success");
jsonResult.setMessageCode(null);
jsonResult.setCode(0);
jsonResult.setBody(null);
return jsonResult;
}
}
BlogArticleBeen.java
//省略 package import
public class BlogArticleBeen {
private Long id;
private String name; //标题
private String mainPhoto; //封面图片
private String sketch; //简述
private String content; //详细描述
private String contentMd; //详细描述 markdown
private Boolean ifTop; //是否置顶
private String sources; //来源
private String staticCode; //静态码
private BigDecimal sorter;
private Boolean status; //状态
@ApiModelProperty(hidden = true)
private String creater;
@ApiModelProperty(dataType = "java.util.Date")
private Timestamp lastUpdateTime;
@ApiModelProperty(dataType = "java.util.Date")
private Timestamp creatTime;
private String columnNamesCache;
private String columnIdsCache;
private String labelIdsCache;
private String labelNamesCache;
//省略 set get
}
PageInfoBeen.java
//省略 package import
public class PageInfoBeen {
@ApiParam(value = "当前页", required = true)
private Integer nowPage;
@ApiModelProperty(value = "每页大小", required = true)
private Integer pageSize;
//省略 set get
}
JSONResult.java
//省略 package import
public class JSONResult {
private String message;
private int code = -1;
private String messageCode;
private Object body;
//省略 set get
}
完成以上操作,我们就已经可以实际看到springfox为我们生成的API json字符串了,重启服务器,在浏览器中访问http://127.0.0.1:port/v2/api-docs
(如果添加了group信息,请参考springfox官方文档),出现下图展示的信息说明配置正确。
如果没有得到这个结果,检查一下是否更换了MessageConverter为fastjson的,如果有,请升级fastjson为最新版本再测试。
####springfox、swagger.annotations.*注解部分参数介绍
在上面只展示了如何使用,这里将对上面添加的swagger注解进行说明,笔记使用时参考了swagger annotations Api 手册,接下来进行部分常用注解使用说明介绍。
- @ApiIgnore 忽略注解标注的类或者方法,不添加到API文档中
-
@ApiOperation 展示每个API基本信息
- value api名称
- notes 备注说明
-
@ApiImplicitParam 用于规定接收参数类型、名称、是否必须等信息
- name 对应方法中接收参数名称
- value 备注说明
- required 是否必须 boolean
- paramType 参数类型 body、path、query、header、form中的一种
- body 使用@RequestBody接收数据 POST有效
- path 在url中配置{}的参数
- query 普通查询参数 例如 ?query=q ,jquery ajax中data设置的值也可以,例如 {query:”q”},springMVC中不需要添加注解接收
- header 使用@RequestHeader接收数据
- form 笔者未使用,请查看官方API文档
- dataType 数据类型,如果类型名称相同,请指定全路径,例如 dataType = “java.util.Date”,springfox会自动根据类型生成模型
-
@ApiImplicitParams 包含多个@ApiImplicitParam
-
@ApiModelProperty 对模型中属性添加说明,例如 上面的PageInfoBeen、BlogArticleBeen这两个类中使用,只能使用在类中。
- value 参数名称
- required 是否必须 boolean
- hidden 是否隐藏 boolean
其他信息和上面同名属性作用相同,hidden属性对于集合不能隐藏,目前不知道原因
-
@ApiParam 对单独某个参数进行说明,使用在类中或者controller方法中都可以。注解中的属性和上面列出的同名属性作用相同
以上为主要常用的注解介绍,请结合springfox使用查看
使用swagger2展示API文档
通过上述配置,我们已经完成了API数据生成,现在我们只需要使用swagger2 UI展示API文档即可
访问github:下载swagger-ui,下载zip文件,解压后把里面的dist目录下的所有文件考入springMVC的静态资源下,修改拷贝的index.html文件,替换下面的js代码:
var baseUrl = "";
$(function () {
var url = window.location.search.match(/url=([^&]+)/);
if (url && url.length > 1) {
url = decodeURIComponent(url[1]);
} else {
//上面描述的api-docs地址
url = baseUrl + "/v2/api-docs";
}
// Pre load translate...
if (window.SwaggerTranslator) {
window.SwaggerTranslator.translate();
}
window.swaggerUi = new SwaggerUi({
url: url,
validatorUrl: undefined,
dom_id: "swagger-ui-container",
supportedSubmitMethods: [‘get‘, ‘post‘, ‘put‘, ‘delete‘, ‘patch‘],
onComplete: function (swaggerApi, swaggerUi) {
if (typeof initOAuth == "function") {
initOAuth({
clientId: "your-client-id",
clientSecret: "your-client-secret-if-required",
realm: "your-realms",
appName: "your-app-name",
scopeSeparator: ",",
additionalQueryStringParams: {}
});
}
if (window.SwaggerTranslator) {
window.SwaggerTranslator.translate();
}
$(‘pre code‘).each(function (i, e) {
hljs.highlightBlock(e)
});
addApiKeyAuthorization();
},
onFailure: function (data) {
log("Unable to Load SwaggerUI");
},
docExpansion: "none",
jsonEditor: false,
apisSorter: "alpha",
defaultModelRendering: ‘schema‘,
showRequestHeaders: false
});
//这里可以添加权限认证,例如token
function addApiKeyAuthorization() {
var token = "you-token";
var tokenHeader = new SwaggerClient.ApiKeyAuthorization("token", token, "header");
window.swaggerUi.api.clientAuthorizations.add("token", tokenHeader);
}
window.swaggerUi.load();
function log() {
if (‘console‘ in window) {
console.log.apply(console, arguments);
}
}
});
完成了以上配置,直接访问修改的index.html,出现下面页面表示成功:
总结
通过以上步骤已经完成基本springfox+swagger-ui的基本配置,其他更新详细使用方法请查看springfox官网和swagger官网,如文章中有错误信息,请联系笔者进行更改。