通用登录模块(解决多端开发登录策略不同的问题)

news2024/11/15 13:28:44

文章目录

    • 1、目前登录接口
    • 2、问题分析
    • 3、解决方案
    • 4、使用场景

现在有一个场景,就是需要做登录,但是我们不确定现在移动端的同学做几端,可能会有 手机号登录、账号密码登录、qq登录、微信登录、PC端登录、网页端登录。这些登录的具体实现肯定是不一样的,而且我们并不知道到底要做几种策略,并且之后一定会有所拓展

举个栗子:

下图是gitee的登录的入口,其中有多种方式可以进行登录

  • 用户名密码登录

  • 短信验证码登录

  • 微信登录

  • QQ登录

在这里插入图片描述

我们来分析一下

1、目前登录接口

说明
请求方式POST
路径/api/user/login
参数LoginReq
返回值LoginResp

请求参数:LoginReq

@Data
public class LoginReq {

    private String name;
    private String password;

    private String phone;
    private String validateCode;//手机验证码

    private String wxCode;//用于微信登录
    /**
     * account : 用户名密码登录
     * sms : 手机验证码登录
     * we_chat : 微信登录
     */
    private String type;
}

响应参数:LoginResp

@Data
public class LoginResp{
    private Integer userId;
    private String userName;
    private String roleCode;
    private String token; //jwt令牌
    private boolean success;

}

控制层LoginController

@RestController
@RequestMapping("/api/user")
public class LoginController {

    @Autowired
    private UserService userService;


    @PostMapping("/login")
    public LoginResp login(@RequestBody LoginReq loginReq){
        return userService.login(loginReq);
    }
}

业务层UserService

@Service
public class UserService {

    public LoginResp login(LoginReq loginReq){

        if(loginReq.getType().equals("account")){
            System.out.println("用户名密码登录");

            //执行用户密码登录逻辑

            return new LoginResp();

        }else if(loginReq.getType().equals("sms")){
            System.out.println("手机号验证码登录");

            //执行手机号验证码登录逻辑

            return new LoginResp();
        }else if (loginReq.getType().equals("we_chat")){
            System.out.println("微信登录");

            //执行用户微信登录逻辑

            return new LoginResp();
        }
        LoginResp loginResp = new LoginResp();
        loginResp.setSuccess(false);
        System.out.println("登录失败");
        return loginResp;
    }
}

2、问题分析

  • 业务层代码大量使用到了if…else,在后期阅读代码的时候会非常不友好,大量使用if…else性能也不高
  • 如果业务发生变更,比如现在新增了QQ登录方式,这个时候需要修改业务层代码,违反了开闭原则

解决方案:

所以我们一般会用IOC容器 + 工厂模式 + 策略模式 来解决

3、解决方案

我们不在service中写业务逻辑,让service调用工厂,然后通过service传递不同的参数来获取不同的登录策略(登录方式)

在这里插入图片描述

我们看看具体怎么写

首先定义一个策略接口:UserGranter

/**
 * 抽象策略类
 */
public interface UserGranter{

   /**
    * 获取数据
    * @param loginReq 传入的参数
    * @return map值
    */
   LoginResp login(LoginReq loginReq);
}

接着定义具体的策略:AccountGranter、SmsGranter、WeChatGranter

/**
 * 	策略:账号登录
 **/
@Component
public class AccountGranter implements UserGranter{

	@Override
	public LoginResp login(LoginReq loginReq) {

		System.out.println("登录方式为账号登录" + loginReq);
		// TODO
		// 执行业务操作 
		
		return new LoginResp();
	}
}
/**
 * 策略:短信登录
 */
@Component
public class SmsGranter implements UserGranter{

	@Override
	public LoginResp login(LoginReq loginReq)  {

		System.out.println("登录方式为短信登录" + loginReq);
		// TODO
		// 执行业务操作

		return new LoginResp();
	}
}
/**
 * 策略:微信登录
 */
@Component
public class WeChatGranter implements UserGranter{

	@Override
	public LoginResp login(LoginReq loginReq)  {

		System.out.println("登录方式为微信登录" + loginReq);
		// TODO
		// 执行业务操作
		
		return new LoginResp();
	}
}

接下来定义一个工厂类:UserLoginFactory

/**
 * 操作策略的上下文环境类 工具类
 * 将策略整合起来 方便管理
 */
@Component
public class UserLoginFactory implements ApplicationContextAware {

    private static Map<String, UserGranter> granterPool = new ConcurrentHashMap<>();

    @Autowired
    private LoginTypeConfig loginTypeConfig;

    /**
     * 从配置文件中读取策略信息存储到map中
     * {
     * account:accountGranter,
     * sms:smsGranter,
     * we_chat:weChatGranter
     * }
     *
     * @param applicationContext
     * @throws BeansException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        loginTypeConfig.getTypes().forEach((k, y) -> {
            granterPool.put(k, (UserGranter) applicationContext.getBean(y));
        });
    }

    /**
     * 对外提供获取具体策略
     *
     * @param grantType 用户的登录方式,需要跟配置文件中匹配
     * @return 具体策略
     */
    public UserGranter getGranter(String grantType) {
        UserGranter tokenGranter = granterPool.get(grantType);
        return tokenGranter;
    }

}

在application.yml文件中新增自定义配置

login:
  types:
    account: accountGranter
    sms: smsGranter
    we_chat: weChatGranter

新增读取数据配置类

@Getter
@Setter
@Configuration
@ConfigurationProperties(prefix = "login")
public class LoginTypeConfig {

    private Map<String,String> types;

}

改造service代码

@Service
public class UserService {

    @Autowired
    private UserLoginFactory factory;

    public LoginResp login(LoginReq loginReq){

        UserGranter granter = factory.getGranter(loginReq.getType());
        if(granter == null){
            LoginResp loginResp = new LoginResp();
            loginResp.setSuccess(false);
            return loginResp;
        }
        LoginResp loginResp = granter.login(loginReq);
        return loginResp;
    }
}

可以看到我们使用了设计模式之后,业务层的代码就清爽多了,如果后期有新的需求改动,比如加入了QQ登录,我们只需要添加对应的策略就可以,无需再改动业务层代码

4、使用场景

其实像这样的需求,在日常开发中非常常见,场景有很多,以下的情景都可以使用工厂模式+策略模式解决比如:

  • 订单的支付策略
    • 支付宝支付
    • 微信支付
    • 银行卡支付
    • 现金支付
  • 解析不同类型excel
    • xls格式
    • xlsx格式
  • 打折促销
    • 满300元9折
    • 满500元8折
    • 满1000元7折
  • 物流运费阶梯计算
    • 5kg以下
    • 5kg-10kg
    • 10kg-20kg
    • 20kg以上

一句话总结:只要代码中有冗长的 if-else 或 switch 分支判断都可以采用策略模式优化

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/732169.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Go语言基础知识(一):基础介绍

一、简介 Go 语言又称 Golang&#xff0c;由 Google 公司于 2009 年发布&#xff0c;近几年伴随着云计算、微服务、分布式的发展而迅速崛起&#xff0c;跻身主流编程语言之列&#xff0c;和 Java 类似&#xff0c;它是一门静态的、强类型的、编译型编程语言&#xff0c;为并发…

python_day2

猜数字-while循环 import randomnum random.randint(1, 10) while True:x int(input("输入&#xff1a;"))if x > num:print("大了")elif x < num:print("小了")else:print("猜对了")break打印九九乘法表-while循环 i 1 wh…

mysql中desc的两种用法---1、查询表结构和降序

Mysql中DESC的两种用法 1、查询表结构 语法&#xff1a; desc table_name&#xff1b; PS&#xff1a;此处desc是describe的缩写&#xff0c;用法&#xff1a; desc 表名/查询语句 2、降序 语法&#xff1a; select * from 表 order by 字段 desc select ename,sal from e…

华为Harmony应用开发初探

HarmonyOS是一款面向万物互联时代的、全新的分布式操作系统。在传统的单设备系统能力基础上,HarmonyOS提出了基于同一套系统能力、适配多种终端形态的分布式理念,能够支持手机、平板、智能穿戴、智慧屏、车机等多种终端设备,提供全场景(移动办公、运动健康、社交通信、媒体…

VectorCAST软件安装

一、VectorCAST的安装 在 Windows 平台&#xff0c;安装文件是一个压缩文件&#xff08;zip 文件&#xff09;&#xff0c;请将其解压缩&#xff0c;解压缩后&#xff0c;找到 setup.exe&#xff0c; 双击运行&#xff0c;打开软件安装界面&#xff0c;之后在此界面点击 Next&…

利用python绘制二三维曲面和矢量流线图

为了实现不同数据的可视化&#xff0c;最近研究了python环境下的可视化方案&#xff0c;为后续的流体运动仿真模拟做好储备&#xff0c;由于python处理数据的便利性&#xff0c;导致目前很多后端处理或者可视化成图操作都在python中实现&#xff0c;比如前端是vue&#xff0c;加…

全国时尚CIO峰会丨实在智能:“数字员工”成企业数字化关键纽带

时尚&#xff0c;是不断演进的艺术。“中国时尚行业转型高峰论坛暨时尚行业CIO夏季峰会”作为时尚界的重要盛事&#xff0c;已经成为业界领袖、品牌大咖与创新者们的汇聚之地。近日&#xff0c;以“数智极智未来&#xff1a;新纪元 新生命”为主题的第八届时尚行业盛会在广东佛…

Linux驱动开发:Linux内核启动流程详解

前言&#xff1a;Linux 内核同样作为 Linux 驱动开发的 “三巨头” 之一&#xff0c;Linux 内核的启动流程要比 uboot 复杂的多&#xff0c;涉及到的内容也更多。但秉持着 “知其然知其所以然” 的学习态度&#xff0c;作者将给读者朋友大致的过一遍 Linux 内核的启动流程。(考…

Jmeter的常用设置(二)

文章目录 前言一、察看结果树响应结果是乱码_解决方法 方法一&#xff1a;在察看结果树之前添加 后置处理器 中的 “BeanShell PostProcessor” 来动态修改结果处理编码方法二&#xff1a;在配置文件中修改二、使用步骤 1.引入库2.读入数据总结 前言 接口测试中遇到的各种问题…

VN积分法卷径计算

卷径计算的其他方法请参看专栏的相关文章,链接如下: 卷径计算(V/N法)_RXXW_Dor的博客-CSDN博客卷径计算(厚度累计法/膜厚叠加法)_RXXW_Dor的博客-CSDN博客卷径计算的截面积法请参看下面的文章链接:卷径计算详解(通过卷绕的膜长和膜厚进行计算)_RXXW_Dor的博客-CSDN博客有关…

高清视频如何转成gif动画?手把手教你在线转换高清gif

说到gif动图相信大家并不陌生&#xff0c;随着gif表情包越来越火爆&#xff0c;大家也不满足于收藏转载别人的表情包了。都开始自己制作gif表情包了&#xff0c;那么&#xff0c;如何将视频转换成高清gif呢&#xff1f;很简单&#xff0c;使用GIF中文网的视频转gif&#xff08;…

Protobuf类型定义

"都甩掉吧&#xff0c;我们的世界一定会更美好&#xff01;其他不重要&#xff01;" 前面呢&#xff0c;我们讲了如何在Linux环境下安装Protobuf所需的库&#xff0c;那么本篇的着眼点在于Protobuf的编写以及语法规则。 什么是proto3? ProtocolBuffers语⾔版本3&am…

CClink IE转Modbus TCP网关连接三菱FX5U PLC

远创智控YC-CCLKIE-TCP 是自主研发的一款 CCLINK IE FIELD BASIC 从站功能的通讯网关。该产品主要功能是将各种 MODBUS-TCP 设备接入到 CCLINK IE FIELD BASIC 网络中。 远创智控YC-CCLKIE-TCP网关连接到 CCLINK IE FIELD BASIC 总线中做为从站使用&#xff0c;连接到 MODBUS-T…

[MMDetection]COCO数据集可视化验证

在使用MMDetection训练之前&#xff0c;需要对图像进行可视化验证&#xff0c;验证数据和标签是否对齐。 # 数据集可视化 import os import matplotlib.pyplot as plt from PIL import Imageoriginal_images [] images [] texts [] plt.figure(figsize(16,12))image_paths …

MySQL阶段_DAY17-DAY19(附笔记)

【注意】&#xff1a;管家婆知识的目录结构&#xff0c;一个针对于CRUD的小案例,也就是后端的CRUD 1、控制层 接收view传递的数据, 向service传递数据(调用service层) 向view返回结果 package controller;import java.util.List;import domain.ZhangWu; import servi…

路径规划算法:基于冠状病毒群体免疫优化的路径规划算法- 附代码

路径规划算法&#xff1a;基于冠状病毒群体免疫优化的路径规划算法- 附代码 文章目录 路径规划算法&#xff1a;基于冠状病毒群体免疫优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要&#xff1a;本文主要…

使用信号量Semaphore 实现多线程访问

一 semaphore多线程访问 1.1 代码 public class Xinhaoliang {public static void main(String[] args) {Semaphore semaphorenew Semaphore(3);for(int k1;k<8;k){final int mk;new Thread(new Runnable() {Overridepublic void run() {try {semaphore.acquire();Syste…

使用ResponseBodyAdvice返回值为String出现cannot be cast to java.lang.String异常

使用ResponseBodyAdvice返回值为String出现cannot be cast to java.lang.String异常 背景 由于项目中为了全局返回统一的JSON格式&#xff0c;使用ResponseBodyAdvice进行拦截&#xff0c;拦截的时候会将返回的信息统一一个对象返回到前端。但是有的同事将一个String的响应对象…

【Linux】高级IO(一)

文章目录 高级IO阻塞IO模型非阻塞IO模型多路转接IOselect简介socket 就绪条件select服务器select的优缺点多路转接的使用场景 高级IO 非阻塞IO&#xff0c;记录锁&#xff0c;系统V流机制&#xff0c;I/O多路转接&#xff08;I/O&#xff09;多路复用&#xff0c;readv 和 wri…

English Learning - L3 综合练习 10 口语语法串讲与思维回顾 2023.07.5 周三

English Learning - L3 综合练习 10 口语语法串讲与思维回顾 2023.07.5 周三 [知识点 1] 名词性从句问题&#xff1a;到底什么是名词笥从句&#xff1f;例 1&#xff1a;我的东西你都可以随便用例 2&#xff1a;不管是谁&#xff0c;放你鸽子就是混蛋例 3&#xff1a;说那种话的…