目录
本文仅提供了短信登录,其他登录方式可复用。
一、控制层controller
二、登录策略接口
三、登录策略实现
?四、策略工厂
五、登录类型枚举
六、pom配置所需依赖
七、疑问联系
本文仅提供了短信登录,其他登录方式可复用。
一、控制层controller
@SneakyThrows(value = RenException.class)
@PostMapping("smsCodeLogin")
@ApiOperation("短信验证码登录")
public Result<Map<String, Object>> smsCodeLogin(@Valid @RequestBody SmsCodeLoginBody smsCodeLoginBody, HttpServletRequest request) {
LoginStrategy loginStrategy = AnnotationLoginStrategyFactory.getTaxStrategy(LoginTypeEnum.VERIFY_CODE_LOGIN);
/** 参数赋值需自行实现 */
return loginStrategy.login(loginParam);
}
二、登录策略接口
?统一service接口
/**
* 登录方法
* @param loginParam
* @return
*/
Result<Map<String, Object>> login(LoginParam loginParam);
三、登录策略实现
@Service
@LoginTypeAnnotation(loginType = LoginTypeEnum.VERIFY_CODE_LOGIN)
public class SmsCodeServiceImpl implements SmsCodeService, LoginStrategy {
/**
* 验证码有效期(分钟)
*/
Integer duration = 5;
@Autowired
SmsLoginService smsLoginService;
@Autowired
TokenService tokenService;
@Autowired
AppUserService userService;
@Autowired
RedisCache redisCache;
@Autowired
PrizeTimesService timesService;
@Override
public Result<String> send(String mobile, SmsCodeTypeEnums codeTypeEnums) {
// 判断是否恶意请求
if (redisCache.hasKey(RedisKeys.smsSendKey(), mobile)) {
return new Result<String>().error("请求过于频繁,请稍后再试!");
}
//随机生成验证码
String code = RandomUtil.randomInt(1000, 9999) + "";
boolean result = redisCache.setCacheMapValue(codeTypeEnums.getMessage(), mobile, code, duration, TimeUnit.MINUTES);
if (!result) {
return new Result<String>().error(ErrorCode.GET_CODE_FAIL);
}
Result<String> sendResult = smsLoginService.sendSmsCode(mobile, code, duration);
if (sendResult.success()) {
redisCache.increment(RedisKeys.smsSendKey(), mobile, 1, 1, TimeUnit.MINUTES);
}
return sendResult;
}
@Override
public Result<String> verify(SmsCodeTypeEnums codeTypeEnums, String mobile) {
if (null == redisCache) {
redisCache = SpringContextUtils.getBean(RedisCache.class);
}
//从短信缓存管理器中获取
String code = redisCache.getCacheMapValue(codeTypeEnums.getMessage(), mobile);
if (StringUtils.isEmpty(code)) {
return new Result<String>().error(ErrorCode.INVALID_CODE);
}
return new Result<String>().ok(code);
}
@Override
public Result<Map<String, Object>> login(LoginParam loginParam) {
userService = SpringContextUtils.getBean(AppUserService.class);
tokenService = SpringContextUtils.getBean(TokenService.class);
timesService = SpringContextUtils.getBean(PrizeTimesService.class);
// 返回参数
Map<String, Object> map = new HashMap<String, Object>();
// 获取验证码
Result<String> verifyResult = verify(SmsCodeTypeEnums.SMS_TYPE_LOGIN, loginParam.getMobile());
if (!verifyResult.success()) {
return new Result<Map<String, Object>>().error(ErrorCode.INVALID_CODE);
}
// 校验
String code = verifyResult.getData();
if (!loginParam.getSmsCode().equals(code)) {
return new Result<Map<String, Object>>().error(ErrorCode.CODE_ERROR);
}
AppUserEntity userEntity = userService.getByMobile(loginParam.getMobile());
// 用户信息为空,则为注册
if (null == userEntity) {
userEntity = buildUserParams(loginParam.getMobile(), loginParam.getPlatform(), null != loginParam.getInviterId() ? loginParam.getInviterId() : null);
userService.insert(userEntity);
userEntity = userService.getByMobile(loginParam.getMobile());
timesService.register(userEntity.getId());
}
// 生成token
map.put("accessToken", tokenService.createToken(new LoginUser(userEntity, null)));
map.put("userId", userEntity.getId());
return new Result<Map<String, Object>>().ok(map);
}
private AppUserEntity buildUserParams(String mobile, String platform, Integer inviterId) {
AppUserEntity entity = new AppUserEntity();
entity.setMobile(mobile);
entity.setName(NumberUtil.getStringRandom(8));
entity.setInviterId(inviterId);
entity.setUserImgUrl(Constant.DEFAULT_IMG);
if (platform.contains("Android")) {
entity.setUserChannel(UserChannelEnums.ANDROID.getNum());
} else {
entity.setUserChannel(UserChannelEnums.IOS.getNum());
}
entity.setAuditStatus(UserAuditStatusEnums.CHECK_PENDING.getNum());
entity.setOpenStatus(OpenStatusEnums.OPEN_STATUS.getNum());
entity.setAuthStatus(1);
entity.setCreator(Constant.ID);
entity.setCreateDate(new Date());
entity.setAuditTime(new Date());
return entity;
}
?四、策略工厂
public class AnnotationLoginStrategyFactory {
// 存储税策略
static Map<LoginTypeEnum, LoginStrategy> loginStrategyMap = new HashMap<>();
static {
registerTaxStrategy();
}
// 通过map获取登录策略,当增加新的登录策略时无需修改代码,对修改封闭,对扩展开放,遵循开闭原则
public static LoginStrategy getTaxStrategy(LoginTypeEnum loginType) throws RenException {
// 当增加新的登录类型时,需要修改代码,同时增加圈复杂度
if (loginStrategyMap.containsKey(loginType)) {
return loginStrategyMap.get(loginType);
} else {
throw new RenException(ErrorCode.NOT_SUPPORT_LOGIN_TYPE);
}
}
// 登录策略
private static void registerTaxStrategy() {
try {
// 通过反射找到所有的登录策略子类进行注册
Reflections reflections = new Reflections(new ConfigurationBuilder()
.setUrls(ClasspathHelper.forPackage("com.haiyeke.hjh.api.service"))
.setScanners(new SubTypesScanner()));
Set<Class<? extends LoginStrategy>> taxStrategyClassSet = reflections.getSubTypesOf(LoginStrategy.class);
if (taxStrategyClassSet != null) {
for (Class<?> clazz: taxStrategyClassSet) {
// 找到登录注解,自动完成登录策略注册
if (clazz.isAnnotationPresent(LoginTypeAnnotation.class)) {
LoginTypeAnnotation taxTypeAnnotation = clazz.getAnnotation(LoginTypeAnnotation.class);
LoginTypeEnum taxType = taxTypeAnnotation.loginType();
loginStrategyMap.put(taxType, (LoginStrategy)clazz.newInstance());
}
}
}
} catch (InstantiationException | IllegalAccessException e) {
// 自行定义异常处理
e.printStackTrace();
}
}
五、登录类型枚举
/**
* 登录类型枚举
*/
public enum LoginTypeEnum {
/**
* 微信登录
*/
WX_LOGIN,
/**
* 抖音登录
*/
DY_LOGIN,
/**
* 验证码登录
*/
VERIFY_CODE_LOGIN,
/**
* APP一键登录
*/
APP_ONE_CLICK_LOGIN,
/**
* H5一键登录
*/
WEB_ONE_CLICK_LOGIN,
/**
* 微信小程序登录
*/
WX_MINI_LOGIN,
/**
* 抖音小程序登录
*/
DY_MINI_LOGIN
}
六、pom配置所需依赖
反射工具类
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.11</version>
</dependency>
七、疑问联系
如有疑问可私信联系我本人,如不能及时回复请联系微信:yanwg_?
|