Let SPRINGMVC restful gracefully support multiple versions

Source: Internet
Author: User

Long time no Update blog, a rare time, a record of today wrote a small tool for the needs of friends reference.

In mobile app development, the simultaneous presence of multiple versions of the interface often occurs, and the interface usually supports multiple versions, and there are several ways:

1. Differentiate different versions with different paths

Such as:

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

This can be achieved through the creation of multiple files, with the advantages of a clear structure, simple implementation, and the disadvantage of a large number of repetitive work resulting in an elegant implementation.


2. Differentiate different versions with different invocation parameters

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

"Version can also be provided via the header of the HTTP request Header"

This approach is relatively flexible and elegant, this article mainly discusses this way, directly on the code!

First define an annotation that marks the version number of the API in the controller's method:

 /**   * multi-version Restful API Support Annotation * *   @author   Tony Mu (email  protected]) *   @since   2017-07-07  */  @Target ({Elementtype.method}) @ Retention (retentionpolicy.runtime) @Documented @mapping  public  @interface   Apiversion { /**   * version code  */ double  Val UE () default  1.0;}  

Then extend the Springmvc requestmappinghandlermapping so that different implementation logic can be called depending on the version number:

/** * Custom handlermapping for support multi-value the spring MVC restful API with same URL. * Version code put into request header.       * <p> * * Spring MVC config Case: * * @Configuration * public class Webconfig extends Webmvcconfigurationsupport {* @Override protected requestmappinghandlermapping createrequestmappinghandlermapping () {* Return new Multiv Ersionrequestmappinghandlermapping (); *} *} * * Controller/action case: * * @RestController * @RequestMapping (value = '/api/product ') * public class Prod           Uctcontroller {* * @RequestMapping (value = "Detail", method = GET) * Public something detaildefault (int id) {* return something; *} * * @RequestMapping (value = "Detail", method = GET) * @RestApi (Version = 1.1) * Public something D ETAILV11 (int id) {* return something; *} * * @RequestMapping (value = "Detail", method = GET) * @    Restapi (Version = 1.2) * Public something detailV12 (int id) {*      return something; *} *} * * Client case: * * $.AJAX ({* Type: "GET", * URL: "http://www.xxx.com/api/product/detail?id=100", * headers: {* value:1.1 *}, * success:function (data) {* Do something *} * }); * * @since2017-07-07*/ Public classMultiversionrequestmappinghandlermappingextendsrequestmappinghandlermapping {Private Static FinalLogger Logger = Loggerfactory.getlogger (multiversionrequestmappinghandlermapping.class); Private Final Staticmap<string, handlermethod> handler_method_map =NewHashmap<>(); /*** Key Pattern,such as:/api/product/detail[get]@1.1*/    Private Final StaticString Handler_method_key_pattern = "%s[%s]@%s"; @Overrideprotected voidRegisterhandlermethod (Object handler, method, Requestmappinginfo mapping) {apiversion Apiversionannota tion= Method.getannotation (apiversion.class); if(Apiversionannotation! =NULL) {Registerrestapihandlermethod (handler, method, mapping, apiversionannotation); return; }        Super. Registerhandlermethod (Handler, method, mapping); } @OverrideprotectedHandlermethod Lookuphandlermethod (String Lookuppath, httpservletrequest request)throwsException {handlermethod Restapihandlermethod=Lookuprestapihandlermethod (Lookuppath, request); if(Restapihandlermethod! =NULL)            returnRestapihandlermethod; return Super. Lookuphandlermethod (Lookuppath, request); }    Private voidRegisterrestapihandlermethod (Object handler, 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); }            }        }    }    Privatehandlermethod Lookuprestapihandlermethod (string lookuppath, HttpServletRequest request) {string version=tryresolverestapiversion (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); }                returnHandlermethod; } logger.debug ("Lookup Apiversion Handlermethod of%s failed", key); }        return NULL; }    Privatestring tryresolverestapiversion (HttpServletRequest request) {string version= Request.getheader ("Version"); if(!Stringutils.hastext (version)) {String Versionfromurl= Request.getparameter ("@value");//For Debug            if(Stringutils.hastext (Versionfromurl)) {version=Versionfromurl; }        }        returnversion; }}

Refer to the code comment using the method.

Let SPRINGMVC restful gracefully support multiple versions

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.