当app迭代时需要,java后端的接口也可能会迭代。
相同的接口,传参和处理方式都会不懂,如果在代码中做向下兼容不可行了,就需要写多个接口进行版本区分。当版本接口不多时,可以通过接口传参然后判断来实现,但是版本接口过多时,在接口中做判断就会效率低下。
但是多个接口暴露出去是同一个访问路径。这样对于app端是察觉不到的。
这里采用拦截器和转发模式,进行请求分发。
首先定义统一接口的版本命名,这里采用v加数字的形式
@RestController
@RequestMapping("/test")
public class TestController {
@PostMapping("/test")
public String get(String name){
return "测试"+name;
}
@PostMapping("/test/v1")
public String pist(String name){
System.out.println(name);
return "测试v1------"+name;
}
@PostMapping("/test/v2")
public String aa(@RequestBody Map<String,Object> map){
System.out.println(map.get("name"));
return "测试v2-----"+map.get("name");
}
}
然后创建一个类,进行版本的接口注册
/**
* 配置多版本的接口
* 根据版本号进行接口匹配
* @author liudong
*/
public class VersionMap {
private HashMap<String,String> urls=new HashMap<>();
private VersionMap(){
//此处配置接口数据(接口,版本列表 逗号隔开 模式 v1-vn)
urls.put("/test/test","v1,v2");
}
private static class SingletonInstance {
private static final VersionMap INSTANCE = new VersionMap();
}
public static VersionMap getInstance() {
return SingletonInstance.INSTANCE;
}
public HashMap<String, String> getUrls() {
return urls;
}
public void setUrls(HashMap<String, String> urls) {
this.urls = urls;
}
}
然后写核心实现 VersionInterceptor拦截器
/**
* 版本拦截器
* @author liudong
*/
public class VersionInterceptor implements HandlerInterceptor{
/**
* 接口版本拦截器
* 对指定的接口进行版本连接
* 根据cookie中javaVersion转发到不同的版本接口中
* request中的参数以最终对应接口的参数为准
* 向下兼容模式
* 最大容错模式
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
Cookie[] aa = request.getCookies();
//后台版本
String javaVersion="";
//app版本
String appVersion="";
//设备
String equipment="";
if (aa==null){
LoggerTools.addInfoLogger("javaVersion");
}
if (("javaVersion").equals(aa[0].getName().trim())){
javaVersion=aa[0].getValue();
}else {
//无版本传入默认最低版本(向下兼容模式)
return true;
}
String url = request.getServletPath().split("\\.")[0];
VersionMap versionUrl = VersionMap.getInstance();
String versions = versionUrl.getUrls().get(url);
//默认最大版本
if (versions.contains(javaVersion)){
url = url+"/"+javaVersion+".do";
}else {
//传入当前版本不在注册中,返回最后一个版本
String[] versionUrls = versions.split(",|,");
url= url+"/"+versionUrls[versionUrls.length-1];
}
//携带参数进行转发
request.getRequestDispatcher(url).forward(request,response);
return false;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Object o, Exception e) throws Exception {
}
}
这里采用cookie进行数据传输,也可以采用其他方式,比如session之类的。
这里的接口后面需要加.do进行情况,所有截取方式请按具体情况进行区分。
我们将最终的接口版本与app端协定,app端在cookie中放置javaVersion。我们获取进行版本管理。
过滤器转发规则:
当没有指定参数传入时,访问初始接口 /test
当有参数传入时,访问指定接口,
当传入参数,不在注册列表时,访问最终版本接口。
所以版本接口的注册书写是按顺序,从左到右,从旧到新的。
接口的版本命名规则。
同一个接口不是按规则的。
接口的版本命名是根据java发布的版本进行命名的。
比如有两个接口 /a 和 /b
/a已经发布了三版 /a/v1 /a/v2
但是/b没有更新过
下一个版本时
/b要更新了
/b 的下一版命名应该是 /b/v3
如果是/b/v1 或者 /b/v2 时
上一版app传入的是v2
/a 接口访问的是/a/v2
/b 接口访问的应该是/b 而不是/b/v1
所以/b接口的下一版命名应该是在最大的版本号的基础上加一 /b/v3