项目中需要兼顾老项目,同时提供新的接口,这时就需要实现多版本,小事安排:
1 自定义注解:
@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface ApiVersion { double value() default 0; }
2 自定义一个RequestCondition
import org.springframework.web.servlet.mvc.condition.RequestCondition; import javax.servlet.http.HttpServletRequest; public class ApiVersionCondition implements RequestCondition<ApiVersionCondition> { private double version; public ApiVersionCondition(double version) { this.version = version; } public double getVersion() { return version; } /** * 和另外的请求匹配条件进行合并,具体合并逻辑由实现提供 * * @param apiVersionCondition * @return */ @Override public ApiVersionCondition combine(ApiVersionCondition apiVersionCondition) { return new ApiVersionCondition(apiVersionCondition.getVersion()); } /** * 检查当前请求匹配条件和指定请求request是否匹配,如果不匹配返回null * 如果匹配,生成一个新的请求匹配条件,该新的请求匹配条件是当前请求匹配条件 * 针对指定请求request的剪裁。 * 举个例子来讲,如果当前请求匹配条件是一个路径匹配条件,包含多个路径匹配模板, * 并且其中有些模板和指定请求request匹配,那么返回的新建的请求匹配条件将仅仅 * 包含和指定请求request匹配的那些路径模板。 * * @param httpServletRequest * @return */ @Override public ApiVersionCondition getMatchingCondition(HttpServletRequest httpServletRequest) { String requestURI = httpServletRequest.getRequestURI(); return this; } /** * 针对指定的请求对象request比较两个请求匹配条件。 * 该方法假定被比较的两个请求匹配条件都是针对该请求对象request调用了 * #getMatchingCondition方法得到的,这样才能确保对它们的比较 * 是针对同一个请求对象request,这样的比较才有意义(最终用来确定谁是 * 更匹配的条件)。 * * @param apiVersionCondition * @param httpServletRequest * @return */ @Override public int compareTo(ApiVersionCondition apiVersionCondition, HttpServletRequest httpServletRequest) { return Double.compare(apiVersionCondition.getVersion(),this.getVersion()); } }
3 自定义RequestMappingHandlerMapping
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; public class VersionRequestMappingHandlerMapping extends RequestMappingHandlerMapping { @Override protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) { ApiVersion annotation = AnnotationUtils.findAnnotation(handlerType, ApiVersion.class); return createCondition(annotation); } @Override protected RequestCondition<?> getCustomMethodCondition(Method method) { ApiVersion annotation = AnnotationUtils.findAnnotation(method, ApiVersion.class); return createCondition(annotation); } private ApiVersionCondition createCondition(ApiVersion annotation) { return null == annotation ? null : new ApiVersionCondition(annotation.value()); } }
4 将自定义的RequestMappingHandlerMapping放入到spring中
import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; @SpringBootConfiguration public class ApiVersionWebMvcRegistrationsAdapter implements WebMvcRegistrations { @Override public RequestMappingHandlerMapping getRequestMappingHandlerMapping() { return new VersionRequestMappingHandlerMapping(); } }
5 controller
@RestController public class VersionController { @ApiVersion(1.0) @RequestMapping(value = "/get/version/{version}",method = RequestMethod.GET) public String getName() { return "this is version 1.0"; } @ApiVersion(2.0) @RequestMapping(value = "/get/version12/{version}",method = RequestMethod.GET) public String getNameV1() { return "this is version 2.0"; } }
打完收工,搞定!