开端
Everybody,好久不见,因为开学的原因,已经拖更了半个多月。周末总算是闲下来写写博文,主要还是不想学习学校里教的那些东西。
我们都知道,API 接口是一个非常神圣的内容。你做的好,前后端开发人员情同手足,和和美美;你做的不好,说不定他们每天一见面就要吵。在现在这个阶段,大家更倾向于使用一些已有的框架来进行API文档的开发,这样更加方便管理。尤其是动态更新 API 文档,更加省去了后端程序员一大部分的工作。在《阿里巴巴 Java 开发手册》中写到,API 文档和 Javadoc 就是为了方便他人阅读和理解程序而设计的,后端程序员若是更改了源代码而没有对应修改文档或注释,那文档和注释就没有了他们存在的意义。
所以今天,我就来讲一个快速生成 API 文档的框架——Swagger。没错,他就是那么 Swag!以及如何整合到项目中去,包含了后端的注解生成器与前端嵌入式的页面显示方案。话不多说,那我们就开始吧。
补充:实践过程中遇到特殊问题,请前往下方链接下载 dist 文件夹的内容并导入至项目文件中
介绍
为了解决前面讲到的问题,人们就提出了各种解决方案,方案用的人一多,就自成了一套体系,成了一套规范,这就是 Swagger 的由来。
按照新的开发模式,只要每次更新 Swagger 的描述文件,就可以自动生成接口文档。但即便如此,仍旧需要开发人员每次修改 yml 或 json 文件。人都是有惰性的,久而久之就再一次忽略了描述文件的修改,导致更新不同步。因此急需更加简便的方案。
所以作为Java届服务端的大一统框架Spring,迅速将Swagger规范纳入自身的标准,建立了 Spring-swagger 项目,后面改成了现在的 Springfox。在项目中引入 Springfox 之后,可以扫描代码并生成描述文件,同步接口文档,实现自动化管理。就目前来说已经是最重要且高效的几个生成接口文档的方式之一了。
整合
介绍不多说,直接开始整合。关于阿里云仓库的使用我就粘贴我的另一篇文章中的内容,免得大家频繁跳转页面。
使用阿里云仓库
众所周知,如果你从 github clone 一个项目,如果没有梯子下载 jar 包可能就要花几个小时的时间。还好阿里爸爸给我们提供了镜像仓库,几分钟就能解决 jar 包的问题。关于引用仓库可以在 maven 配置中修改:
<mirror>
<id>aliyunmaven</id>
<mirrorOf>*</mirrorOf>
<name>阿里云公共仓库</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
不过我还是推荐大家在自己的项目中加入仓库,灵活性更高:
<repositories>
<repository>
<id>alimaven</id>
<name>aliyun maven</name>
<url>https://maven.aliyun.com/repository/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
这里我就直接用 public 仓库,这个仓库整合了两个小仓库,东西更丰富些。releases 是线上版本,snapshots 是开发版本,都填 true 问题不大。
搜索并导入 jar 包
大家可以在上边这个网址内搜索自己要找的 jar 包,中心 central 仓库够大了,输入文件名,点击搜索到的蓝色文件名后把 Maven 依赖这些代码复制进项目里即可。
像下面的一样,我们引入最新版本的 Swagger 相关的 jar 包,如需拓展可以引用其他包。
<!--核心包-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>3.0.0</version>
</dependency>
<!--默认ui包-->
<dependency>
<groupId>io.springfox</groupId>-->
<artifactId>springfox-swagger-ui</artifactId>-->
<version>3.0.0</version>-->
</dependency>
<!--推荐ui包-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.9.6</version>
</dependency>
由于默认的 UI 界面并不那么舒适,也不适合用于前端展示,所以推荐使用最后一个包,两者选其一导入。
这里提一点,项目使用的 Java 版本最好是高于或等于 11,如果太低下面讲到的一步中可能会报错。
创建SpringFoxConfig配置类
我们先来写配置,再使用注解优化显示。在后端项目中创建一个配置类如下:
@Configuration
@EnableSwagger2
public class SpringFoxConfig {
@Bean
public Docket docket() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.host("localhost:9988")
.select()
.apis(RequestHandlerSelectors.basePackage("cn.kevin.ims.controller"))
.paths(Predicate.not(PathSelectors.regex("/error.*")))
.paths(PathSelectors.regex("/.*"))
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder().title("接口文档")
.contact(new Contact("Kevin", "http://test.ims.cool", "jiazekai1003@gmail.com"))
.description("Swagger动态接口文档")
.license("The Apache License, Version 2.0")
.licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html")
.version("Demo")
.build();
}
}
特别提醒,类名前一定要写两个注解。@Configuration
表示这是受 Spring 控制的配置组件,@EnableSwagger2
表示启用 Swagger 2。
首先构建一个 docket。host 填写后端项目的 url。apis 填写需要扫描的包。paths中可以选择扫描路径以及不扫描的路径,推荐将 error 排除。
然后构建一个 apiInfo,里面的信息自行填写,按我的模板改一下即可,不影响实际使用。
通过注解实现文档优化
如果看成果,可以跳过这一部分,但是优化之后的文档更加美观写易于阅读。
先从底层的 Entity 开始写:
@Data
@ApiModel(description = "基本实体")
public abstract class BaseEntity implements Serializable {
@ApiModelProperty(value = "创建时间", required = true)
protected long utcCreate;
@ApiModelProperty(value = "修改时间", required = true)
protected long utcModify;
@ApiModelProperty(value = "修改人", required = true)
protected String modifyBy;
@ApiModelProperty(value = "是否有效", required = true)
protected Boolean valid;
@ApiModelProperty(value = "备注", required = true)
protected String remark;
}
使用@ApiModel
注释实体类的别名,使用@APIModelProperty
注释实体类属性的别名和是否必要等信息。
不要忘了把 VO 类也注解一遍。
然后注解 Controller 层的类:
@Api(tags = "用户模块")
@CrossOrigin
@RestController()
@RequestMapping("/user/")
public class UserController extends BaseController {
@Resource(name = "userServiceImpl")
private UserService userService;
@Resource(name = "roleServiceImpl")
private RoleService roleService;
@ApiOperation(value = "默认Get请求", notes = "请求不存在的路径时调用此默认接口")
@ApiImplicitParam(name = "name", value = "默认字段", required = true, dataTypeClass = String.class)
@GetMapping(value = "/{name}")
@ResponseBody
public String helloWorld(@PathVariable(name = "name") String name) {
return "Hello " + name;
}
@ApiOperation(value = "添加用户", notes = "插入一条用户记录")
@ApiImplicitParam(name = "usrType", value = "用户角色", required = true, dataTypeClass = String.class)
@RequiresRoles("admin")
@RequiresPermissions("user:insert")
@PostMapping(value = "/insert")
@ResponseBody
public Response<User> saveUserInfo(@NotNull @RequestBody User sysUser, @RequestParam String usrType) {
User result = userService.saveUserInfo(sysUser);
if (result != null) {
roleService.createUserRole(usrType, result.getUsrName());
return getSuccessResult(result);
}
return getFailResult(405, "Message already exist!");
}
}
使用@APi
标记类,并取别名。
使用@ApiOperation
备注接口,可以加上 note 写更多描述信息。
使用@ApiImplicitParam
备注每一个接口中所需要的参数,注意如果参数为先前已经注解过的实体则不需要再次备注,如果参数为多个可以在@ApiImplicitParams
中内嵌@ApiImplicitParam
。具体的填写格式如下:
name:参数名
value:参数的汉字说明、解释
required:参数是否必须传
paramType:参数放在哪个地方
· header --> 请求参数的获取:@RequestHeader
· query --> 请求参数的获取:@RequestParam
· path(用于restful接口)--> 请求参数的获取:@PathVariable
· body(不常用)
· form(不常用)
dataType:参数类型,默认String,其它值dataType="Integer"
defaultValue:参数的默认值
前端内嵌网页访问文档
至此简单的优化已经完成了,如果项目工程比较大,还可以将不同的 Controller 放入不同的 Docket 中。
那么前端我们的目的就是访问先前配置的路径下的接口文档,先前 docket 中我们设置的 host 为 localhost:9988,那么访问 localhost:9988/doc.html 就可以看到接口文档了,如果没有使用推荐的 UI 包,则需要访问 swagger-ui.html。
可以看到已经有那味儿了,为了能让文档更符合我们项目的结构,更方便查阅,可以采用嵌入式的方法。在前端页面合适的组件内,使用<iframe>
标签内嵌显示文档。
<iframe src="http://test.ims.cool:9988/doc.html" width="100%" height="95%"/>
接下来我们在项目页面中直接打开文档,就可以看到内嵌效果了(我事先已经做好了一个新组件并注册在了菜单中)。
可以发现,通过优化注解,中文版的 API 文档更加方便理解,让人一目了然。
总结
本文简单介绍了一下 Swagger 的由来,从后端导包、配置、注解,到前端内嵌网页显示文档,教大家如何快速整合这一框架。在实际测试中,在访问 UI 页面时遇到过问题,采用下载官方 GitHub 的 Dist 文件夹方法解决了,如果有更好的方法比如采用前端导入的方式,请大佬们留言教教我。另外,跨域问题相信也会有一部分朋友遇到,请查阅我之前写过的文章一并解决。希望本文能帮助大家对 Swagger2 和如何整合有一个初步的概念。篇幅有限,深入的知识就只能自行学习了。