背景:最近在工作中发现,已经多次发现后台开发人员提供的接口协议和实际的业务代码不统一。这些现象往往都是因为开发人员在对接口协议调整后没有及时进行协议文档的更新造成的。
在SprintBoot中引入Swagger2依赖包很简单,在pom.xml文件中引入相应的依赖即可。
io.springfox
springfox-swagger2
2.8.0
io.springfox
springfox-swagger-ui
2.8.0
我们创建一个入门的Springboot项目。项目整体目录结构如下:
然后编写一个DemoController类,在类中添加几个方法,具体如下:
package com.majing.learning.springboot.swagger2.controller;
import com.majing.learning.springboot.swagger2.entity.User;
import io.swagger.annotations.*;
import org.springframework.web.bind.annotation.*;
import java.util.*;
@RestController
@Api(tags = "用户管理相关接口")
@RequestMapping(value="/users")
public class DemoController {
static Map users = Collections.synchronizedMap(new HashMap<>());
static{
users.put(1L, new User(1L,"majing1", "31"));
users.put(2L, new User(2L,"majing2", "32"));
users.put(3L, new User(3L,"majing3", "33"));
users.put(4L, new User(4L,"majing4", "34"));
}
@ApiOperation(value="获取用户列表", notes="")
@RequestMapping(value={""}, method= RequestMethod.GET)
@ApiResponses(value={@ApiResponse(code=9001, message="OK"),@ApiResponse(code=9002, message="ERROR")})
public List getUserList() {
List r = new ArrayList(users.values());
return r;
}
@ApiOperation(value="创建用户", notes="根据User对象创建用户")
@ApiImplicitParam(name = "user", value = "用户详细实体user", required = true, dataType = "User")
@RequestMapping(value="/", method=RequestMethod.POST)
public String postUser(@RequestBody User user) {
users.put(user.getId(), user);
return "success";
}
@ApiOperation(value="获取用户详细信息", notes="根据url的id来获取用户详细信息")
@ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "Long")
@RequestMapping(value="/{id}", method=RequestMethod.GET)
public User getUser(@PathVariable Long id) {
return users.get(id);
}
@ApiOperation(value="更新用户详细信息", notes="根据url的id来指定更新对象,并根据传过来的user信息来更新用户详细信息")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "Long"),
@ApiImplicitParam(name = "user", value = "用户详细实体user", required = true, dataType = "User")
})
@RequestMapping(value="/{id}", method=RequestMethod.PUT)
public String putUser(@PathVariable Long id, @RequestBody User user) {
User u = users.get(id);
u.setName(user.getName());
u.setAge(user.getAge());
users.put(id, u);
return "success";
}
@ApiOperation(value="删除用户", notes="根据url的id来指定删除对象")
@ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "Long")
@RequestMapping(value="/{id}", method=RequestMethod.DELETE)
public String deleteUser(@PathVariable Long id) {
users.remove(id);
return "success";
}
}
对于上面的实体类User定义如下:
package com.majing.learning.springboot.swagger2.entity;
import io.swagger.annotations.ApiModel;
@ApiModel
public class User {
private Long id;
private String name;
private String age;
public User(long id, String name, String age){
this.id = id;
this.name = name;
this.age = age;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
为了使用Swagger2,需要在应用启动类同级目录加上Swagger2的配置及注解,具体如下:
package com.majing.learning.springboot.swagger2;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
public class Swagger2Config {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.majing.learning.springboot.swagger2.controller"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Spring Boot中使用Swagger2构建RESTful APIs")
.description("测试使用Swagger2生成API文档")
.termsOfServiceUrl("https://***.com/")
.contact("马靖")
.version("1.0")
.build();
}
}
接下来我们启动应用程序,然后访问http://localhost:5002/swagger-ui.html,即可看到自动生成的API文档。这里的端口根据需要在application.properties文件自行调整。
至此,在SpringBoot2中集成Swagger2便完成了,看了下生成的API文档,感觉还是不错的。
上面的示例是没问题的,但是最开始尝试集成Swagger2时遇到个启动报错,其中有一段错误信息如下:
AnnotationConfigServletWebServerApplicationContext: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'linkDiscoverers' defined in class path resource [org/springframework/hateoas/config/HateoasConfiguration.class]: Unsatisfied dependency expressed through method 'linkDiscoverers' parameter 0; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.springframework.plugin.core.PluginRegistry' available: expected single matching bean but found 15: modelBuilderPluginRegistry,modelPropertyBuilderPluginRegistry,typeNameProviderPluginRegistry,documentationPluginRegistry,apiListingBuilderPluginRegistry,operationBuilderPluginRegistry,parameterBuilderPluginRegistry,expandedParameterBuilderPluginRegistry,resourceGroupingStrategyRegistry,operationModelsProviderPluginRegistry,defaultsProviderPluginRegistry,pathDecoratorRegistry,relProviderPluginRegistry,linkDiscovererRegistry,entityLinksPluginRegistry
刚开始看到这个错误有点懵逼,后来百度了下,说是Swagger2版本和Springboot版本不兼容导致,所以就修改了下Swagger2的版本,用了2.8.0,我自己的SpringBoot版本是2.3.0,重新启动了下,发现问题真的没有了。这里做个记录。
上面我们通过Swagger2实现了后台代码动态生成和更新API文档,非常方便。但是有个缺点是没有访问权限的控制,数据Mock等功能。而且存在一定的代码侵入。后来针对国内外的API接口管理平台给调研了下,主要看了下ShowDoc、阿里云的RAP和CRAP-API,觉得都还挺好用的,有需要的可以自己研究下,这三个都是可以支持私有化部署的。