news 2026/3/6 6:56:04

告别登录逻辑混乱!基于 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/2/19 0:16:23

三步搞定所有证件照!AI智能证件照在线制作源码系统

温馨提示&#xff1a;文末有资源获取方式极致便捷的操作流程整个系统设计以用户友好为核心&#xff0c;操作过程仅需三步。第一步&#xff0c;上传一张清晰的日常正面照片&#xff0c;无需特意去照相馆拍摄&#xff1b;第二步&#xff0c;从丰富的模板库中选择所需证件照规格&a…

作者头像 李华
网站建设 2026/3/1 22:21:38

深度测评9个降AIGC工具 千笔AI帮你轻松应对论文查重难题

AI降重工具&#xff1a;让论文更自然&#xff0c;更安全 在当今学术写作中&#xff0c;随着AI技术的广泛应用&#xff0c;越来越多的学生开始依赖AI生成内容来提高写作效率。然而&#xff0c;随之而来的AIGC率问题也成为了论文查重中的“隐形炸弹”。如何在保持原文语义不变的…

作者头像 李华
网站建设 2026/2/26 23:48:41

计算机毕业设计之springboot作业布置和批改的微信小程序的设计与实现

相比于以前的传统手工管理方式&#xff0c;智能化的管理方式可以大幅降低学校的运营人员成本&#xff0c;实现了作业布置和批改的标准化、制度化、程序化的管理&#xff0c;有效地防止了作业布置和批改的随意管理&#xff0c;提高了信息的处理速度和精确度&#xff0c;能够及时…

作者头像 李华