隐藏

springmvc实现webapi接口版本兼容

发布:2021/7/31 17:35:13作者:管理员 来源:本站 浏览次数:1308

主要实现webapi版本兼容和降级,比如访问api/v3/hello但是服务端没有这个版本只有api/v2/hello可以默认降级到该版本


下面贴部分代码:

1.ApiVersion.java 定义版本注解


import java.lang.annotation.Documented;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;


import org.springframework.web.bind.annotation.Mapping;


/**

*

* @author wszhang

*

* @create 2017年4月9日 上午12:57:04


* @version 1.0


* @description 接口版本标识注解

*/

@Target({ElementType.METHOD, ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Mapping

public @interface ApiVersion {

   int value();

}


 


2.ApiVesrsionCondition 版本筛选,注意request.getPathInfo()和request.getPathInfo()区别否则会有空指针,在原作者基础上加了一个case使错误版本号默认返回最新版本


import java.util.regex.Matcher;

import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;

import org.springframework.web.servlet.mvc.condition.RequestCondition;


/**

*

* @author wszhang

*

* @create 2017年4月9日 上午12:57:39


* @version 1.0


* @description 版本号匹配筛选器

*/

public class ApiVesrsionCondition implements RequestCondition<ApiVesrsionCondition> {


   // 路径中版本的前缀, 这里用 /v[1-9]/的形式

   private final static Pattern VERSION_PREFIX_PATTERN = Pattern.compile("v(\\d+)/");


   private int apiVersion;


   public ApiVesrsionCondition(int apiVersion) {

       this.apiVersion = apiVersion;

   }


   @Override

   public ApiVesrsionCondition combine(ApiVesrsionCondition other) {

       // 采用最后定义优先原则,则方法上的定义覆盖类上面的定义

       return new ApiVesrsionCondition(other.getApiVersion());

   }


   @Override

   public int compareTo(ApiVesrsionCondition other, HttpServletRequest request) {

       // 优先匹配最新的版本号

       return other.getApiVersion() - this.apiVersion;

   }


   public int getApiVersion() {

       return apiVersion;

   }


   @Override

   public ApiVesrsionCondition getMatchingCondition(HttpServletRequest request) {

       //request.getPathInfo()

       Matcher m = VERSION_PREFIX_PATTERN.matcher(request.getServletPath());

       if (m.find()) {

           Integer version = Integer.valueOf(m.group(1));

           if (version >= this.apiVersion)

               // 如果请求的版本号大于等于配置版本号, 则满足

               return this;

       } else {

           // 如果版本号错误返回最新版本号

           return this;

       }

       return null;

   }


}


 


2.CustomRequestMappingHandlerMapping自定义RequestMappingHandlerMapping


import java.util.regex.Matcher;

import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;

import org.springframework.web.servlet.mvc.condition.RequestCondition;


/**

*

* @author wszhang

*

* @create 2017年4月9日 上午12:57:39


* @version 1.0


* @description 版本号匹配筛选器

*/

public class ApiVesrsionCondition implements RequestCondition<ApiVesrsionCondition> {


   // 路径中版本的前缀, 这里用 /v[1-9]/的形式

   private final static Pattern VERSION_PREFIX_PATTERN = Pattern.compile("v(\\d+)/");


   private int apiVersion;


   public ApiVesrsionCondition(int apiVersion) {

       this.apiVersion = apiVersion;

   }


   @Override

   public ApiVesrsionCondition combine(ApiVesrsionCondition other) {

       // 采用最后定义优先原则,则方法上的定义覆盖类上面的定义

       return new ApiVesrsionCondition(other.getApiVersion());

   }


   @Override

   public int compareTo(ApiVesrsionCondition other, HttpServletRequest request) {

       // 优先匹配最新的版本号

       return other.getApiVersion() - this.apiVersion;

   }


   public int getApiVersion() {

       return apiVersion;

   }


   @Override

   public ApiVesrsionCondition getMatchingCondition(HttpServletRequest request) {

       //request.getPathInfo()

       Matcher m = VERSION_PREFIX_PATTERN.matcher(request.getServletPath());

       if (m.find()) {

           Integer version = Integer.valueOf(m.group(1));

           if (version >= this.apiVersion)

               // 如果请求的版本号大于等于配置版本号, 则满足

               return this;

       } else {

           // 如果版本号错误返回最新版本号

           return this;

       }

       return null;

   }


}


 


4.配置文件及小结,原作者已经说明采用这种方式会导致mvc:annotation-driven不能使用,做过不少尝试避免此问题,但是均没有好的解决方案,主要是不设置ByteArrayHttpMessageConverter会导致接口返回数据乱码,遂重新注入了RequestMappingHandlerAdapter


<!--自定义requestMapping解析器 -->

<bean class="com.demo.util.version.CustomRequestMappingHandlerMapping">

       <property name="order" value="0" />

   </bean>


<!-- 解决乱码问题 -->

<bean       class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">

       <property name="messageConverters">

           <list>

               <bean               class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />

               <bean           class="org.springframework.http.converter.StringHttpMessageConverter">

                   <property name="supportedMediaTypes">

                       <list>

               <value>text/plain;charset=UTF-8</value>

                       </list>

                   </property>

               </bean>

           </list>

       </property>

   </bean>


 


原作者采用JavaConfig的方式注入CustomRequestMappingHandlerMapping,代码如下:


@Configuration

public class WebConfig extends WebMvcConfigurationSupport{


   @Override

   @Bean

   public RequestMappingHandlerMapping requestMappingHandlerMapping() {

       RequestMappingHandlerMapping handlerMapping = new CustomRequestMappingHandlerMapping();

       handlerMapping.setOrder(0);

       handlerMapping.setInterceptors(getInterceptors());

       return handlerMapping;

   }

}