在Spring Boot 4.0中新增了一个API版本控制的特性,它有以下几种选项可用:
- 请求头(Request header)
- 请求参数(Request parameter)
- 路径段(Path segment)
- 媒体类型参数(Media type parameter)
- 自定义
下面我们来逐一介绍。
我们先创建一个Spring Boot 4.0的工程,可以从https://start.spring.io/这个官方网站上快速创建一个Java Web的工程,Spring Boot的版本选择4.0.0,也顺便添加Spring Web依赖,点击GENERATE就可以将创建的工程下载了。
请求头
使用请求头来控制API版本就是要在header中设置版本参数,比如在header中使用API-Version参数来控制版本。
先实现Controller中的代码,也就是在这里标明不同版本的API,用version字段来设置。
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/hello")
public class VersionTestController {
@GetMapping(version = "1.0")
public String version1() {
return "hello, v1";
}
@GetMapping(version = "2.0")
public String version2() {
return "hello, v2";
}
}
写完这个VersionTestController类就可以直接运行项目了,当然启动的时候你会看到如下的错误提示:
Caused by: java.lang.IllegalStateException: API version specified, but no ApiVersionStrategy configured
at org.springframework.util.Assert.state(Assert.java:80) ~[spring-core-7.0.1.jar:7.0.1]
at org.springframework.web.servlet.mvc.method.RequestMappingInfo$DefaultBuilder.build(RequestMappingInfo.java:773) ~[spring-webmvc-7.0.1.jar:7.0.1]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.createRequestMappingInfo(RequestMappingHandlerMapping.java:385) ~[spring-webmvc-7.0.1.jar:7.0.1]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.createRequestMappingInfo(RequestMappingHandlerMapping.java:289) ~[spring-webmvc-7.0.1.jar:7.0.1]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.getMappingForMethod(RequestMappingHandlerMapping.java:207) ~[spring-webmvc-7.0.1.jar:7.0.1]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.getMappingForMethod(RequestMappingHandlerMapping.java:80) ~[spring-webmvc-7.0.1.jar:7.0.1]
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.lambda$detectHandlerMethods$0(AbstractHandlerMethodMapping.java:279) ~[spring-webmvc-7.0.1.jar:7.0.1]
... 28 common frames omitted
这是在告诉我们API版本控制需要配置策略,那我们就需要实现WebMvcConfigurer接口来配置策略,代码如下:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ApiVersionConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void configureApiVersioning(ApiVersionConfigurer configurer) {
configurer.useRequestHeader("API-Version");
}
}
增加了这个配置之后,我们再次启动项目,就能发现错误消失了,一切正常。然后可以找一个接口测试工具,比如Postman、Apifox等。
我们访问/api/hello这个接口,并在header中添加API-Version:1.0或者API-Version:2.0来测试,你会发现设置不同的版本会得到不同的返回结果。
当然,如果你不喜欢直接用代码实现WebMvcConfigurer接口来配置策略,也可以通过在application.yml中进行配置,如下:
spring:
mvc:
apiversion:
default: 2.0
use:
header: API-Version
default:2.0是表示如果你在请求接口时,不在header中配置API版本控制参数,默认返回2.0版本的接口。
请求参数
使用请求参数来控制API版本,就是类似这样的访问:/api/hello?version=1.0。其他的内容我们不需要动,只需要实现WebMvcConfigurer接口的策略修改为useQueryParam即可,代码如下:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ApiVersionConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void configureApiVersioning(ApiVersionConfigurer configurer) {
configurer.useQueryParam("version");
}
}
其实就只修改了一行代码,即:configurer.useQueryParam(“version”)。
也可以选择在application.yml中进行配置,如下:
spring:
mvc:
apiversion:
default: 2.0
use:
query-parameter: version
路径段
使用路径段来控制API版本,就是在URI中控制,类似这样:/api/v1/hello,我们需要首先调整一下Controller类的部分,代码如下:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api")
public class VersionTestController2 {
@GetMapping(path = "{version}/hello", version = "v1")
public String version1() {
return "hello, v1";
}
@GetMapping(path = "{version}/hello", version = "v2")
public String version2() {
return "hello, v2";
}
}
我们用占位符{version}来标明版本号的位置,依旧用version来配置版本,同样API策略也有需要进行修改,代码如下:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.method.HandlerTypePredicate;
import org.springframework.web.servlet.config.annotation.ApiVersionConfigurer;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void configureApiVersioning(ApiVersionConfigurer configurer) {
configurer.usePathSegment(1);
}
}
路径段控制API版本策略需要这么一行代码:configurer.usePathSegment(1)。usePathSegment()函数的参数是一个int类型,它指的是路径段的索引,像我们示例的路径段是/api/v1/hello,那么将这个路径段分割之后是这样的[api,v1,hello],版本所在位置的索引就是1,所以这里设置为1。
使用application.yml进行配置,如下:
spring:
mvc:
apiversion:
default: 2.0
use:
path-segment: 1
媒体类型参数
使用媒体类型参数控制API的版本核心在于使用HTTP的Accept请求头。比如我们在header中添加一个这样的Accept,Accept:application/json;version=1.0。首先我们看一下Controller的代码,如下:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api")
public class VersionTestController3 {
@GetMapping(path = "hello", version = "1.0")
public String version1() {
return "hello, v1";
}
@GetMapping(path = "hello", version = "2.0")
public String version2() {
return "hello, v2";
}
}
配置一下API的策略,代码如下:
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.config.annotation.ApiVersionConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void configureApiVersioning(ApiVersionConfigurer configurer) {
configurer.useMediaTypeParameter(MediaType.APPLICATION_JSON, "version");
}
}
或者在application.yml中进行配置,如下:
spring:
mvc:
apiversion:
use:
media-type-parameter:
'[application/json]': version
自定义
自定义控制API版本的核心是实现ApiVersionResolver,根据实际需要编写resolveVersion函数即可。API策略代码如下:
import jakarta.servlet.http.HttpServletRequest;
import org.jspecify.annotations.Nullable;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.accept.ApiVersionResolver;
import org.springframework.web.servlet.config.annotation.ApiVersionConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void configureApiVersioning(ApiVersionConfigurer configurer) {
configurer.useVersionResolver(new ApiVersionResolver() {
@Override
public @Nullable String resolveVersion(HttpServletRequest request) {
return "";
}
});
}
}
参考
- https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-config/api-version.html
- https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-requestmapping.html#mvc-ann-requestmapping-version
- https://docs.spring.io/spring-boot/reference/web/servlet.html#web.servlet.spring-mvc.api-versioning

677

被折叠的 条评论
为什么被折叠?



