springmvc实现restful api版本控制并兼容swagger的方法
一、Restful API版本控制
1、版本控制的概述
RESTful API版本控制是一种常见的API管理方式,主要是为了在API更新过程中不破坏已有的API接口,避免数据的不兼容或API过时而导致使用者的不满,通常会结合请求头中的Accept或者X-Version参数来标识当前请求的API版本。
2、版本控制的方案
(1)URL 方案
利用URL的路径来标识版本号,如api.example.com/v1/xxx。
优点: 相对简单易懂,扩展性好。
缺点: 如果后续需要调整版本控制,会存在大量URL重构的情况。
(2)参数方案
利用查询字符串参数或请求头来标识版本号,如api.example.com/xxx?v=1。
优点: 相对简单,易于控制版本和参数。
缺点: 在接口设计上需要规定好参数名称和取值,容易与业务参数混淆。
(3)Header 方案
利用请求头中的Accept或X-Version参数来标识版本号,如Accept: application/json; version=1。
优点: 与业务参数完全分离,易于设计;容易扩展多个版本,不需要URL重构,兼容http1.1和http2等多种协议。
缺点: 在接口文档中需要明确说明API版本和请求头的使用说明。
二、SpringMVC集成Swagger
1、Swagger的简介
Swagger是一个API文档自动生成工具,可以通过注解的方式将API规范描述和文档生成在一起,支持多种语言和多种框架的集成,可以自动生成HTML、Markdown和PDF等多种格式的文档。
2、SpringMVC集成Swagger的方法
(1)添加Swagger依赖
在pom.xml文件中添加如下依赖:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.10.5</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.10.5</version>
</dependency>
(2)创建Swagger配置类
创建SwaggerConfig类,并添加如下注解:
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build()
.apiInfo(apiInfo());
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("接口文档")
.version("1.0")
.build();
}
}
上述配置会扫描所有的请求,生成文档,在访问http://host:port/swagger-ui.html 或者http://host:port/v2/api-docs 可以看到swagger的界面和API接口的文档描述。
(3)增加接口注解
在需要生成文档的方法上添加@Api注解、@ApiOperation注解、@ApiImplicitParam注解等,其中@Api用来描述整个接口,@ApiOperation用来描述接口的方法,@ApiImplicitParam用来描述接口参数。
@Api(value = "登录", tags = "用户")
@RestController
@RequestMapping("/api/user")
public class UserController {
@ApiOperation(value = "用户登录", notes = "用户登录接口")
@ApiImplicitParams({
@ApiImplicitParam(paramType = "query", name = "username", value = "用户名", required = true),
@ApiImplicitParam(paramType = "query", name = "password", value = "密码", required = true)
})
@RequestMapping(value = "/login", method = RequestMethod.POST)
public Result login(String username, String password) {
return userService.login(username, password);
}
}
(4)版本号处理
在Swagger提供的上述配置中,并未处理版本号的问题,需要自行定制处理,在上述SwaggerConfig中添加如下代码:
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("com.example.demo.controller"))
.paths(PathSelectors.any())
.build()
.apiInfo(apiInfo())
.groupName("user")
.directModelSubstitute(Date.class, String.class)
.globalOperationParameters(createGlobalParam())
.useDefaultResponseMessages(false)
.pathMapping("/api/{version}")
.enableUrlTemplating(false)
.ignoredParameterTypes(HttpServletResponse.class)
.genericModelSubstitutes(ResponseEntity.class)
.securitySchemes(Collections.singletonList(apiKey()))
.securityContexts(Collections.singletonList(securityContext()))
.tags(new Tag("登录", "用户相关接口"))
.enable(true);
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("API文档")
.description("API文档")
.version("1.0")
.contact(new Contact("项目名称", "http://www.baidu.com","xxx@163.com"))
.build();
}
private ApiKey apiKey() {
return new ApiKey("token", "token", "header");
}
public List<Parameter> createGlobalParam() {
List<Parameter> globalParam = new ArrayList<Parameter>();
globalParam.add(new ParameterBuilder()
.name("version")
.description("API版本,默认为v1")
.modelRef(new ModelRef("string"))
.parameterType("header")
.required(false)
.defaultValue("v1")
.build());
return globalParam;
}
private SecurityContext securityContext() {
return SecurityContext.builder()
.securityReferences(Collections.singletonList(new SecurityReference("token", new AuthorizationScope[]{new AuthorizationScope("global", "accessEverything")})))
.forPaths(PathSelectors.any())
.build();
}
}
上述配置中,增加了pathMapping()方法,将版本号写死为/api/v1,同时通过createGlobalParam()添加了版本号的请求头,并默认为v1。需要注意的是,由于Swagger2使用了WebMvcConfigurerAdapter来加载,如果同时使用了SpringMVC等其他框架,可能会产生冲突,导致全局异常处理等无法正常工作。
参考资料:
Springfox Documentation
官方GitHub
《Spring Cloud微服务实战》
《Spring Cloud与Docker微服务架构实战》
《深入浅出Spring Boot 2.x》
《深入浅出Spring Cloud》
《Spring Boot编程思想》
思否开发者社区
