最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

優(yōu)雅可拓展的登錄封裝,讓你遠(yuǎn)離if-else

2023-08-20 12:12 作者:好困想睡覺(jué)了啦  | 我要投稿

前言

Hi,大家好,我是你們的禿頭朋友程序員小甲,相信各位碼農(nóng)朋友在搭建從0到1項(xiàng)目時(shí)在搭建完基建等任務(wù)后,最先去做的都是去搭建系統(tǒng)的用戶(hù)體系,那么每一個(gè)碼農(nóng)朋友都會(huì)去編碼屬于自己系統(tǒng)的一套用戶(hù)登錄注冊(cè)體系;但是登錄方式極其多樣,光小甲一個(gè)人對(duì)接的就有g(shù)oogle登錄,蘋(píng)果登錄,手機(jī)驗(yàn)證碼,微信驗(yàn)證碼登錄,微博登錄等各種各樣的登錄;

針對(duì)這么多的登錄方式,小甲是如何進(jìn)行功能接入的呢?(Ps:直接switch-case和if-else接入不香嗎,又不是不能用,這其實(shí)是小甲做功能時(shí)最真實(shí)的想法了,但是迫于團(tuán)隊(duì)老大哥的強(qiáng)大氣場(chǎng),小甲自然不敢這樣硬核編碼了),接下來(lái)就讓禿頭小甲和大伙一起分享一下是怎么讓普普通通的登錄也能玩出逼格的!(由于篇幅過(guò)長(zhǎng),接下來(lái)進(jìn)入硬核時(shí)刻,希望各位能挺住李云龍二營(yíng)長(zhǎng)的意大利跑前進(jìn)哈)

功能實(shí)現(xiàn)

技術(shù)棧:SpringBoot,MySQL,MyBatisPlus,hutool,guava,Redis,Jwt,Springboot-emial等;

sdk組件架構(gòu)

項(xiàng)目結(jié)構(gòu)包:

  1. scss復(fù)制代碼 ? tea-api(前臺(tái)聚合服務(wù))


  2. scss復(fù)制代碼 ? tea-mng(后管聚合服務(wù))


  3. scss復(fù)制代碼 ? tea-sdk(SpringBoot相關(guān)組件模塊)


  4. scss復(fù)制代碼 ? tea-common(公共模塊,提供一些工具類(lèi)支持和公有類(lèi)引用)


項(xiàng)目結(jié)構(gòu)引用關(guān)系: sdk引入了common包,api和mng引入了sdk包;

封裝思路

思路一:通過(guò)前端登錄路由請(qǐng)求頭key值通過(guò)反射生成對(duì)應(yīng)的LoginProvider類(lèi)來(lái)進(jìn)行登錄業(yè)務(wù)邏輯的執(zhí)行。具體的做法如下:

  1. 在classPath路徑下新增一個(gè)json/Provider.json文件,json格式如下圖所示:

  1. 定義具體的Provider繼承基類(lèi)Provider,禿頭小甲這里定義了一般業(yè)務(wù)系統(tǒng)最常對(duì)接的集中Provider(PS:由于google登錄和App登錄主要是用于對(duì)接海外業(yè)務(wù),因此小甲這里就沒(méi)把集成代碼放出來(lái)了)如下圖是小甲定義的幾個(gè)Provider:

其中UserLoginService是所有Provider的基類(lèi)接口,封裝了模板方法。EmialLoginProvider類(lèi)主要是實(shí)現(xiàn)郵箱驗(yàn)證碼登錄,PasswordProvider用于實(shí)現(xiàn)賬號(hào)密碼登錄,PhoneLoginProvider是用于手機(jī)號(hào)驗(yàn)證碼登錄.WbLoginProvider用于實(shí)現(xiàn)PC端微博授權(quán)登錄,WxLoginPrvider用于實(shí)現(xiàn)微信PC端授權(quán)登錄;

3.EmailLoginProvider和PhoneLoginProvider需要用到驗(yàn)證碼校驗(yàn),因此需要實(shí)現(xiàn)UserLoginService接口的驗(yàn)證碼獲取,并將獲取到的驗(yàn)證碼存儲(chǔ)到redis中;

4.將前端的路由gateWay作為key值,需要加載的動(dòng)態(tài)類(lèi)名作為value值。定義一個(gè)LoginService業(yè)務(wù)處理類(lèi),類(lèi)中定義一個(gè)Map緩存對(duì)象,在bean注入加載到ioc容器時(shí),通過(guò)讀取解析json文件對(duì)Map緩存進(jìn)行反射屬性注入,該設(shè)計(jì)理念參考了Springboot的SPI注入原理以此實(shí)現(xiàn)對(duì)Provider的可拔插操作;

思路二:

  1. 通過(guò)SpringBoot事件監(jiān)聽(tīng)機(jī)制,通過(guò)前端路由請(qǐng)求頭的key值發(fā)布生成不同的ApplicationEvent事件,利用事件監(jiān)聽(tīng)對(duì)業(yè)務(wù)處理解耦;

  2. 定義具體的Event事件以及Listener;

  3. 根據(jù)前端路由gateWay值生成需要發(fā)布的Event事件基類(lèi),在具體的listener類(lèi)上根據(jù)@EventListener注解來(lái)對(duì)具體的事件進(jìn)行監(jiān)聽(tīng)處理;

思路對(duì)比

思路一通過(guò)模板+工廠+反射等設(shè)計(jì)模式的原理對(duì)多方式登錄方式來(lái)達(dá)到解耦和拓展,從而規(guī)避了開(kāi)發(fā)人員大量的if-else或switch等硬編碼的方式,思路二通過(guò)模板+工廠+事件監(jiān)聽(tīng)機(jī)制等設(shè)計(jì)模式也做到了對(duì)多方式登錄的解耦和拓展,兩種思路均能做到延伸代碼的拓展性的作用;

封裝源碼

1.基類(lèi)UserLoginService

markdown復(fù)制代碼/** ?* 登錄 ?* ?* @param req 登錄請(qǐng)求體 ?* @return ?*/ LoginResp login(LoginReq req); ? /** ?* 驗(yàn)證碼獲取 ?* ?* @param req 登錄請(qǐng)求體 ?* @return ?*/ LoginResp vertifyCode(LoginReq req); ?

2.拓展類(lèi)Provider代碼

ini復(fù)制代碼public class EmailLoginProvider implements UserLoginService { ? ? ?@Override ?? ?public LoginResp login(LoginReq req) { ?? ? ? ?UserService userService = SpringUtil.getBean(UserService.class); ?? ? ? ?User user = userService.getOne(Wrappers.lambdaQuery(new User()).eq(User::getEmail, req.getEmail()).eq(User::getStatus, 1)); ?? ? ? ?if (Objects.isNull(user)) { ?? ? ? ? ? ?return null; ?? ? ? ?} ?? ? ? ?String redisKey = req.getEmail(); ?? ? ? ?RedisTemplate redisTemplate = SpringUtil.getBean(StringRedisTemplate.class); ?? ? ? ?String code = (String) redisTemplate.opsForValue().get(redisKey); ?? ? ? ?if (StringUtils.isEmpty(code)||!code.equals(req.getCode())) { ?? ? ? ? ? ?return null; ?? ? ? ?} ?? ? ? ?String token = JwtParse.getoken(user); ?? ? ? ?LoginResp resp = new LoginResp(); ?? ? ? ?resp.setToken(token); ?? ? ? ?return resp; ?? ?} ? ? ?@Override ?? ?public LoginResp vertifyCode(LoginReq req) { ?? ? ? ?String redisKey = req.getEmail(); ?? ? ? ?LoginResp resp = new LoginResp(); ?? ? ? ?RedisTemplate redisTemplate = SpringUtil.getBean(StringRedisTemplate.class); ?? ? ? ?String code = (String) redisTemplate.opsForValue().get(redisKey); ?? ? ? ?if (StringUtils.isNotEmpty(code)) { ?? ? ? ? ? ?resp.setCode(code); ?? ? ? ? ? ?return resp; ?? ? ? ?} ?? ? ? ?MailService mailService = SpringUtil.getBean(MailService.class); ?? ? ? ?String mailCode = CodeUtils.make(4); ?? ? ? ?mailService.sendMail(req.getEmail(), "郵箱驗(yàn)證碼", mailCode); ?? ? ? ?redisTemplate.opsForValue().set(req.getEmail(), mailCode); ?? ? ? ?return resp; ?? ?} } java復(fù)制代碼public class PasswordProvider implements UserLoginService { ? ? ?@Override ?? ?public LoginResp login(LoginReq req) { ?? ? ? ?UserService userService = SpringUtil.getBean(UserService.class); ?? ? ? ?User user = userService.getOne(Wrappers.lambdaQuery(new User()).eq(User::getPassword, req.getPassword()).eq(User::getStatus, 1)); ?? ? ? ?if (Objects.isNull(user)) { ?? ? ? ? ? ?return null; ?? ? ? ?} ?? ? ? ?String token = JwtParse.getoken(user); ?? ? ? ?LoginResp resp = new LoginResp(); ?? ? ? ?resp.setToken(token); ?? ? ? ?return resp; ?? ?} ? ? ?@Override ?? ?public LoginResp vertifyCode(LoginReq req) { ?? ? ? ?return null; ?? ?} } ini復(fù)制代碼public class PhoneLoginProvider implements UserLoginService { ? ? ?@Override ?? ?public LoginResp login(LoginReq req) { ?? ? ? ?UserService userService = SpringUtil.getBean(UserService.class); ?? ? ? ?User user = userService.getOne(Wrappers.lambdaQuery(new User()).eq(User::getPhone, req.getPhone()).eq(User::getStatus, 1)); ?? ? ? ?if (Objects.isNull(user)) { ?? ? ? ? ? ?return null; ?? ? ? ?} ?? ? ? ?String redisKey = req.getPhone(); ?? ? ? ?RedisTemplate redisTemplate = SpringUtil.getBean(RedisTemplate.class); ?? ? ? ?String code = (String) redisTemplate.opsForValue().get(redisKey); ?? ? ? ?if (!code.equals(req.getCode())) { ?? ? ? ? ? ?return null; ?? ? ? ?} ?? ? ? ?String token = JwtParse.getoken(user); ?? ? ? ?LoginResp resp = new LoginResp(); ?? ? ? ?resp.setToken(token); ?? ? ? ?return resp; ?? ?} ? ? ?@Override ?? ?public LoginResp vertifyCode(LoginReq req) { ?? ? ? ?String redisKey = req.getPhone(); ?? ? ? ?LoginResp resp = new LoginResp(); ?? ? ? ?RedisTemplate redisTemplate = SpringUtil.getBean(RedisTemplate.class); ?? ? ? ?String code = (String) redisTemplate.opsForValue().get(redisKey); ?? ? ? ?if (StringUtils.isNotEmpty(code)) { ?? ? ? ? ? ?resp.setCode(code); ?? ? ? ? ? ?return resp; ?? ? ? ?} ?? ? ? ?MailService mailService = SpringUtil.getBean(MailService.class); ?? ? ? ?String mailCode = CodeUtils.make(4); ?? ? ? ?mailService.sendMail(req.getPhone(), "手機(jī)登錄驗(yàn)證碼", mailCode); ?? ? ? ?redisTemplate.opsForValue().set(req.getEmail(), mailCode); ?? ? ? ?return resp; ?? ?} } ini復(fù)制代碼public class WxLoginProvider implements UserLoginService { ? ? ?@Override ?? ?public LoginResp login(LoginReq req) { ?? ? ? ?WxService wxService = SpringUtil.getBean(WxService.class); ?? ? ? ?WxReq wxReq = new WxReq(); ?? ? ? ?wxReq.setCode(req.getAuthCode()); ?? ? ? ?WxResp token = wxService.getAccessToken(wxReq); ?? ? ? ?String accessToken = token.getAccessToken(); ?? ? ? ?if (StringUtils.isEmpty(accessToken)) { ? ? ? ? ?} ?? ? ? ?wxReq.setOpenid(token.getOpenid()); ?? ? ? ?WxUserInfoResp userInfo = wxService.getUserInfo(wxReq); ?? ? ? ?//根據(jù)unionId和openid查找一下當(dāng)前用戶(hù)是否已經(jīng)存在系統(tǒng),如果不存在,幫其注冊(cè)這里單純是為了登錄; ?? ? ? ?UserService userService = SpringUtil.getBean(UserService.class); ?? ? ? ?User user = userService.getOne(Wrappers.lambdaQuery(new User()).eq(User::getOpenId, token.getOpenid()).eq(User::getUnionId, token.getUnionId())); ?? ? ? ?if (Objects.isNull(user)) { ? ? ? ? ?} ?? ? ? ?String getoken = JwtParse.getoken(user); ?? ? ? ?LoginResp resp = new LoginResp(); ?? ? ? ?resp.setToken(getoken); ?? ? ? ?return resp; ?? ?} ? ? ?@Override ?? ?public LoginResp vertifyCode(LoginReq req) { ?? ? ? ?return null; ?? ?} }

3.接口暴露Service--LoginService源碼

typescript復(fù)制代碼@Service @Slf4j public class LoginService { ? ? ?private Map<String, UserLoginService> loginServiceMap = new ConcurrentHashMap<>(); ? ? ?@PostConstruct ?? ?public void init() { ?? ? ? ?try { ?? ? ? ? ? ?List<JSONObject> jsonList = JSONArray.parseObject(ResourceUtil.getResource("json/Provider.json").openStream(), List.class); ?? ? ? ? ? ?for (JSONObject object : jsonList) { ?? ? ? ? ? ? ? ?String key = object.getString("key"); ?? ? ? ? ? ? ? ?String className = object.getString("value"); ?? ? ? ? ? ? ? ?Class loginProvider = Class.forName(className); ?? ? ? ? ? ? ? ?UserLoginService loginService = (UserLoginService) loginProvider.newInstance(); ?? ? ? ? ? ? ? ?loginServiceMap.put(key, loginService); ?? ? ? ? ? ?} ?? ? ? ?} catch (Exception e) { ?? ? ? ? ? ?log.info("[登錄初始化異常]異常堆棧信息為:{}", ExceptionUtils.parseStackTrace(e)); ?? ? ? ?} ?? ?} ? ? ?/** ?? ? * 統(tǒng)一登錄 ?? ? * ?? ? * @param gateWayRoute 路由路徑 ?? ? * @param req ? ? ? ? ?登錄請(qǐng)求 ?? ? * @return ?? ? */ ?? ?public RetunrnT<LoginResp> login(String gateWayRoute, LoginReq req) { ?? ? ? ?UserLoginService userLoginService = loginServiceMap.get(gateWayRoute); ?? ? ? ?LoginResp loginResp = userLoginService.login(req); ?? ? ? ?return RetunrnT.success(loginResp); ?? ?} ? ?? ?/** ?? ? * 驗(yàn)證碼發(fā)送 ?? ? * ?? ? * @param gateWayRoute 路由路徑 ?? ? * @param req ? ? ? ? ?登錄請(qǐng)求 ?? ? * @return ?? ? */ ?? ?public RetunrnT<LoginResp> vertifyCode(String gateWayRoute, LoginReq req) { ?? ? ? ?UserLoginService userLoginService = loginServiceMap.get(gateWayRoute); ?? ? ? ?LoginResp resp = userLoginService.vertifyCode(req); ?? ? ? ?return RetunrnT.success(resp); ?? ?} ?}

4.郵件發(fā)送Service具體實(shí)現(xiàn)--MailService

typescript復(fù)制代碼public interface MailService { ? ? ?/** ?? ? * 發(fā)送郵件 ?? ? * ?? ? * @param to ? ? ?收件人 ?? ? * @param subject 主題 ?? ? * @param content 內(nèi)容 ?? ? */ ?? ?void sendMail(String to, String subject, String content); } less復(fù)制代碼@Service @Slf4j public class MailServiceImpl implements MailService { ? ? ?/** ?? ? * Spring Boot 提供了一個(gè)發(fā)送郵件的簡(jiǎn)單抽象,直接注入即可使用 ?? ? */ ?? ?@Resource ?? ?private JavaMailSender mailSender; ?? ?/** ?? ? * 配置文件中的發(fā)送郵箱 ?? ? */ ?? ?@Value("${spring.mail.from}") ?? ?private String from; ? ? ?@Override ?? ?@Async ?? ?public void sendMail(String to, String subject, String content) { //創(chuàng)建一個(gè)郵箱消息對(duì)象 ?? ? ? ?SimpleMailMessage message = new SimpleMailMessage(); ?? ? ? ?//郵件發(fā)送人 ?? ? ? ?message.setFrom(from); ?? ? ? ?//郵件接收人 ?? ? ? ?message.setTo(to); ?? ? ? ?//郵件主題 ?? ? ? ?message.setSubject(subject); ?? ? ? ?//郵件內(nèi)容 ?? ? ? ?message.setText(content); ?? ? ? ?//發(fā)送郵件 ?? ? ? ?mailSender.send(message); ?? ? ? ?log.info("郵件發(fā)成功:{}", message.toString()); ?? ?} }

5.token生成JsonParse類(lèi)

typescript復(fù)制代碼private static final String SECRECTKEY = "zshsjcbchsssks123"; ?public static String getoken(User user) { ?? ?//Jwts.builder()生成 ?? ?//Jwts.parser()驗(yàn)證 ?? ?JwtBuilder jwtBuilder = Jwts.builder() ?? ? ? ? ? ?.setId(user.getId() + "") ?? ? ? ? ? ?.setSubject(JSON.toJSONString(user)) ? ?//用戶(hù)對(duì)象 ?? ? ? ? ? ?.setIssuedAt(new Date())//登錄時(shí)間 ?? ? ? ? ? ?.signWith(SignatureAlgorithm.HS256, SECRECTKEY).setExpiration(new Date(System.currentTimeMillis() + 86400000)); ?? ?//設(shè)置過(guò)期時(shí)間 ?? ?//前三個(gè)為載荷playload 最后一個(gè)為頭部 header ?? ?log.info("token為:{}", jwtBuilder.compact()); ?? ?return jwtBuilder.compact(); }

6.微信認(rèn)證授權(quán)Service---WxService

csharp復(fù)制代碼 public interface WxService { ? ? ?/** ?? ? * 通過(guò)code獲取access_token ?? ? */ ?? ?WxResp getAccessToken(WxReq req); ? ? ?/** ?? ? * 通過(guò)accessToken獲取用戶(hù)信息 ?? ? */ ?? ?WxUserInfoResp getUserInfo(WxReq req); } less復(fù)制代碼@Service @Slf4j public class WxServiceImpl implements WxService { ? ? ?@Resource ?? ?private WxConfig wxConfig; ? ?? ?@Override ?? ?public WxResp getAccessToken(WxReq req) { ?? ? ? ?req.setAppid(wxConfig.getAppid()); ?? ? ? ?req.setSecret(wxConfig.getSecret()); ?? ? ? ?Map map = JSON.parseObject(JSON.toJSONString(req), Map.class); ?? ? ? ?WxResp wxResp = JSON.parseObject(HttpUtil.createGet(wxConfig.getTokenUrl()).formStr(map).execute().body(), WxResp.class); ?? ? ? ?return wxResp; ?? ?} ? ? ?@Override ?? ?public WxUserInfoResp getUserInfo(WxReq req) { ?? ? ? ?req.setAppid(wxConfig.getAppid()); ?? ? ? ?req.setSecret(wxConfig.getSecret()); ?? ? ? ?Map map = JSON.parseObject(JSON.toJSONString(req), Map.class); ?? ? ? ?return JSON.parseObject(HttpUtil.createGet(wxConfig.getGetUserUrl()).formStr(map).execute().body(), WxUserInfoResp.class); ?? ?} }

功能演練

項(xiàng)目總結(jié)

相信很多小伙伴在平時(shí)開(kāi)發(fā)過(guò)程中都能看到一定的業(yè)務(wù)硬核代碼,前期設(shè)計(jì)不合理,后續(xù)開(kāi)發(fā)只能在前人的基礎(chǔ)上不斷的進(jìn)行if-else或者switch來(lái)進(jìn)行業(yè)務(wù)的功能拓展,千里之行基于跬步,地基不穩(wěn)注定是要地動(dòng)山搖的,希望在接下來(lái)的時(shí)光,禿頭小甲也能不斷提升自己的水平,寫(xiě)出更多有水準(zhǔn)的代碼;

碎碎念時(shí)光

首先很感謝能看完全篇幅的各位老鐵兄弟們,希望本篇文章能對(duì)各位和禿頭小甲一樣碼農(nóng)有所幫助,當(dāng)然如果各位技術(shù)大大對(duì)這模塊做法有更優(yōu)質(zhì)的做法的,也歡迎各位技術(shù)大大能在評(píng)論區(qū)留言探討,寫(xiě)在最后~~~~~~ 創(chuàng)作不易,希望各位老鐵能不吝惜于自己的手指,幫禿頭點(diǎn)下您寶貴的贊把!

優(yōu)雅可拓展的登錄封裝,讓你遠(yuǎn)離if-else的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
昂仁县| 法库县| 九寨沟县| 阿克| 东乡族自治县| 海口市| 庆云县| 中超| 航空| 吴川市| 景泰县| 蓝田县| 临潭县| 崇礼县| 华阴市| 孝昌县| 淮南市| 金塔县| 自治县| 桐柏县| 商河县| 靖江市| 青神县| 巴林左旗| 临朐县| 桐乡市| 乌拉特后旗| 简阳市| 镇坪县| 新乡市| 磐安县| 鄂伦春自治旗| 民乐县| 滕州市| 盐津县| 建德市| 蒲江县| 古丈县| 五寨县| 西充县| 钦州市|