├── .gitignore ├── README.md ├── pom.xml └── src └── main ├── java └── com │ └── mspapant │ └── example │ └── restVersion │ ├── RestVersioningApplication.java │ ├── conf │ ├── WebConfig.java │ ├── WebConfiguration.java │ └── mapping │ │ └── VersionRequestMappingHandlerMapping.java │ └── controller │ └── UserController.java └── resources ├── application.properties └── banner.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Java template 3 | *.class 4 | 5 | # Mobile Tools for Java (J2ME) 6 | .mtj.tmp/ 7 | 8 | # Package Files # 9 | *.jar 10 | *.war 11 | *.ear 12 | 13 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 14 | hs_err_pid* 15 | 16 | # maven 17 | target/ 18 | pom.xml.tag 19 | pom.xml.releaseBackup 20 | pom.xml.versionsBackup 21 | pom.xml.next 22 | release.properties 23 | dependency-reduced-pom.xml 24 | buildNumber.properties 25 | .mvn/timing.properties 26 | 27 | # Intellij 28 | # User-specific stuff: 29 | .idea/ 30 | 31 | /*.iml 32 | ## File-based project format: 33 | *.iws 34 | 35 | ## Plugin-specific files: 36 | 37 | # IntelliJ 38 | /out/ 39 | 40 | # mpeltonen/sbt-idea plugin 41 | .idea_modules/ 42 | 43 | # JIRA plugin 44 | atlassian-ide-plugin.xml 45 | 46 | # Crashlytics plugin (for Android Studio and IntelliJ) 47 | com_crashlytics_export_strings.xml 48 | crashlytics.properties 49 | crashlytics-build.properties 50 | fabric.properties 51 | 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Alt text](http://g.gravizo.com/g? 2 | digraph G { 3 | rankdir=LR; 4 | "FILE" -> "FileParseActivator" -> "StringToProductTransformer" -> "ProductNormalizerTransformer" -> "PersistProductFilter" -> "AggregatorActivator" -> "PersistProductActivator" 5 | } 6 | ) 7 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.springframework.boot 8 | spring-boot-dependencies 9 | 1.3.7.RELEASE 10 | 11 | com.mspapant.example 12 | rest-versioning 13 | 1.0-SNAPSHOT 14 | mspapant 15 | 16 | 17 | 18 | org.springframework.boot 19 | spring-boot-starter-web 20 | 21 | 22 | io.springfox 23 | springfox-swagger2 24 | 2.5.0 25 | 26 | 27 | io.springfox 28 | springfox-swagger-ui 29 | 2.5.0 30 | 31 | 32 | 33 | 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-maven-plugin 38 | 39 | true 40 | 41 | 42 | 43 | package-artifacts 44 | package 45 | 46 | repackage 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /src/main/java/com/mspapant/example/restVersion/RestVersioningApplication.java: -------------------------------------------------------------------------------- 1 | package com.mspapant.example.restVersion; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration; 7 | import org.springframework.context.annotation.ComponentScan; 8 | 9 | @SpringBootApplication 10 | @EnableAutoConfiguration 11 | public class RestVersioningApplication { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(RestVersioningApplication.class, args); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/mspapant/example/restVersion/conf/WebConfig.java: -------------------------------------------------------------------------------- 1 | package com.mspapant.example.restVersion.conf; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.web.servlet.config.annotation.EnableWebMvc; 5 | import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; 6 | import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; 7 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 8 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 9 | 10 | /** 11 | * TODO comments. 12 | * 13 | * @author : Manos Papantonakos on 11/6/2016. 14 | */ 15 | @Configuration 16 | @EnableWebMvc 17 | @EnableSwagger2 18 | public class WebConfig extends WebMvcConfigurerAdapter { 19 | 20 | @Override 21 | public void addResourceHandlers(ResourceHandlerRegistry registry) { 22 | registry.addResourceHandler("/**").addResourceLocations("classpath:/META-INF/resources/"); 23 | } 24 | } -------------------------------------------------------------------------------- /src/main/java/com/mspapant/example/restVersion/conf/WebConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.mspapant.example.restVersion.conf; 2 | 3 | import com.mspapant.example.restVersion.conf.mapping.VersionRequestMappingHandlerMapping; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.web.accept.ContentNegotiationManager; 8 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; 9 | import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; 10 | 11 | @Configuration 12 | public class WebConfiguration extends WebMvcConfigurationSupport { 13 | 14 | @Autowired 15 | private ContentNegotiationManager contentNegotiationManager; 16 | 17 | @Bean 18 | public RequestMappingHandlerMapping requestMappingHandlerMapping() { 19 | VersionRequestMappingHandlerMapping handlerMapping = new VersionRequestMappingHandlerMapping(); 20 | handlerMapping.setOrder(0); 21 | handlerMapping.setRemoveSemicolonContent(false); 22 | handlerMapping.setContentNegotiationManager(contentNegotiationManager); 23 | 24 | return handlerMapping; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/mspapant/example/restVersion/conf/mapping/VersionRequestMappingHandlerMapping.java: -------------------------------------------------------------------------------- 1 | package com.mspapant.example.restVersion.conf.mapping; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.web.method.HandlerMethod; 5 | import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; 6 | 7 | import javax.servlet.http.HttpServletRequest; 8 | import javax.servlet.http.HttpServletRequestWrapper; 9 | 10 | public class VersionRequestMappingHandlerMapping extends RequestMappingHandlerMapping { 11 | 12 | @Value("${server.apiContext}") 13 | private String apiContext; 14 | 15 | @Value("${server.versionContext}") 16 | private String versionContext; 17 | 18 | @Override 19 | protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { 20 | HandlerMethod method = super.lookupHandlerMethod(lookupPath, request); 21 | if (method == null && lookupPath.contains(getApiAndVersionContext())) { 22 | String afterAPIURL = lookupPath.substring(lookupPath.indexOf(getApiAndVersionContext()) + getApiAndVersionContext().length()); 23 | String version = afterAPIURL.substring(0, afterAPIURL.indexOf("/")); 24 | String path = afterAPIURL.substring(version.length() + 1); 25 | 26 | int previousVersion = getPreviousVersion(version); 27 | if (previousVersion != 0) { 28 | lookupPath = getApiAndVersionContext() + previousVersion + "/" + path; 29 | final String lookupFinal = lookupPath; 30 | return lookupHandlerMethod(lookupPath, new HttpServletRequestWrapper(request) { 31 | @Override 32 | public String getRequestURI() { 33 | return lookupFinal; 34 | } 35 | 36 | @Override 37 | public String getServletPath() { 38 | return lookupFinal; 39 | }}); 40 | } 41 | } 42 | return method; 43 | } 44 | 45 | private String getApiAndVersionContext() { 46 | return "/" + apiContext + "/" + versionContext; 47 | } 48 | 49 | private int getPreviousVersion(final String version) { 50 | return new Integer(version) - 1 ; 51 | } 52 | } -------------------------------------------------------------------------------- /src/main/java/com/mspapant/example/restVersion/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.mspapant.example.restVersion.controller; 2 | 3 | import io.swagger.annotations.Api; 4 | import io.swagger.annotations.ApiOperation; 5 | import org.springframework.stereotype.Controller; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.RequestMethod; 8 | import org.springframework.web.bind.annotation.ResponseBody; 9 | 10 | /** 11 | * The user controller. 12 | * 13 | * @author : Manos Papantonakos on 19/8/2016. 14 | */ 15 | @Controller 16 | @Api(value = "user", description = "Operations about users") 17 | public class UserController { 18 | 19 | /** 20 | * Return the user. 21 | * 22 | * @return the user 23 | */ 24 | @ResponseBody 25 | @RequestMapping(method = RequestMethod.GET, value = "/api/v1/user") 26 | @ApiOperation(value = "Returns user", notes = "Returns the user", tags = {"GET", "User"}) 27 | public String getUserV1() { 28 | return "User V1"; 29 | } 30 | 31 | /** 32 | * Return the user. 33 | * 34 | * @return the user 35 | */ 36 | @ResponseBody 37 | @RequestMapping(method = RequestMethod.GET, value = "/api/v2/user") 38 | @ApiOperation(value = "Returns user", notes = "Returns the user", tags = {"GET", "User"}) 39 | public String getUserV2() { 40 | return "User V2"; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # Server Properties 2 | # ----------------- 3 | server.port=9001 4 | server.contextPath=/ 5 | server.apiContext=api 6 | server.versionContext=v -------------------------------------------------------------------------------- /src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | _____ _ __ __ _ ______ _ 2 | | __ \ | | \ \ / / (_) | ____| | | 3 | | |__) |___ ___| |_ \ \ / /__ _ __ ___ _ ___ _ __ | |__ __ ____ _ _ __ ___ _ __ | | ___ 4 | | _ // _ \/ __| __| \ \/ / _ \ '__/ __| |/ _ \| '_ \ | __| \ \/ / _` | '_ ` _ \| '_ \| |/ _ \ 5 | | | \ \ __/\__ \ |_ \ / __/ | \__ \ | (_) | | | | | |____ > < (_| | | | | | | |_) | | __/ 6 | |_| \_\___||___/\__| \/ \___|_| |___/_|\___/|_| |_| |______/_/\_\__,_|_| |_| |_| .__/|_|\___| 7 | | | 8 | |_| --------------------------------------------------------------------------------