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