设计一个支持多版本的APP的后端服务

2023-05-16

  1. 以注册为例子的说明

我们以我们的用户中心的注册为例子我们实现的非常简单就是做一个校验,校验成功之后,把用户注册的数据入库即可。

随着我们产品的迭代注册肯定没有这么简单。比如说我需要填写一个电话号码并且拿到验证码并验证正确了才有资格注册。

但是有一个问题,我们的app升级了版本之后。用户在收到版本升级的消息时,并不一定愿意升级版本。

我们在遇到上述的情况,我们希望更新了新版本的用户使用的是需要经过验证并拿到了验证的标识。在注册的时候需要有验证标识才能做下一步的操作。所以我们可能要对接口进行改造。

第一:我们在接口中通过不同的版本号走不同的逻辑。这个其实也能解决我们遇到的问题。

但是随着版本的升级。我们会遇到更多的需求如果在代码中添加太多的判断肯定会降低接口的响应。也增加了后期维护代码的难度一句话low

第二:我们提供多个不同版本的接口。在请求发起的时候带上app的版本号。我们根据不同的版本号转发到不同的接口。这样我们便于后期代码的维护和重构。同一个接口不至于逻辑过于复杂

  1. 我们在用户中心实现以上的想法

由于我们在各个微服务的中都会需要多升级的版本进行控制。所以把这些通用的工具写到common的工具类中。

在common中添加api版本的包如下图:

 

定义一个自定义注解ApiVersion实现如下(我们把顺便把使用注解的方式以注释的方式写在实现类中):

/**

 * 标识接口版本的注解类

 * @author yusong

 */

/*定义该注解可以作用在的位置  

 * ElementType.METHOD可以在方法上加入注解

 * ElementType.TYPE 在接口、类、枚举、注解可以使用该注解

 */

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

/*定义注解的生命周期

 * RetentionPolicy.RUNTIME:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在

 *一般如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解

 */

@Retention(RetentionPolicy.RUNTIME)

@Documented //该注解标明在生成文档的时候是否显示该注解

@Mapping //定义用于mapping映射

public @interface ApiVersion {

/**

 * 标识版本号

 * @return

 */

String value();

}

  1. api版本管理的条件控制的实现

/**

 * api版本管理的条件控制

 * @author yusong

 */

public class ApiVersionCondition implements RequestCondition<ApiVersionCondition>{

//API版本号

private String apiVersion;

//从头信息获取到的版本的字段

private static final String HEADER_VERSION = "version";

/**

 * 构造函数传入版本号

 */

public ApiVersionCondition(String apiVersion) {

this.apiVersion = apiVersion;

}

/**

 * 符合不同筛选条件的进行合并

 */

@Override

public ApiVersionCondition combine(ApiVersionCondition other) {

return new ApiVersionCondition(other.getApiVersion());

}

/**

 * 版本对比用于排序

 */

@Override

public int compareTo(ApiVersionCondition other, HttpServletRequest request) {

return compareTo(other.getApiVersion(),this.getApiVersion())?1:-1;

}

/**

 * 根据request的header版本号进行查找匹配的筛选条件

 */

@Override

public ApiVersionCondition getMatchingCondition(HttpServletRequest request) {

//从头信息中获取版本信息

String version = request.getHeader(HEADER_VERSION);

if(version!=null) {

//向下找到最近最新的一个版本  达到向下兼容的目的

if(compareTo(version, this.apiVersion)) {

return this;

}

}

//客户端未添加app版本的时候 给一个基础的版本

return new ApiVersionCondition("1.0.0");

}

private boolean compareTo(String version1,String version2) {

String[] split1 = version1.split("\\.");

String[] split2 = version2.split("\\.");

for(int i=0;i<split1.length;i++) {

if(Integer.parseInt(split1[i])<Integer.parseInt(split2[i])) {

return false;

}

}

return true;

}

public String getApiVersion() {

return apiVersion;

}

}

  1. 处理mapping映射管理

/**

 * mapping映射管理

 * @author yusong

 */

public class CustomRequestMappingHandlerMapping extends RequestMappingHandlerMapping{

/**

 * 定义api条件控制的类 注解在类上

 */

@Override

protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) {

ApiVersion apiVersion = AnnotationUtils.findAnnotation(handlerType, ApiVersion.class);

return createCondition(apiVersion);

}

/**

 * 定义api条件控制的类 注解在方法上

 */

@Override

protected RequestCondition<?> getCustomMethodCondition(Method method){

ApiVersion apiVersion = AnnotationUtils.findAnnotation(method, ApiVersion.class);

return createCondition(apiVersion);

}

private RequestCondition<ApiVersionCondition> createCondition(ApiVersion apiVersion){

return apiVersion == null?null:new ApiVersionCondition(apiVersion.value());

}

}

  1. WebConfig的定义

@Configuration

public class WebConfig extends WebMvcConfigurationSupport{

//定义该值为了其他工程使用该注解生效的时候 扫描该包

public static final String WEB_CONFIG_API_VERSION = "cn.com.leimon.common.tool.util.apiversion";

/**

 * 注册请求的版本请求方法

 */

@Override

public RequestMappingHandlerMapping requestMappingHandlerMapping(

@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,

@Qualifier("mvcConversionService") FormattingConversionService conversionService,

@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {

RequestMappingHandlerMapping handlerMapping = new CustomRequestMappingHandlerMapping();

handlerMapping.setOrder(0);

handlerMapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));

return handlerMapping;

}

}

  1. 让注解生效

我们在用户中心的启动类的注解@ComponentScan中加入common中公用的版本管理。如下:

@ComponentScan(basePackages={"cn.com.leimon.user",WebConfig.WEB_CONFIG_API_VERSION})

  1. 测试

Open接口定义添加同一个路径的的不同实现接口

@ApiOperation(value="用户注册(使用用户名密码的方式)1.0.0版本")

@PostMapping(value = "/register")

public ReturnResult register(

@ApiParam(value = "用户名",required = true)

@RequestParam(required = true)String userName,

@ApiParam(value = "密码",required = true)

@RequestParam(required = true)String password

);

@ApiOperation(value="用户注册(使用用户名密码的方式)")

@PostMapping(value = "/register")

public ReturnResult registertV1(

@ApiParam(value = "用户名",required = true)

@RequestParam(required = true)String userName,

@ApiParam(value = "密码",required = true)

@RequestParam(required = true)String password

);

@ApiOperation(value="用户注册(使用用户名密码的方式)")

@PostMapping(value = "/register")

public ReturnResult registertV2(

@ApiParam(value = "用户名",required = true)

@RequestParam(required = true)String userName,

@ApiParam(value = "密码",required = true)

@RequestParam(required = true)String password

);

我们在实现中加入版本的注解如下:

@Override

@ApiVersion(value = "1.0.0")

public ReturnResult register(String userName,String password) {

System.out.println("==========33333333333333=========================");

/**

 * 1.判断用户名是否在系统中已经存在

 * 2.判断密码是否符合既定的规则

 * 3.入库

 * 4.返回注册状态

 * 5.

 * 6.

 */

//判断用户是否存在

int num = userInfoService.checkRegisterUser(userName);

if(num==1) {//用户已经注册

return new ReturnResult(ResultMessage.USER_IS_REGISTER);

}

if(!StringCheckUtil.isLetterDigit(password)) {

return new ReturnResult(ResultMessage.PASSWORD_ISNOT_RULE);

}

//TODO 入库操作 并返回操作状态

//使用雪花算法计算分布式id

return null;

}

@Override

@ApiVersion(value = "1.0.1")

public ReturnResult registertV1(String userName, String password) {

System.out.println("============111111==========================");

return null;

}

@Override

@ApiVersion(value = "1.0.2")

public ReturnResult registertV2(String userName, String password) {

System.out.println("================22222222222=========================");

return null;

}

我们使用postman测试如下图所示:

 

发送请求时不同的version请求会落到不同的实现。说明功能已经完成了

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

设计一个支持多版本的APP的后端服务 的相关文章

  • Linux上SMB挂载提示mount: block device //xxx.xxx.xx.xx/xx is write-protected, mounting read-only时解决办法

    当在Linux上挂载SMB服务器时候有时会提示如下错误 xff1a root 64 test mount o username 61 lisi 192 168 23 32 smb test mount block device 192 16
  • Linux下的LAMP环境搭建时访问PHP页面时变成下载页面的原因

    在搭建LAMP环境的时候遇到了配置完PHP环境后测试访问PHP页面的时候却变成下载的情况 xff0c 主要的影响有一下两个方面 1 PHP的配置问题 2 主要原因是httpd conf配置文件内容出错大致有下面几个地方 xff1a Load
  • 服务器肉鸡/入侵被恶意利用的排查和优化方案

    排查方法 xff1a 1 账户方面 xff1a Windows xff1a xff08 1 xff09 检查服务器内是否有异常的账户 xff0c 查看下服务器内是否有非系统和用户本身创建的账户 xff0c 一般黑客创建的账户账户名 后会有
  • Opensuse如何安装桌面环境

    安装必须的范式 xff1a zypper install t pattern kde kde plasma 编辑 etc sysconfig displaymanager 文件并设定 DISPLAYMANAGER 61 kdm xff0c
  • 怎么用谷歌学术检索下载外文文献

    谷歌学术是一个可以免费搜索外文学术文章的搜索引擎 xff0c 包括了世界上绝大部分出版的学术期刊 xff0c 可广泛搜索学术文献 谷歌学术可了解有关某一领域的学术文献 xff1b 了解某一作者的著述 xff0c 并提供书目信息 xff08
  • 英文文献去哪里查找,8个超强英文文献查找网站建议收藏

    英文文献去哪里查找 xff1f 找对方向用对工具可大幅提升学习和研究效率 xff01 下面详细介绍8个查找英文文献非常好用的网站 一 文献党下载器 xff08 wxdown org xff09 xff1a 该网站几乎整合汇聚了所有文献数据库
  • 基于STM32系列的模拟串口(非阻塞式)

    STM32单片机一般少则3个串口 多则5个 而我这次的项目还偏偏5个硬件串口还是不够用 至于不够用的原因 哎 是项目做到后面有定制 随便哪个串口都省不得 没得办法 只能另想法子咯 板子上有几个预留IO口 可以用来模拟串口 模拟串口一般都选9
  • 复制一个目录下的所有文件到另外一个目录(Java实现)

    首先说说我的思路 xff0c 要复制一个目录下的所有文件到另外的一个目录下 xff0c 我们不知道目录下的结构是怎么样的 xff0c 也不知道目录有多少层 xff0c 文件有多少个 xff0c 这样我们会想用循环 xff0c for 但是我
  • RT-Thread嵌入式操作系统

    一 系统架构 RT Thread xff0c 全称是 Real Time Thread xff0c 顾名思义 xff0c 它是一个嵌入式实时多线程操作系统 RT Thread 主要采用 C 语言编写 xff0c 浅显易懂 xff0c 方便移
  • 1.javascript类型中你不知道的细节

    1 数据类型 基本数据类型 xff1a Undefined xff1b Null xff1b Boolean xff1b String xff1b Number xff1b Symbol xff1b Object 1 1 undefined
  • RT-Thread内核基础

    RT Thread内核基础 1 RT Thread 内核介绍 下图为 RT Thread 内核架构图 xff0c 内核处于硬件层之上 xff0c 内核部分包括内核库 实时内核实现 实时内核的实现包括 xff1a 对象管理 线程管理及调度器
  • 安装和配置VNC服务器的法则

    这是一个关于怎样在你的 CentOS 7 上安装配置VNC服务的教程 当然这个教程也适合 RHEL 7 在这个教程里 xff0c 我们将学习什么是 VNC 以及怎样在 CentOS 7 上安装配置VNC 服务器 我们都知道 xff0c 作为
  • 阿里云轻量应用服务器使用教程

    阿里云轻量应用服务器怎么远程连接 xff1f 轻量服务器可以更换操作系统吗 xff1f 使用轻量应用服务器如何搭建网站 xff1f 轻量应用服务器端口如何开通 xff1f 阿里云百科来详细说下轻量服务器远程连接 搭建网站 开放端口等详细使用
  • 超详细!阿里内部都在用的K8S实战手册,新手看这一篇就够了

    一直关注云计算领域的人 xff0c 必定知道Kubernetes的崛起 如今 xff0c 世界范围内的公有云巨头 xff08 谷歌 亚马逊 微软 华为云 阿里云等等 xff09 都在其传统的公共云服务之上提供托管的Kubernetes服务
  • YOLO目标检测多种改进模型

    写于2020年11月 一 SlimYOLOv3 论文链接 xff1a arxiv org abs 1907 11093 代码链接 xff1a https github com PengyiZhang SlimYOLOv3 二 YOLOV3
  • 解决cv2.error报错解决方案

    问题摘要 xff1a 一般出现如下 xff1a 解决cv2 error OpenCV 4 2 0 C projects opencv python opencv 报错 cv2 error OpenCV 4 2 0 C projects op
  • YOLOv5网络结构分析

  • EraseNet:端到端的真实场景文本擦除方法

    六 相关资源 EraseNet论文链接 xff1a https ieeexplore ieee org document 9180003 EraseNet代码 xff1a https github com lcy0604 EraseNet
  • 《程序人生》

    对乔布斯和马斯克访谈的反思 xff1a 1 这个世界不在乎你的自尊 xff0c 只在乎你自我感觉良好的同时有所成就 说明大多数人的观点是 乌合之众 xff0c 必须有从想到去做到的能力 xff0c 面子是无能者维护尊严的盾牌 2 年轻时候一
  • DiffusionDet:Diffusion Model for Object Detection

    Diffusion Model for Object Detection 一种用于目标检测的扩散模型 Motivation 1 如何使用一种更简单的方法代替可查询的object queries 2 Bounding box的生成方式过去是三

随机推荐

  • springboot整合shiro的小demo(一)

    刚学shiro整合springboot xff0c 在此做一个笔记 xff0c 以便后期忘了查阅 本文分以下几个方面进行整合以及验证 xff1a 1 springboot项目搭建整合thymeleaf实现页面访问 2 springboot整
  • ChatGPT:通用人工智能设计范式方法

    通用人工智能设计范式未来发展方向 https openai com https riscv org 一 ChatGPT xff08 AIGC xff09 开启通用人工智能AGI新纪元时代 二 通用人工智能设计范式现状和方法 目前随着Chat
  • 格拉布斯法—异常值判断(异常值)

    数值数据类型 xff1a 方法一 xff1a Z Score 方法二 xff1a DBSCAN 方法三 xff1a Lsolation Forest 方法四 xff1a Mahalanobis距离 xff08 主要解决多元离散群点问题 xf
  • 你会为AI转型吗? 土豆的思考浅谈

    人工智能意味着什么 xff1f 终身学习与人工智能 复杂 读后感 0 经历 按照自己生活规律每天早上第一件事收发邮件这是昨天打开邮箱后看到的论文和相关论文推荐 xff0c 从1956年诞生以来到2013开始接触这个东西 xff0c 国内我曾
  • 神经网络的过去、现状、未来!

    从BP CNN RNN DCN GAN GNN图网络 GCN CAP三维卷积胶囊模型及融合 人工神经网络是计算智能和机器学习研究的最活跃的分支之一 xff0c 它是从人脑的生理结构出发探讨人类智能活动的机理 从 1943年 McCulloc
  • 场景理解类目标检测SENet

    论文 xff1a Squeeze and Excitation Networks 论文链接 xff1a https arxiv org abs 1709 01507 代码地址 xff1a https github com hujie fra
  • 目标检测发展方向(1)

    从目标检测发展到目标追踪 目标检测 xff08 监督学习 xff09 FasterRCNN CascadeRCNN YOLOX Complex YOLO SSD RetinaNet xff0c FOCS ATSS CornerNet Cen
  • 车道线检测与分割

    https github com amusi awesome lane detection VPGNet论文 xff1a https arxiv org abs 1710 06288 caffe 版code xff1a https gith
  • CAS单点登录原理解析

    1 基于Cookie的单点登录的回顾 基于Cookie的单点登录核心原理 xff1a 将用户名密码加密之后存于Cookie中 xff0c 之后访问网站时在过滤器 xff08 filter xff09 中校验用户权限 xff0c 如果没有权限
  • js中.?、??、??=的用法和含义

    前言 在项目中我们往往要做很多很多的空值判断进行容错处理 往往伴随着三目运算 与或 if else来使用 不仅要写很多冗余的代码 后期维护起来也是满屏的if else可以说是非常的痛苦了 今天分享几个处理空值简单的方法 希望可以解决大家的一
  • 服务器安装docker,拉取一些常用镜像

    1 购买服务器 xff08 系统centos7 6 xff09 2 在控制台中找到购买的服务器 xff0c 设置密码 xff0c 账号默认 root 3 开放需要的端口 xff0c 如nacos xff0c redis等等 4 使用Fina
  • udacity上Google的深度学习笔记

    Udacity上deeplearning这门课是google开的 xff0c 介绍了常见的几种深度神经网络模型 xff0c 同时还附带了几个练习 xff0c 并且练习用的工具都是tensorflow xff0c 所以既可以学习一下神经网络的
  • maven插件解决项目中静态资源版本问题

    产品从第一次上线后 xff0c 迭代发了两个版本了 由于含web客户端 xff0c 由于浏览器的静态资源缓存策略 xff0c 出现了静态资源的版本管理问题 开发人员每次修改完js或css文件后都需要自己在html文件中修改版本号 xff0c
  • samba服务

    samba服务的完整配置 xff1a 配置centos6与centos7文件之间的共享 1 xff09 以centos6为服务端 xff0c 安装samba服务 root 64 centos6 yum install samba y 2 x
  • XML 根级别上的数据无效。 行 1,位置 1

    上午 xff1a 将XML数据保持到数据中 xff0c 从数据库提取XML 顺利通过 下午 xff1a 一键还原电脑 xff0c 重新打开VS2010运行程序 xff0c 从数据库提取XML报错 根级别上的数据无效 行 1 xff0c 位置
  • 接触客户、接触业务、来谈我的感触

    很久没有做工作总结 xff0c 今天记录下我今年接触客户的一些感触 以前是一个刚入门的开发新人 xff0c 刚进公司感觉公司的开发能力不行 xff0c 没有一套成熟的框架 xff0c 没有美工 xff0c 已经开发出的软件界面很丑 自己开发
  • 走过2011

    走过2011 时间飞逝 xff0c 2011不寻常的一年还剩下短短5天 三百天的生活与工作是一份平淡一份快乐 工作需要总结 生活也要总结 日子才会越来越好 xff01 2011是进入公司的第二年 公司开发人员有来有离 xff0c 我没有离开
  • Error: This command has to be run with superuser privileges (under the root user on most systems).

    意思是错误 xff1a 此命令必须以超级用户权限 xff08 在大多数系统上以root用户权限 xff09 运行 所以当前的用户是普通用户 xff0c 需要切换为超级用户 xff08 root用户 xff09 先输入在命令行中输入 su r
  • P200 7

    lt img src 61 34 https img blog csdn net 20150518130711865 watermark 2 text aHR0cDovL2Jsb2cuY3Nkbi5uZXQvWXVTb25nNDg2OQ 6
  • 设计一个支持多版本的APP的后端服务

    以注册为例子的说明 我们以我们的用户中心的注册为例子我们实现的非常简单就是做一个校验 xff0c 校验成功之后 xff0c 把用户注册的数据入库即可 随着我们产品的迭代注册肯定没有这么简单 比如说我需要填写一个电话号码并且拿到验证码并验证正