日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

让SpringMVC Restful API优雅地支持多版本

發布時間:2025/5/22 javascript 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 让SpringMVC Restful API优雅地支持多版本 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

好久沒有更新博客,難得有空,記錄一下今天寫的一個小工具,供有需要的朋友參考。

在移動APP開發中,多版本接口同時存在的情況經常發生,通常接口支持多版本,有以下兩種方式:

1.通過不同路徑區分不同版本

如:

http://www.xxx.com/api/v1/product/detail?id=100 (版本1)
http://www.xxx.com/api/v2/product/detail?id=100 (版本2)

這種情況,可以通過建立多個文件的方式實現,優點是結構清晰、實現簡單,缺點是大量重復工作導致實現不優雅。


2.通過不同調用參數區分不同版本

如:
http://www.xxx.com/api/v1/product/detail?id=100&@version=1(版本1)
http://www.xxx.com/api/v1/product/detail?id=100&@version=2(版本2)

【version還可以通過http請求頭的header提供】

這種方式相對靈活且優雅,這篇文章主要討論這種方式,直接上代碼!

首先定義一個注解,用于在控制器的方法中標記API的版本號:

/*** Annotation for support Multi-version Restful API** @author Tony Mu(tonymu@qq.com)* @since 2017-07-07*/ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Mapping public @interface ApiVersion {/*** api version code*/double value() default 1.0;}

然后擴展SpringMVC的RequestMappingHandlerMapping,以便于根據不同的版本號,調用不同的實現邏輯:

?

/*** Custom RequestMappingHandlerMapping for support multi-version of spring mvc restful api with same url.* Version code provide by {@code ApiVersionCodeDiscoverer}.* <p>** How to use ?** Spring mvc config case:** <pre class="code">* @Configuration* public class WebConfig extends WebMvcConfigurationSupport {* @Override protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {* MultiVersionRequestMappingHandlerMapping requestMappingHandlerMapping = new MultiVersionRequestMappingHandlerMapping();* requestMappingHandlerMapping.registerApiVersionCodeDiscoverer(new DefaultApiVersionCodeDiscoverer());* return requestMappingHandlerMapping;* }* }</pre>** Controller/action case:** <pre class="code">* @RestController* @RequestMapping(value = "/api/product")* public class ProductController {** @RequestMapping(value = "detail", method = GET)* public something detailDefault(int id) {* return something;* }** @RequestMapping(value = "detail", method = GET)* @ApiVersion(value = 1.1)* public something detailV11(int id) {* return something;* }** @RequestMapping(value = "detail", method = GET)* @ApiVersion(value = 1.2)* public something detailV12(int id) {* return something;* }* }</pre>** Client case:** <pre class="code">* $.ajax({* type: "GET",* url: "http://www.xxx.com/api/product/detail?id=100",* headers: {* value: 1.1* },* success: function(data){* do something* }* });</pre>** @since 2017-07-07*/ public class MultiVersionRequestMappingHandlerMapping extends RequestMappingHandlerMapping {private static final Logger logger = LoggerFactory.getLogger(MultiVersionRequestMappingHandlerMapping.class);private final static Map<String, HandlerMethod> HANDLER_METHOD_MAP = new HashMap<>();/*** key pattern,such as:/api/product/detail[GET]@1.1*/private final static String HANDLER_METHOD_KEY_PATTERN = "%s[%s]@%s";private List<ApiVersionCodeDiscoverer> apiVersionCodeDiscoverers = new ArrayList<>();@Overrideprotected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {ApiVersion apiVersionAnnotation = method.getAnnotation(ApiVersion.class);if (apiVersionAnnotation != null) {registerMultiVersionApiHandlerMethod(handler, method, mapping, apiVersionAnnotation);return;}super.registerHandlerMethod(handler, method, mapping);}@Overrideprotected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {HandlerMethod restApiHandlerMethod = lookupMultiVersionApiHandlerMethod(lookupPath, request);if (restApiHandlerMethod != null)return restApiHandlerMethod;return super.lookupHandlerMethod(lookupPath, request);}public void registerApiVersionCodeDiscoverer(ApiVersionCodeDiscoverer apiVersionCodeDiscoverer){if(!apiVersionCodeDiscoverers.contains(apiVersionCodeDiscoverer)){apiVersionCodeDiscoverers.add(apiVersionCodeDiscoverer);}}private void registerMultiVersionApiHandlerMethod(Object handler, Method method, RequestMappingInfo mapping, ApiVersion apiVersionAnnotation) {PatternsRequestCondition patternsCondition = mapping.getPatternsCondition();RequestMethodsRequestCondition methodsCondition = mapping.getMethodsCondition();if (patternsCondition == null|| methodsCondition == null|| patternsCondition.getPatterns().size() == 0|| methodsCondition.getMethods().size() == 0) {return;}Iterator<String> patternIterator = patternsCondition.getPatterns().iterator();Iterator<RequestMethod> methodIterator = methodsCondition.getMethods().iterator();while (patternIterator.hasNext() && methodIterator.hasNext()) {String patternItem = patternIterator.next();RequestMethod methodItem = methodIterator.next();String key = String.format(HANDLER_METHOD_KEY_PATTERN, patternItem, methodItem.name(), apiVersionAnnotation.value());HandlerMethod handlerMethod = super.createHandlerMethod(handler, method);if (!HANDLER_METHOD_MAP.containsKey(key)) {HANDLER_METHOD_MAP.put(key, handlerMethod);if (logger.isDebugEnabled()) {logger.debug("register ApiVersion HandlerMethod of %s %s", key, handlerMethod);}}}}private HandlerMethod lookupMultiVersionApiHandlerMethod(String lookupPath, HttpServletRequest request) {String version = tryResolveApiVersion(request);if (StringUtils.hasText(version)) {String key = String.format(HANDLER_METHOD_KEY_PATTERN, lookupPath, request.getMethod(), version);HandlerMethod handlerMethod = HANDLER_METHOD_MAP.get(key);if (handlerMethod != null) {if (logger.isDebugEnabled()) {logger.debug("lookup ApiVersion HandlerMethod of %s %s", key, handlerMethod);}return handlerMethod;}logger.debug("lookup ApiVersion HandlerMethod of %s failed", key);}return null;}private String tryResolveApiVersion(HttpServletRequest request) {for (int i = 0; i < apiVersionCodeDiscoverers.size(); i++) {ApiVersionCodeDiscoverer apiVersionCodeDiscoverer = apiVersionCodeDiscoverers.get(i);String versionCode = apiVersionCodeDiscoverer.getVersionCode(request);if(StringUtils.hasText(versionCode))return versionCode;}return null;} }

?

使用方式參考代碼注釋。

?

以下是用到的相關代碼:

/*** Interface to discover api version code in http request.** @author Tony Mu(tonymu@qq.com)* @since 2017-07-11*/ public interface ApiVersionCodeDiscoverer {/*** Return an api version code that can indicate the version of current api.** @param request current HTTP request* @return an api version code that can indicate the version of current api or {@code null}.*/String getVersionCode(HttpServletRequest request);}

?

/*** Default implementation of the {@link ApiVersionCodeDiscoverer} interface, get api version code* named "version" in headers or named "@version" in parameters.** @author Tony Mu(tonymu@qq.com)* @since 2017-07-11*/ public class DefaultApiVersionCodeDiscoverer implements ApiVersionCodeDiscoverer {/*** Get api version code named "version" in headers or named "@version" in parameters.** @param request current HTTP request* @return api version code named "version" in headers or named "@version" in parameters.*/@Overridepublic String getVersionCode(HttpServletRequest request) {String version = request.getHeader("version");if (!StringUtils.hasText(version)) {String versionFromUrl = request.getParameter("@version");//for debugif (StringUtils.hasText(versionFromUrl)) {version = versionFromUrl;}}return version;} }

?

?

轉載于:https://www.cnblogs.com/tonymu/p/7147172.html

總結

以上是生活随笔為你收集整理的让SpringMVC Restful API优雅地支持多版本的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。