├── .gitignore
├── LICENSE
├── README.md
├── pom.xml
└── src
├── main
└── java
│ └── com
│ └── github
│ └── lkqm
│ └── spring
│ └── api
│ └── version
│ ├── ApiVersion.java
│ ├── ApiVersionAutoConfiguration.java
│ ├── ApiVersionProperties.java
│ ├── ApiVersionRequestCondition.java
│ ├── ApiVersionWebMvcRegistrations.java
│ ├── EnableApiVersioning.java
│ ├── InnerUtils.java
│ └── VersionedRequestMappingHandlerMapping.java
└── test
└── java
└── com
└── github
└── lkqm
└── spring
└── api
└── version
├── Application.java
├── InnerUtilsTest.java
├── controller
└── UserController.java
└── integration
├── UserControllerHeaderTest.java
├── UserControllerParamTest.java
├── UserControllerUrIEndTest.java
└── UserControllerUrITest.java
/.gitignore:
--------------------------------------------------------------------------------
1 | # maven ignore
2 | target/
3 | *.jar
4 | !.mvn/wrapper/*
5 | *.war
6 | *.zip
7 | *.tar
8 | *.tar.gz
9 |
10 | # eclipse ignore
11 | .settings/
12 | .project
13 | .classpath
14 |
15 | # idea ignore
16 | .idea/
17 | *.ipr
18 | *.iml
19 | *.iws
20 |
21 | # temp ignore
22 | *.log
23 | *.cache
24 | *.diff
25 | *.patch
26 | *.tmp
27 |
28 | # system ignore
29 | .DS_Store
30 | Thumbs.db
31 | *.orig
32 | *.out
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Mario Luo
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # spring-api-versioning
2 | 
3 | 
4 |
5 | Simple development of multi-version api based on spring-mvc via @ApiVersion annotation, support for uri, header, param.
6 |
7 | Supports: JDK 1.8, spring-boot 2.x
8 |
9 | ## Features
10 | - URI: /v1/user/list, /v2/user/list
11 | - Header: /user/list, header: X-API-VERSION=1
12 | - Param: /user/list?api_version=1
13 |
14 | Important: version number use precise matching with String equals method.
15 |
16 | ## Quick
17 | 1. Add Dependency(Maven)
18 | ```
19 |
20 | com.github.lkqm
21 | spring-api-versioning
22 | ${version}
23 |
24 | ```
25 |
26 | 2. @EnableApiVersioning with Application class
27 | ```
28 | @SpringBootApplication
29 | @EnableApiVersioning
30 | public class Application {
31 | public static void main(String[] args) {
32 | SpringApplication.run(Application.class, args);
33 | }
34 | }
35 | ```
36 |
37 | 3. Controller
38 | ```
39 | @RestController
40 | @RequestMapping("/user")
41 | @ApiVersion("1")
42 | public class UserController {
43 |
44 | @GetMapping("/list")
45 | public String list1() {
46 | return "list1";
47 | }
48 |
49 | @GetMapping("/list")
50 | @ApiVersion("1.1")
51 | public String list2() {
52 | return "list2";
53 | }
54 | }
55 | ```
56 | 4. Test
57 | ```
58 | curl http://127.0.0.1:8080/v1/user/list
59 | curl http://127.0.0.1:8080/v1.1/user/list
60 | ```
61 |
62 |
63 | ## Config properties
64 | ```
65 | api.version.type=uri # versioning implement way: uri(default), header, param
66 | api.version.uri-prefix= # uri prefix, if set /api, request uri like: /api/v1/... /api/v2/...
67 | api.version.uri-location= # uri version location: begin(/v1/user/list), end(/user/list/v1)
68 | api.version.header=X-API-VERSION # version control http header name
69 | api.version.param=api_version # version control http query string name
70 | ```
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 | com.github.lkqm
6 | springboot3-api-versioning
7 | 1.0.0
8 |
9 | ${project.artifactId}
10 | Simple development of multi-version api based on spring-mvc via @ApiVersion annotation, support for
11 | uri, header, param.
12 |
13 | https://github.com/lkqm/spring-api-versioning
14 |
15 |
16 | The Apache License, Version 2.0
17 | http://www.apache.org/licenses/LICENSE-2.0.txt
18 |
19 |
20 |
21 |
22 | Mario Luo
23 | luokaiqiongmou@foxmail.com
24 | https://github.com/lkqm
25 |
26 |
27 |
28 | scm:git:https://github.com/lkqm/spring-api-versioning.git
29 | scm:git:git@github.com:lkqm/spring-api-versioning.git
30 | https://github.com/lkqm/spring-api-versioning
31 | HEAD
32 |
33 |
34 | 17
35 | 17
36 | UTF-8
37 | UTF-8
38 | 3.1.5
39 |
40 |
41 |
42 |
43 |
44 | org.springframework.boot
45 | spring-boot-starter
46 | ${spring.version}
47 | true
48 |
49 |
50 | org.springframework.boot
51 | spring-boot-configuration-processor
52 | ${spring.version}
53 | true
54 |
55 |
56 | org.springframework.boot
57 | spring-boot-starter-web
58 | ${spring.version}
59 | true
60 |
61 |
62 | org.springframework.boot
63 | spring-boot-starter-test
64 | ${spring.version}
65 | test
66 |
67 |
68 |
69 | org.projectlombok
70 | lombok
71 | 1.18.30
72 | provided
73 |
74 |
75 |
76 |
77 |
78 | release
79 |
80 |
81 |
82 | org.apache.maven.plugins
83 | maven-source-plugin
84 | 2.2.1
85 |
86 |
87 | attach-sources
88 |
89 | jar-no-fork
90 |
91 |
92 |
93 |
94 |
95 | org.apache.maven.plugins
96 | maven-javadoc-plugin
97 | 2.9.1
98 |
99 |
100 | attach-javadocs
101 |
102 | jar
103 |
104 |
105 | -Xdoclint:none
106 |
107 |
108 |
109 |
110 |
111 | org.apache.maven.plugins
112 | maven-gpg-plugin
113 | 1.5
114 |
115 |
116 | sign-artifacts
117 | verify
118 |
119 | sign
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 | org.apache.maven.plugins
133 | maven-release-plugin
134 | 2.5.3
135 |
136 | v@{project.version}
137 | true
138 | false
139 | -DskipTests
140 |
141 |
142 |
143 | org.sonatype.plugins
144 | nexus-staging-maven-plugin
145 | 1.6.7
146 | true
147 |
148 | ossrh
149 | https://oss.sonatype.org/
150 | true
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 | ossrh
159 | Nexus Releases Repository
160 | https://oss.sonatype.org/service/local/staging/deploy/maven2
161 |
162 |
163 | ossrh
164 | Nexus Snapshots Repository
165 | https://oss.sonatype.org/content/repositories/snapshots
166 |
167 |
168 |
169 |
170 |
--------------------------------------------------------------------------------
/src/main/java/com/github/lkqm/spring/api/version/ApiVersion.java:
--------------------------------------------------------------------------------
1 | package com.github.lkqm.spring.api.version;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | /**
9 | * 标示当前请求版本
10 | */
11 | @Target({ElementType.TYPE, ElementType.METHOD})
12 | @Retention(RetentionPolicy.RUNTIME)
13 | public @interface ApiVersion {
14 |
15 | /**
16 | * 版本号
17 | */
18 | String value();
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/com/github/lkqm/spring/api/version/ApiVersionAutoConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.github.lkqm.spring.api.version;
2 |
3 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
4 | import org.springframework.boot.context.properties.EnableConfigurationProperties;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.context.annotation.Configuration;
7 |
8 | /**
9 | * 配置api版本
10 | */
11 | @Configuration
12 | @EnableConfigurationProperties(ApiVersionProperties.class)
13 | public class ApiVersionAutoConfiguration {
14 |
15 | @Bean
16 | @ConditionalOnMissingBean
17 | public ApiVersionWebMvcRegistrations apiVersionWebMvcRegistrations(ApiVersionProperties apiVersionProperties) {
18 | return new ApiVersionWebMvcRegistrations(apiVersionProperties);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/com/github/lkqm/spring/api/version/ApiVersionProperties.java:
--------------------------------------------------------------------------------
1 | package com.github.lkqm.spring.api.version;
2 |
3 | import lombok.Data;
4 | import org.springframework.boot.context.properties.ConfigurationProperties;
5 |
6 | import java.io.Serializable;
7 |
8 | /**
9 | * Api-Version配置
10 | */
11 | @Data
12 | @ConfigurationProperties(prefix = "api.version")
13 | public class ApiVersionProperties implements Serializable {
14 |
15 | /**
16 | * 实现多版本的方式
17 | */
18 | private Type type = Type.URI;
19 |
20 | /**
21 | * URI地址前缀, 例如: /api
22 | */
23 | private String uriPrefix;
24 |
25 | /**
26 | * URI的位置
27 | */
28 | private UriLocation uriLocation = UriLocation.BEGIN;
29 |
30 | /**
31 | * 版本请求头名
32 | */
33 | private String header = "X-API-VERSION";
34 |
35 | /**
36 | * 版本请求参数名
37 | */
38 | private String param = "api_version";
39 |
40 | public enum Type {
41 | /**
42 | * URI路径
43 | */
44 | URI,
45 | /**
46 | * 请求头
47 | */
48 | HEADER,
49 | /**
50 | * 请求参数
51 | */
52 | PARAM;
53 | }
54 |
55 | public enum UriLocation {
56 | BEGIN, END
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/com/github/lkqm/spring/api/version/ApiVersionRequestCondition.java:
--------------------------------------------------------------------------------
1 | package com.github.lkqm.spring.api.version;
2 |
3 | import jakarta.servlet.http.HttpServletRequest;
4 | import lombok.Getter;
5 | import lombok.NonNull;
6 | import org.springframework.web.servlet.mvc.condition.RequestCondition;
7 |
8 |
9 | @Getter
10 | public class ApiVersionRequestCondition implements RequestCondition {
11 |
12 | private final String apiVersion;
13 | private final ApiVersionProperties apiVersionProperties;
14 |
15 | public ApiVersionRequestCondition(@NonNull String apiVersion, @NonNull ApiVersionProperties apiVersionProperties) {
16 | this.apiVersion = apiVersion.trim();
17 | this.apiVersionProperties = apiVersionProperties;
18 | }
19 |
20 | @Override
21 | public ApiVersionRequestCondition combine(ApiVersionRequestCondition other) {
22 | // method annotation first
23 | return new ApiVersionRequestCondition(other.getApiVersion(), other.getApiVersionProperties());
24 | }
25 |
26 | @Override
27 | public int compareTo(ApiVersionRequestCondition other, HttpServletRequest request) {
28 | return other.getApiVersion().compareTo(getApiVersion());
29 | }
30 |
31 | @Override
32 | public ApiVersionRequestCondition getMatchingCondition(HttpServletRequest request) {
33 | ApiVersionProperties.Type type = apiVersionProperties.getType();
34 | String version = null;
35 | switch (type) {
36 | case HEADER:
37 | version = request.getHeader(apiVersionProperties.getHeader());
38 | break;
39 | case PARAM:
40 | version = request.getParameter(apiVersionProperties.getParam());
41 | break;
42 | }
43 | boolean match = version != null && version.length() > 0 && version.trim().equals(apiVersion);
44 | if (match) {
45 | return this;
46 | }
47 | return null;
48 | }
49 |
50 | @Override
51 | public String toString() {
52 | return "@ApiVersion(" + apiVersion + ")";
53 | }
54 | }
--------------------------------------------------------------------------------
/src/main/java/com/github/lkqm/spring/api/version/ApiVersionWebMvcRegistrations.java:
--------------------------------------------------------------------------------
1 | package com.github.lkqm.spring.api.version;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.NonNull;
5 | import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;
6 | import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
7 |
8 |
9 | @AllArgsConstructor
10 | public class ApiVersionWebMvcRegistrations implements WebMvcRegistrations {
11 |
12 | @NonNull
13 | private ApiVersionProperties apiVersionProperties;
14 |
15 | @Override
16 | public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
17 | return new VersionedRequestMappingHandlerMapping(apiVersionProperties);
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/com/github/lkqm/spring/api/version/EnableApiVersioning.java:
--------------------------------------------------------------------------------
1 | package com.github.lkqm.spring.api.version;
2 |
3 | import org.springframework.context.annotation.Import;
4 |
5 | import java.lang.annotation.ElementType;
6 | import java.lang.annotation.Retention;
7 | import java.lang.annotation.RetentionPolicy;
8 | import java.lang.annotation.Target;
9 |
10 | /**
11 | * 开启多版本API控制
12 | *
13 | * @see ApiVersionProperties 配置属性
14 | * @see ApiVersionAutoConfiguration 配置类
15 | */
16 | @Target(ElementType.TYPE)
17 | @Retention(RetentionPolicy.RUNTIME)
18 | @Import(ApiVersionAutoConfiguration.class)
19 | public @interface EnableApiVersioning {
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/com/github/lkqm/spring/api/version/InnerUtils.java:
--------------------------------------------------------------------------------
1 | package com.github.lkqm.spring.api.version;
2 |
3 | import java.util.regex.Pattern;
4 |
5 | class InnerUtils {
6 |
7 | private final static Pattern VERSION_NUMBER_PATTERN = Pattern.compile("^\\d+(\\.\\d+){0,2}$");
8 |
9 | /**
10 | * 检查版本匹配是否复合(最大三个版本)
11 | */
12 | public static void checkVersionNumber(String version, Object targetMethodOrType) {
13 | if (!matchVersionNumber(version)) {
14 | throw new IllegalArgumentException(String.format("Invalid version number: @ApiVersion(\"%s\") at %s", version, targetMethodOrType));
15 | }
16 | }
17 |
18 | /**
19 | * 判断是否满足最大3个版本号的匹配
20 | */
21 | public static boolean matchVersionNumber(String version) {
22 | return version.length() != 0 && VERSION_NUMBER_PATTERN.matcher(version).find();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/github/lkqm/spring/api/version/VersionedRequestMappingHandlerMapping.java:
--------------------------------------------------------------------------------
1 | package com.github.lkqm.spring.api.version;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.extern.slf4j.Slf4j;
5 | import org.springframework.core.annotation.AnnotatedElementUtils;
6 | import org.springframework.core.annotation.AnnotationUtils;
7 | import org.springframework.util.StringUtils;
8 | import org.springframework.web.bind.annotation.RequestMapping;
9 | import org.springframework.web.servlet.mvc.condition.RequestCondition;
10 | import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
11 | import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
12 |
13 | import java.lang.reflect.AnnotatedElement;
14 | import java.lang.reflect.Method;
15 |
16 | @Slf4j
17 | @AllArgsConstructor
18 | public class VersionedRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
19 |
20 | /**
21 | * 多版本配置属性
22 | */
23 | private ApiVersionProperties apiVersionProperties;
24 |
25 | @Override
26 | protected RequestCondition> getCustomTypeCondition(Class> handlerType) {
27 | return createRequestCondition(handlerType);
28 | }
29 |
30 | @Override
31 | protected RequestCondition> getCustomMethodCondition(Method method) {
32 | return createRequestCondition(method);
33 | }
34 |
35 | private RequestCondition createRequestCondition(AnnotatedElement target) {
36 | if (apiVersionProperties.getType() == ApiVersionProperties.Type.URI) {
37 | return null;
38 | }
39 | ApiVersion apiVersion = AnnotationUtils.findAnnotation(target, ApiVersion.class);
40 | if (apiVersion == null) {
41 | return null;
42 | }
43 | String version = apiVersion.value().trim();
44 | InnerUtils.checkVersionNumber(version, target);
45 | return new ApiVersionRequestCondition(version, apiVersionProperties);
46 | }
47 |
48 | //--------------------- 动态注册URI -----------------------//
49 | @Override
50 | protected RequestMappingInfo getMappingForMethod(Method method, Class> handlerType) {
51 | RequestMappingInfo info = this.createRequestMappingInfo(method);
52 | if (info != null) {
53 | RequestMappingInfo typeInfo = this.createRequestMappingInfo(handlerType);
54 | if (typeInfo != null) {
55 | info = typeInfo.combine(info);
56 | }
57 |
58 | // 指定URL前缀
59 | if (apiVersionProperties.getType() == ApiVersionProperties.Type.URI) {
60 | ApiVersion apiVersion = AnnotationUtils.getAnnotation(method, ApiVersion.class);
61 | if (apiVersion == null) {
62 | apiVersion = AnnotationUtils.getAnnotation(handlerType, ApiVersion.class);
63 | }
64 | if (apiVersion != null) {
65 | String version = apiVersion.value().trim();
66 | InnerUtils.checkVersionNumber(version, method);
67 |
68 | String prefix = "/v" + version;
69 | if (apiVersionProperties.getUriLocation() == ApiVersionProperties.UriLocation.END) {
70 | info = info.combine(RequestMappingInfo.paths(prefix).options(getBuilderConfiguration()).build());
71 | } else {
72 | if (StringUtils.hasText(apiVersionProperties.getUriPrefix())) {
73 | prefix = apiVersionProperties.getUriPrefix().trim() + prefix;
74 | }
75 | info = RequestMappingInfo.paths(prefix).options(getBuilderConfiguration()).build().combine(info);
76 | }
77 | }
78 | }
79 | }
80 |
81 | return info;
82 | }
83 |
84 | private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
85 | RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
86 | RequestCondition> condition = (element instanceof Class ?
87 | getCustomTypeCondition((Class>) element) : getCustomMethodCondition((Method) element));
88 | return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
89 | }
90 |
91 | }
--------------------------------------------------------------------------------
/src/test/java/com/github/lkqm/spring/api/version/Application.java:
--------------------------------------------------------------------------------
1 | package com.github.lkqm.spring.api.version;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | @EnableApiVersioning
8 | public class Application {
9 |
10 | public static void main(String[] args) {
11 | SpringApplication.run(Application.class, args);
12 | }
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/test/java/com/github/lkqm/spring/api/version/InnerUtilsTest.java:
--------------------------------------------------------------------------------
1 | package com.github.lkqm.spring.api.version;
2 |
3 |
4 | import org.junit.jupiter.api.Assertions;
5 | import org.junit.jupiter.api.Test;
6 |
7 | public class InnerUtilsTest {
8 |
9 | @Test
10 | public void matchVersionNumber() {
11 | Assertions.assertTrue(InnerUtils.matchVersionNumber("1"));
12 | Assertions.assertTrue(InnerUtils.matchVersionNumber("1.1"));
13 | Assertions.assertTrue(InnerUtils.matchVersionNumber("1.1.1"));
14 |
15 | Assertions.assertFalse(InnerUtils.matchVersionNumber("1.1.1.0"));
16 | Assertions.assertFalse(InnerUtils.matchVersionNumber(""));
17 | Assertions.assertFalse(InnerUtils.matchVersionNumber("."));
18 | Assertions.assertFalse(InnerUtils.matchVersionNumber("a.b"));
19 | }
20 | }
--------------------------------------------------------------------------------
/src/test/java/com/github/lkqm/spring/api/version/controller/UserController.java:
--------------------------------------------------------------------------------
1 | package com.github.lkqm.spring.api.version.controller;
2 |
3 | import com.github.lkqm.spring.api.version.ApiVersion;
4 | import org.springframework.web.bind.annotation.GetMapping;
5 | import org.springframework.web.bind.annotation.RequestMapping;
6 | import org.springframework.web.bind.annotation.RestController;
7 |
8 | @RestController
9 | @RequestMapping("/user")
10 | public class UserController {
11 |
12 | @GetMapping("/list")
13 | @ApiVersion("1")
14 | public String list1() {
15 | return "list1";
16 | }
17 |
18 | @GetMapping("/list")
19 | @ApiVersion("1.1")
20 | public String list2() {
21 | return "list2";
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/src/test/java/com/github/lkqm/spring/api/version/integration/UserControllerHeaderTest.java:
--------------------------------------------------------------------------------
1 | package com.github.lkqm.spring.api.version.integration;
2 |
3 | import com.github.lkqm.spring.api.version.Application;
4 | import org.junit.jupiter.api.Test;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
7 | import org.springframework.boot.test.context.SpringBootTest;
8 | import org.springframework.test.web.servlet.MockMvc;
9 |
10 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
11 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
12 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
13 |
14 | @SpringBootTest(classes = Application.class, properties = {
15 | "api.version.type=header",
16 | "api.version.header=X-API-VERSION"
17 | })
18 | @AutoConfigureMockMvc
19 | public class UserControllerHeaderTest {
20 |
21 | @Autowired
22 | private MockMvc mockMvc;
23 |
24 | @Test
25 | public void listV1() throws Exception {
26 | mockMvc.perform(get("/user/list").header("X-API-VERSION", "1"))
27 | .andExpect(status().isOk())
28 | .andExpect(content().string("list1"));
29 | }
30 |
31 | @Test
32 | public void listV2() throws Exception {
33 | mockMvc.perform(get("/user/list").header("X-API-VERSION", "1.1"))
34 | .andExpect(status().isOk())
35 | .andExpect(content().string("list2"));
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/test/java/com/github/lkqm/spring/api/version/integration/UserControllerParamTest.java:
--------------------------------------------------------------------------------
1 | package com.github.lkqm.spring.api.version.integration;
2 |
3 | import com.github.lkqm.spring.api.version.Application;
4 | import org.junit.jupiter.api.Test;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
7 | import org.springframework.boot.test.context.SpringBootTest;
8 | import org.springframework.test.web.servlet.MockMvc;
9 |
10 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
11 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
12 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
13 |
14 | @SpringBootTest(classes = Application.class, properties = {
15 | "api.version.type=param",
16 | "api.version.param=api_version"
17 | })
18 | @AutoConfigureMockMvc
19 | public class UserControllerParamTest {
20 |
21 | @Autowired
22 | private MockMvc mockMvc;
23 |
24 | @Test
25 | public void listV1() throws Exception {
26 | mockMvc.perform(get("/user/list").param("api_version", "1"))
27 | .andExpect(status().isOk())
28 | .andExpect(content().string("list1"));
29 | }
30 |
31 | @Test
32 | public void listV2() throws Exception {
33 | mockMvc.perform(get("/user/list").param("api_version", "1.1"))
34 | .andExpect(status().isOk())
35 | .andExpect(content().string("list2"));
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/test/java/com/github/lkqm/spring/api/version/integration/UserControllerUrIEndTest.java:
--------------------------------------------------------------------------------
1 | package com.github.lkqm.spring.api.version.integration;
2 |
3 | import com.github.lkqm.spring.api.version.Application;
4 | import org.junit.jupiter.api.Test;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
7 | import org.springframework.boot.test.context.SpringBootTest;
8 | import org.springframework.test.web.servlet.MockMvc;
9 |
10 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
11 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
12 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
13 |
14 | @SpringBootTest(classes = Application.class, properties = {
15 | "api.version.type=uri",
16 | "api.version.uri-location=end",
17 | })
18 | @AutoConfigureMockMvc
19 | public class UserControllerUrIEndTest {
20 |
21 | @Autowired
22 | private MockMvc mockMvc;
23 |
24 | @Test
25 | public void listV1() throws Exception {
26 | mockMvc.perform(get("/user/list/v1"))
27 | .andExpect(status().isOk())
28 | .andExpect(content().string("list1"));
29 | }
30 |
31 | @Test
32 | public void listV2() throws Exception {
33 | mockMvc.perform(get("/user/list/v1.1"))
34 | .andExpect(status().isOk())
35 | .andExpect(content().string("list2"));
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/test/java/com/github/lkqm/spring/api/version/integration/UserControllerUrITest.java:
--------------------------------------------------------------------------------
1 | package com.github.lkqm.spring.api.version.integration;
2 |
3 | import com.github.lkqm.spring.api.version.Application;
4 | import org.junit.jupiter.api.Test;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
7 | import org.springframework.boot.test.context.SpringBootTest;
8 | import org.springframework.test.web.servlet.MockMvc;
9 |
10 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
11 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
12 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
13 |
14 | @SpringBootTest(classes = Application.class, properties = {
15 | "api.version.type=uri",
16 | "api.version.uri-prefix=/api"
17 | })
18 | @AutoConfigureMockMvc
19 | public class UserControllerUrITest {
20 |
21 | @Autowired
22 | private MockMvc mockMvc;
23 |
24 | @Test
25 | public void listV1() throws Exception {
26 | mockMvc.perform(get("/api/v1/user/list"))
27 | .andExpect(status().isOk())
28 | .andExpect(content().string("list1"));
29 | }
30 |
31 | @Test
32 | public void listV2() throws Exception {
33 | mockMvc.perform(get("/api/v1.1/user/list"))
34 | .andExpect(status().isOk())
35 | .andExpect(content().string("list2"));
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------