news 2026/4/18 10:01:03

优雅解耦!SpringBoot 工厂+策略模式统一多端登录

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
优雅解耦!SpringBoot 工厂+策略模式统一多端登录

各位开发者好,我是在项目里被登录功能折磨过无数次的老码农。还记得三年前接手一个多端登录项目,用户名密码、微信、手机号验证码三种登录方式挤在一个if-else里,新增支付宝登录时整整改了 17 处代码,最后还漏了一处校验 —— 从此发誓再也不用 "面条代码" 处理登录逻辑。

今天就把结合工厂模式和策略模式的优雅实现分享出来,带你从需求分析到 Spring Boot 实战,彻底告别登录模块的维护噩梦。

一、需求分析:当产品说 "我们要支持 10 种登录方式"
1. 典型登录场景:代码里的 "联合国"

假设我们要实现一个支持三种登录方式的系统:

  • 用户名密码登录:需要校验密码加密、账号是否锁定

  • 微信扫码登录:需要调用微信开放平台 API,校验授权码

  • 手机号验证码登录:需要生成验证码、校验有效期和正确性

传统写法是写一个LoginService,用if-else判断登录类型:

public String login(String loginType, Map<String, Object> params) { if ("password".equals(loginType)) { // 用户名密码登录逻辑 } else if ("wechat".equals(loginType)) { // 微信登录逻辑 } else if ("sms".equals(loginType)) { // 手机号登录逻辑 } else { throw new IllegalArgumentException("不支持的登录类型"); } }

这种写法的问题在于:

  • 扩展性差:新增登录方式要改if-else,违反开闭原则

  • 职责混乱:所有逻辑挤在一个类里,可读性差

  • 复用困难:不同登录方式的公共逻辑(如用户校验)无法抽取

2. 设计模式选择:策略模式解耦算法,工厂模式创建实例

策略模式:将每种登录方式封装成独立策略类,实现统一接口,调用者无需关心具体实现 工厂模式:通过工厂类根据登录类型创建对应的策略实例,避免调用者直接 new 对象

二、Spring Boot 项目搭建:先搭好 "舞台"
1. 创建 Spring Boot 项目

添加 Web 依赖,项目结构如下:

src/main/java/com/example/login ├── config │ └── StrategyConfig.java // 策略Bean配置 ├── controller │ └── LoginController.java // 登录控制器 ├── factory │ └── LoginStrategyFactory.java // 登录策略工厂 ├── model │ └── LoginRequest.java // 登录请求参数 ├── service │ ├── impl │ │ ├── PasswordLoginStrategy.java // 用户名密码策略 │ │ ├── WechatLoginStrategy.java // 微信策略 │ │ └── SmsLoginStrategy.java // 手机号策略 │ └── LoginStrategy.java // 登录策略接口 └── Application.java
2. 定义统一登录策略接口
public interface LoginStrategy { // 登录类型标识,如"password"、"wechat" String getLoginType(); // 登录方法,参数用Map传递不同登录方式的参数 String execute(Map<String, Object> params); }
三、策略模式实现:每种登录方式都是 "独立演员"
1. 用户名密码登录策略
@Service publicclass PasswordLoginStrategy implements LoginStrategy { @Override public String getLoginType() { return"password"; } @Override public String execute(Map<String, Object> params) { String username = (String) params.get("username"); String password = (String) params.get("password"); // 模拟密码校验(实际应从数据库查询+密码解密) if (!"123456".equals(password)) { thrownew IllegalArgumentException("密码错误"); } // 模拟用户校验 checkUserLocked(username); return"登录成功(用户名密码)"; } private void checkUserLocked(String username) { // 调用用户服务检查账号是否锁定 System.out.println("检查用户" + username + "是否锁定"); } }
2. 微信扫码登录策略
@Service publicclass WechatLoginStrategy implements LoginStrategy { @Override public String getLoginType() { return"wechat"; } @Override public String execute(Map<String, Object> params) { String authCode = (String) params.get("authCode"); // 模拟调用微信接口获取用户信息 String openId = callWechatApi(authCode); // 模拟数据库查询用户绑定关系 String userId = getUserIdByOpenId(openId); if (userId == null) { thrownew IllegalArgumentException("微信账号未绑定系统用户"); } return"登录成功(微信扫码)"; } private String callWechatApi(String authCode) { // 实际应调用微信开放平台API System.out.println("调用微信接口,authCode=" + authCode); return"wechat_open_id_123"; } }
3. 手机号验证码登录策略
@Service publicclass SmsLoginStrategy implements LoginStrategy { @Override public String getLoginType() { return"sms"; } @Override public String execute(Map<String, Object> params) { String phone = (String) params.get("phone"); String code = (String) params.get("code"); // 模拟验证码校验(实际应从Redis获取) if (!"666888".equals(code)) { thrownew IllegalArgumentException("验证码错误"); } // 模拟用户校验 checkPhoneRegistered(phone); return"登录成功(手机号验证码)"; } private void checkPhoneRegistered(String phone) { // 检查手机号是否注册 System.out.println("检查手机号" + phone + "是否注册"); } }
四、工厂模式实现:让 "导演" 决定用哪个 "演员"
1. 登录策略工厂类
@Component publicclass LoginStrategyFactory { privatefinal Map<String, LoginStrategy> strategyMap; // 通过Spring依赖注入获取所有LoginStrategy实现类 public LoginStrategyFactory(Map<String, LoginStrategy> strategyMap) { this.strategyMap = strategyMap; } public LoginStrategy getStrategy(String loginType) { LoginStrategy strategy = strategyMap.get(loginType); if (strategy == null) { thrownew IllegalArgumentException("不支持的登录类型:" + loginType); } return strategy; } }

这里利用 Spring 的自动装配,将所有@Service标记的LoginStrategy实现类注入到strategyMap中,键为 Bean 名称(默认是类名首字母小写,如passwordLoginStrategy),但我们在策略类中通过getLoginType()返回自定义的类型标识,所以需要在配置类中调整 Bean 名称:

2. 策略 Bean 配置(关键!)
@Configuration publicclass StrategyConfig { @Bean("passwordStrategy") // 自定义Bean名称 public LoginStrategy passwordLoginStrategy() { returnnew PasswordLoginStrategy(); } @Bean("wechatStrategy") public LoginStrategy wechatLoginStrategy() { returnnew WechatLoginStrategy(); } @Bean("smsStrategy") public LoginStrategy smsLoginStrategy() { returnnew SmsLoginStrategy(); } }

然后在策略类中重写getLoginType()返回和前端约定的类型标识(如 "password"),并在工厂类中建立类型标识到 Bean 的映射:

// 修改工厂类的构造方法,建立正确映射 public LoginStrategyFactory(Map<String, LoginStrategy> strategyMap) { this.strategyMap = new HashMap<>(); strategyMap.forEach((beanName, strategy) -> this.strategyMap.put(strategy.getLoginType(), strategy) ); }
五、控制器集成:对外提供统一接口
1. 登录请求参数类
public class LoginRequest { private String loginType; // 登录类型,如"password"、"wechat" private Map<String, Object> params; // 具体参数,不同登录方式不同 // 省略getter/setter }
2. 登录控制器
@RestController @RequestMapping("/login") publicclass LoginController { privatefinal LoginStrategyFactory factory; @Autowired public LoginController(LoginStrategyFactory factory) { this.factory = factory; } @PostMapping public String login(@RequestBody LoginRequest request) { String loginType = request.getLoginType(); Map<String, Object> params = request.getParams(); LoginStrategy strategy = factory.getStrategy(loginType); return strategy.execute(params); } }
六、测试验证:三种登录方式轻松切换
1. 用户名密码登录请求
{ "loginType": "password", "params": { "username": "user123", "password": "123456" } }
2. 微信扫码登录请求
{ "loginType": "wechat", "params": { "authCode": "wechat_auth_code_456" } }
3. 新增登录方式:比如支付宝登录

只需新增AlipayLoginStrategy类并实现接口,无需修改现有代码:

@Service("alipayStrategy") public class AlipayLoginStrategy implements LoginStrategy { @Override public String getLoginType() { return "alipay"; } @Override public String execute(Map<String, Object> params) { // 支付宝登录逻辑 return "登录成功(支付宝)"; } }
七、核心优势:让代码具备 "抗需求变化体质"
1. 策略模式的好处
  • 解耦算法:每种登录逻辑独立在策略类中,可读性强

  • 易于扩展:新增登录方式只需添加新策略类,符合开闭原则

  • 方便测试:可以单独测试每个策略类,无需关心其他逻辑

2. 工厂模式的好处
  • 封装创建逻辑:调用者无需知道策略类的创建细节

  • 集中管理实例:通过 Spring 管理策略 Bean,支持依赖注入和生命周期管理

3. 结合 Spring Boot 的优势
  • 自动装配:通过@ServiceMap<String, LoginStrategy>自动收集所有策略 Bean

  • 类型安全:工厂类在运行时检查登录类型是否合法,避免NullPointerException

八、最佳实践:这些细节别忽略
1. 参数校验前置

在控制器中先对loginTypeparams做基础校验,比如必填参数检查,避免策略类中重复校验

2. 公共逻辑抽取

如果多种登录方式有公共逻辑(如登录成功后的 Token 生成),可以创建抽象策略类,让具体策略类继承

3. 日志和异常处理

在策略类中添加登录日志记录,统一捕获异常并返回友好的错误信息:

@Service public class PasswordLoginStrategy implements LoginStrategy { @Override public String execute(Map<String, Object> params) { try { // 登录逻辑 } catch (Exception e) { log.error("用户名密码登录失败:{}", e.getMessage()); throw new LoginException("登录失败,请重试"); // 自定义业务异常 } } }
4. 配置化登录类型

将支持的登录类型存储在配置文件中,前端调用时先获取支持的登录类型列表,避免硬编码

九、总结:设计模式让代码更有 "尊严"

回顾三年前的面条代码,再看现在的实现,最大的感受是:好的设计模式能让代码在需求变化面前保持优雅。工厂模式和策略模式的组合,就像给登录模块装了一个 "热插拔" 接口,新增功能时不用改核心逻辑,只需要添加新的 "插件"。

最后送大家一句口诀:登录逻辑别硬刚,策略模式来帮忙,工厂负责创实例,开闭原则记心上,Spring Boot 搭舞台,依赖注入真叫爽,需求万变不用慌,代码优雅没商量!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 3:25:01

零基础新手漏洞挖掘入门指南:要啥技能、去哪挖、怎么挖

零基础新手漏洞挖掘入门指南&#xff1a;要啥技能、去哪挖、怎么挖 漏洞挖掘是合法合规的安全实践&#xff0c;核心是 “先学基础、再练靶场、合规实战”&#xff0c;新手不用怕门槛高&#xff0c;按步骤推进就能逐步上手。 一、新手必备&#xff1a;3 大核心能力&#xff08;…

作者头像 李华
网站建设 2026/4/18 3:28:26

【收藏】提示学习入门指南:驱动大模型能力跃升的关键技术

提示学习是连接预训练语言模型与下游任务的关键技术&#xff0c;通过将任务转化为模型熟悉的完形填空形式&#xff0c;有效弥合预训练与微调之间的鸿沟。其核心包括提示模板和语言表达器两大组件&#xff0c;使模型能够高效应用于小样本甚至零样本场景&#xff0c;显著提升资源…

作者头像 李华
网站建设 2026/4/18 5:21:57

Open-AutoGLM一键部署脚本泄露(内部团队都在用的高效方案)

第一章&#xff1a;Open-AutoGLM一键部署脚本的核心价值Open-AutoGLM的一键部署脚本极大降低了大语言模型本地化部署的技术门槛&#xff0c;使开发者无需深入理解底层依赖与服务编排即可快速启动推理服务。该脚本集成了环境检测、依赖安装、模型下载与服务启动四大核心功能&…

作者头像 李华
网站建设 2026/4/18 7:14:34

智谱Open-AutoGLM部署必知的7个技术细节,少一步都可能失败

第一章&#xff1a;智谱Open-AutoGLM部署前的环境评估与准备在部署智谱AI推出的Open-AutoGLM系统前&#xff0c;必须对运行环境进行全面评估与配置&#xff0c;以确保模型推理与训练任务的高效稳定运行。该系统对计算资源、依赖库版本及硬件兼容性有较高要求&#xff0c;需提前…

作者头像 李华
网站建设 2026/4/18 5:24:32

语音唤醒准确率提升80%?Open-AutoGLM+ASR融合方案全解析

第一章&#xff1a;语音唤醒技术演进与Open-AutoGLM的融合机遇语音唤醒技术作为人机交互的关键入口&#xff0c;经历了从传统信号处理到深度学习驱动的跨越式发展。早期系统依赖于固定关键词的模板匹配与MFCC特征提取&#xff0c;虽具备低功耗优势&#xff0c;但泛化能力弱、误…

作者头像 李华