在进行系统开发时,经常会遇到那种会在不同方式之间进行切换使用,比如在gitee上的登录页面,它提供了多种登录方式,比如github登录,微信登录、华为云账号登录……在后端如果使用多个接口来接受不同的登录的话,就显得代码比较冗余,可维护性就很差。为了解决这种状况就可以使用策略工厂模式来实现登录方式的动态添加。
package com.example.demo;
public class Test {
public void Login(LoginBean loginBean){
switch (loginBean.LoginType){
case "WeChatLogin":
new WechatLogin().login(loginBean);
case "QQLogin":
new QQLogin().login(loginBean);
case "PhoneLogin":
new PhoneNumber().login(loginBean);
}
}
}
当让这样也是可以解决多种方式的登录,但是这样写的话,如果以后需要增加新的登录方式的话,又需要来修改业务层的代码,实现动态添加登录方式的话就比较繁杂。但是如果使用配置文件和策略工厂模式来结合的话,以后就不需要修改工厂类的业务代码,只需要增加新的登录接口实现类和添加配置文件的字段就可以了。
第一步设置一个登录的实体类对象:
package com.example.demo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class LoginBean {
//账号
public String username;
//账户密码
public String password;
//登录方式
public String LoginType = "Wechat";
}
指定一个登录的接口
package com.example.demo;
public interface LoginService {
public void login(LoginBean loginBean);
}
然后按照不同的登录方式,来实现各自的登录接口
package com.example.demo;
import org.springframework.stereotype.Service;
/**
* 这里就实现一个手机号登录的接口,并指定当前类在IOC容器中的
* 名称为 Phone
* */
@Service(value = "Phone")
public class PhoneNumber implements LoginService{
//重写登录方法
@Override
public void login(LoginBean loginBean) {
//TODO 这里首先不同方式的登录逻辑
System.out.println("使用手机号登录");
}
}
创建一个工厂类用来实现不同登录逻辑
package com.example.demo;
import jakarta.annotation.PostConstruct;
import lombok.Data;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.yaml.snakeyaml.Yaml;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
@Configuration
@Data
public class LoginFactory {
//创建一个Map集合用来接收配置文件中的配置信息
private static Map<String,String> loginType;
@Autowired
private ApplicationContext applicationContext;
public void Login(LoginBean loginBean) {
//使用这个方法方便,检查配置文件是否更新了,添加了新的登录方式
readYaml();
//通过登录方式,读取出登录接口的具体实现方法在IOC容器中的名称
String s = loginType.get(loginBean.getLoginType());
//通过applicationContext在IOC容器中获取指定对象
LoginService loginService = (LoginService) applicationContext.getBean(s);
loginService.login(loginBean);
}
public static void readYaml(){
Yaml yaml = new Yaml();
try{
//读取配置文件中的属性
InputStream inputStream = new FileInputStream("src/main/resources/application.yml");
Map<String,Object> load = yaml.load(inputStream);
loginType = (Map<String, String>) load.get("logintype");
}catch (Exception e){
e.printStackTrace();
}
}
}
最后定义配置文件,注意配置文件中的值必须与@Service注解中value属性定义的值一致
spring:
application:
name: factory_demo # 策略工厂模式demo
logintype:
WeChatLogin: Wechat
QQLogiin: QQ
PhoneLogin: Phone
TwierLogin: Twier
在登录时只需要传入登录请求,就可以让登录工厂自行断使用哪种登录方式来处理请求
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class LoginController {
@Autowired
LoginFactory loginFactory;
@PostMapping("login")
public String login(@RequestBody LoginBean loginBean){
loginFactory.Login(loginBean);
return "ok";
}
}