Spring Boot 4.0 API版本控制

在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 "";
            }
        });
    }
}

参考

  1. https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-config/api-version.html
  2. https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-requestmapping.html#mvc-ann-requestmapping-version
  3. https://docs.spring.io/spring-boot/reference/web/servlet.html#web.servlet.spring-mvc.api-versioning

未来编程实验室

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值