激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - SpringBoot API增加version版本號方式

SpringBoot API增加version版本號方式

2022-02-19 14:34一只懶惰的程序猿 Java教程

這篇文章主要介紹了SpringBoot API增加version版本號方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

SpringBoot 增加 API Version

基于restful風格上,增加version版本號

例如: get /api/v1/users/

一、增加ApiVersion自定義注解

作用于Controller上,指定API版本號

這里版本號使用了double ,考慮到小版本的情況,例如1.1

?
1
2
3
4
5
6
7
8
9
10
11
12
13
import java.lang.annotation.*;
/**
 * API Version type
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ApiVersion {
    /**
     * api version begin 1
     */
    double version() default 1;
}

二、新增RequestCondition自定義匹配條件

Spring提供RequestCondition接口,用于定義API匹配條件

這里通過自定義匹配條件,識別ApiVersion,進行版本匹配

getMatchingCondition 用于檢查URL中,是否符合/v{版本號},用于過濾無版本號接口;

compareTo 用于決定多個相同API時,使用哪個接口進行處理;

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import org.springframework.web.servlet.mvc.condition.RequestCondition;
import javax.servlet.http.HttpServletRequest;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * API version condition
 * @author w
 * @date 2020-11-16
 */
public class ApiVersionCondition implements RequestCondition<ApiVersionCondition> {
    /**
     * 接口路徑中的版本號前綴,如: api/v[1-n]/test
     */
    private final static Pattern VERSION_PREFIX_PATTERN = Pattern.compile("/v([0-9]+\\.{0,1}[0-9]{0,2})/");
    /** API VERSION interface **/
    private ApiVersion apiVersion;
    ApiVersionCondition(ApiVersion apiVersion){
        this.apiVersion = apiVersion;
    }
    /**
     * [當class 和 method 請求url相同時,觸發(fā)此方法用于合并url]
     * 官方解釋:
     * - 某個接口有多個規(guī)則時,進行合并
     * - 比如類上指定了@RequestMapping的 url 為 root
     * - 而方法上指定的@RequestMapping的 url 為 method
     * - 那么在獲取這個接口的 url 匹配規(guī)則時,類上掃描一次,方法上掃描一次,這個時候就需要把這兩個合并成一個,表示這個接口匹配root/method
     * @param other 相同api version condition
     * @return ApiVersionCondition
     */
    @Override
    public ApiVersionCondition combine(ApiVersionCondition other) {
        // 此處按優(yōu)先級,method大于class
        return new ApiVersionCondition(other.getApiVersion());
    }
    /**
     * 判斷是否成功,失敗返回 null;否則,則返回匹配成功的條件
     * @param httpServletRequest http request
     * @return 匹配成功條件
     */
    @Override
    public ApiVersionCondition getMatchingCondition(HttpServletRequest httpServletRequest) {
        // 通過uri匹配版本號
        System.out.println(httpServletRequest.getRequestURI());
        Matcher m = VERSION_PREFIX_PATTERN.matcher(httpServletRequest.getRequestURI());
        if (m.find()) {
            // 獲得符合匹配條件的ApiVersionCondition
            System.out.println("groupCount:"+m.groupCount());
            double version = Double.valueOf(m.group(1));
            if (version >= getApiVersion().version()) {
                return this;
            }
        }
        return null;
    }
    /**
     * 多個都滿足條件時,用來指定具體選擇哪一個
     * @param other 多個時
     * @param httpServletRequest http request
     * @return 取版本號最大的
     */
    @Override
    public int compareTo(ApiVersionCondition other, HttpServletRequest httpServletRequest) {
        // 當出現多個符合匹配條件的ApiVersionCondition,優(yōu)先匹配版本號較大的
        return other.getApiVersion().version() >= getApiVersion().version() ? 1 : -1;
    }
    public ApiVersion getApiVersion() {
        return apiVersion;
    }
}

三、重寫RequestMappingHandlerMapping處理

通過重寫 RequestMappingHandlerMapping 類,對RequestMappering進行識別@ApiVersion注解,針對性處理;

這里考慮到有些接口不存在版本號,則使用Spring原來的ApiVersionRequestMappingHandlerMapping繼續(xù)處理;

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.servlet.mvc.condition.RequestCondition;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import java.lang.reflect.Method;
/**
 * API version setting
 * @author w
 * @date 2020-11-15
 */
public class ApiVersionRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
    /**
     * class condition
     * - 在class上加@ApiVersion注解&url加{version}
     * @param handlerType class type
     * @return ApiVersionCondition
     */
    @Override
    protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) {
        ApiVersion apiVersion = AnnotationUtils.findAnnotation(handlerType,ApiVersion.class);
        return null == apiVersion ? super.getCustomTypeCondition(handlerType) : new ApiVersionCondition(apiVersion);
    }
    /**
     * method condition
     * - 在方法上加@ApiVersion注解&url加{version}
     * @param method method object
     * @return ApiVersionCondition
     */
    @Override
    protected RequestCondition<?> getCustomMethodCondition(Method method) {
        ApiVersion apiVersion = AnnotationUtils.findAnnotation(method,ApiVersion.class);
        return null == apiVersion ? super.getCustomMethodCondition(method) : new ApiVersionCondition(apiVersion);
    }
}

四、Controller接口增加@ApiVersion注解

通過@ApiVersion注解指定該接口版本號

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import com.panda.common.web.controller.BasicController;
import com.panda.common.web.version.ApiVersion;
import com.panda.core.umc.service.UserInfoService;
import com.panda.core.umc.vo.QueryUsersConditionVo;
import com.panda.face.umc.dto.user.QueryUsersReq;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
/**
 * 用戶信息服務
 * @author w
 * @date 2020-11-06
 */
@RequestMapping("/api")
@RestController
public class UserInfoController extends BasicController{
    @Autowired
    private UserInfoService userInfoService;
    /**
     * 查詢所有用戶信息
     * @param req 查詢條件信息
     */
    @ApiVersion
    @RequestMapping(value = "{version}/users", method = RequestMethod.GET)
    @ResponseBody
    public ResponseEntity getUsers(@PathVariable("version") String version, QueryUsersReq req){
        QueryUsersConditionVo condition = new QueryUsersConditionVo();
        BeanUtils.copyProperties(req,condition);
        condition.setOrderBy("CREATE_TIME");
        condition.setSort("DESC");
        return assemble("1111");
    }
    /**
     * 查詢所有用戶信息
     * @param req 查詢條件信息
     */
    @ApiVersion(version = 1.1)
    @RequestMapping(value = "{version}/users", method = RequestMethod.GET)
    @ResponseBody
    public ResponseEntity getUsersV2(@PathVariable("version") String version, QueryUsersReq req){
        QueryUsersConditionVo condition = new QueryUsersConditionVo();
        BeanUtils.copyProperties(req,condition);
        condition.setOrderBy("CREATE_TIME");
        condition.setSort("DESC");
        return assemble("222");
    }
    /**
     * 根據用戶ID獲取用戶信息
     * @param userId 用戶ID
     */
    @RequestMapping(value = "/users/uid/{userId}", method = RequestMethod.GET)
    @ResponseBody
    public ResponseEntity getUserInfo(@PathVariable("userId") String userId){
        return assemble(userInfoService.selectByUserId(userId));
    }
}

五、測試調用

通過訪問以下URL,測試返回結果

GET http://127.0.0.1/api/v1/users

GET http://127.0.0.1/api/v1.1/users

GET http://127.0.0.1/api/v1.2/users

GET http://127.0.0.1/api/users/uid/U0001

六、總結

1.通過@ApiVersion注解方式,可以靈活指定接口版本;

2.缺點很明顯,需要在URL上加入{version},才能進行匹配成功,這種PathVariable識別過于模糊,后期排查問題增加困難;

3.建議通過包名增加v1/v2明顯區(qū)分版本,且在controller的URL上直接寫死v1版本號,這種更直觀;

SpringBoot的項目API版本控制

一、自定義版本號標記注解

?
1
2
3
4
5
6
7
8
9
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ApiVersion {
    /**
     * 標識版本號,從1開始
     */
    int value() default 1;
}

二、重寫RequestCondition,自定義url匹配邏輯

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
@Data
@Slf4j
public class ApiVersionCondition implements RequestCondition<ApiVersionCondition> {
    /**
     * 接口路徑中的版本號前綴,如: api/v[1-n]/fun
     */
    private final static Pattern VERSION_PREFIX = Pattern.compile("/v(\\d+)/");
    private int apiVersion;
    ApiVersionCondition(int apiVersion) {
        this.apiVersion = apiVersion;
    }
    /**
     * 最近優(yōu)先原則,方法定義的 @ApiVersion > 類定義的 @ApiVersion
     */
    @Override
    public ApiVersionCondition combine(ApiVersionCondition other) {
        return new ApiVersionCondition(other.getApiVersion());
    }
    /**
     * 獲得符合匹配條件的ApiVersionCondition
     */
    @Override
    public ApiVersionCondition getMatchingCondition(HttpServletRequest request) {
        Matcher m = VERSION_PREFIX.matcher(request.getRequestURI());
        if (m.find()) {
            int version = Integer.valueOf(m.group(1));
            if (version >= getApiVersion()) {
                return this;
            }
        }
        return null;
    }
    /**
     * 當出現多個符合匹配條件的ApiVersionCondition,優(yōu)先匹配版本號較大的
     */
    @Override
    public int compareTo(ApiVersionCondition other, HttpServletRequest request) {
        return other.getApiVersion() - getApiVersion();
    }
}

說明:

getMatchingCondition方法中,控制了只有版本小于等于請求參數中的版本的 ApiCondition 才滿足規(guī)則

compareTo 指定了當有多個ApiCoondition滿足這個請求時,選擇最大的版本

三、重寫RequestMappingHandlerMapping,自定義匹配的處理器

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class ApiRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
    @Override
    protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) {
        // 掃描類上的 @ApiVersion
        ApiVersion apiVersion = AnnotationUtils.findAnnotation(handlerType, ApiVersion.class);
        return createRequestCondition(apiVersion);
    }
    @Override
    protected RequestCondition<?> getCustomMethodCondition(Method method) {
        // 掃描方法上的 @ApiVersion
        ApiVersion apiVersion = AnnotationUtils.findAnnotation(method, ApiVersion.class);
        return createRequestCondition(apiVersion);
    }
    private RequestCondition<ApiVersionCondition> createRequestCondition(ApiVersion apiVersion) {
        if (Objects.isNull(apiVersion)) {
            return null;
        }
        int value = apiVersion.value();
        Assert.isTrue(value >= 1, "Api Version Must be greater than or equal to 1");
        return new ApiVersionCondition(value);
    }
}

四、配置注冊自定義WebMvcRegistrations

?
1
2
3
4
5
6
7
@Configuration
public class WebMvcRegistrationsConfig implements WebMvcRegistrations {
    @Override
    public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
        return new ApiRequestMappingHandlerMapping();
    }
}

五、編寫測試接口

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@RestController
@RequestMapping("/api/{version}")
public class ApiControler {
    @GetMapping("/fun")
    public String fun1() {
        return "fun 1";
    }
    @ApiVersion(5)
    @GetMapping("/fun")
    public String fun2() {
        return "fun 2";
    }
    @ApiVersion(9)
    @GetMapping("/fun")
    public String fun3() {
        return "fun 5";
    }
}

頁面測試效果:

SpringBoot API增加version版本號方式

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持服務器之家。

原文鏈接:https://blog.csdn.net/bluewait321/article/details/110192577

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 成年免费观看视频 | 在线视频观看国产 | 一区二区三区日韩在线 | 午夜视频福利 | 亚洲一区二区国产 | 一本在线高清码电影 | 成人午夜免费福利 | 毛片在线免费 | 久久免费视频8 | 午夜小视频免费观看 | 黄色羞羞视频在线观看 | 毛片a级毛片免费播放100 | 欧美日韩在线播放 | 久久国产精品久久久久 | 久久精品国产亚洲7777 | 91在线精品亚洲一区二区 | 99久久久| 看片一区 | 成人福利在线观看 | 精品1| freexxxx性女hd性吃奶 | 午夜精品福利影院 | 欧美a∨一区二区三区久久黄 | 色偷偷一区 | 91精品国产刺激国语对白 | 成人免费电影av | 日本成人在线免费 | 日韩精品免费一区二区三区 | 成人男女啪啪免费观看网站四虎 | 欧美成人一级 | 国产精品成人一区二区三区吃奶 | 国产免费看片 | 亚洲免费网站 | 国产精品一区2区3区 | 高潮激情aaaaa免费看 | 国产免费中文字幕 | 国产女厕一区二区三区在线视 | 亚洲一区二区国产 | 久久久日韩av免费观看下载 | 欧美日本另类 | 久久久国产视频 |