Java如何優(yōu)雅的實現(xiàn)微信登錄注冊
引言
今天我們來聊一聊微信登錄注冊遇到的一些事兒。
在我們的業(yè)務系統(tǒng)中,一個用戶在系統(tǒng)中肯定會有一個唯一標識,并且這個唯一標識一般是從系統(tǒng)外部獲取的,而不是系統(tǒng)自動生成的,例如:手機號或者身份證。
我們在微信的場景下(微信公眾號H5或者小程序),對于用戶的唯一標識一般都是手機號或者openid。在正常情況下,我們遇到的都是一個用戶只有一個微信號,一個微信號綁定了一個手機號,所以我們就認為三者的關(guān)系如下:

但是,理想很豐滿,現(xiàn)實很骨感,我們遇到的情況肯定不會如此的簡單。
問題分析
當一個系統(tǒng)運行的足夠久,用戶量足夠多,那么你總會遇到各種奇奇怪怪的問題。
在上一節(jié),我們知道正常情況遇到的場景會比較簡單,用戶、微信號、手機號三者是1:1:1的關(guān)系,也就說三者可以等價,我用其中一個信息,總是可以查詢出另外兩個的信息,例如:我可以用手機號,查詢出用戶ID和微信openid。
所以,根據(jù)以上思路,我們很容易設計出用戶表:cus_info ,基本表結(jié)構(gòu)如下:
| 用戶ID | 微信openid | 用戶手機號 | 邏輯刪除 | 其他字段 |
|---|---|---|---|---|
| id | openid | mobile | del_flg | ... |
但是當遇到以下2個場景的時候,這個表結(jié)構(gòu)設計就無法滿足需求了。
一個用戶2個微信號有些用戶是擁有兩個微信號,并且綁定同一個手機號(這個邏輯可以通過微信換綁手機號實現(xiàn))。
在這個場景下,一旦用戶換了個微信號登錄進入系統(tǒng)的時候,根據(jù)微信openid進行登錄,因為表數(shù)據(jù)找不到該openid,則走注冊流程;在注冊的時候,又根據(jù)手機號查詢用戶信息,發(fā)現(xiàn)用戶已經(jīng)存在,返回登錄流程,最終造成邏輯死循環(huán)。

一個用戶2個手機號另外還有一些用戶擁有2個手機號,并且綁定同一個手機號(這個邏輯在用戶授權(quán)手機號的時候添加另外一個手機號實現(xiàn))。
在這個場景下,第一次用戶使用手機號A注冊并登錄,我們在后端綁定了手機號A和對應的微信openid;第二次用戶使用手機號B注冊并登錄,這時候數(shù)據(jù)庫會有2條記錄,不同手機號相同的openid。這樣子會導致在某些場景下(例如支付回調(diào)),根據(jù)openid獲取用戶信息的時候,找到2個用戶,從而導致業(yè)務異常。
解決思路
以上2個問題,在不同的業(yè)務場景下,不同的人會有不同的解法。有以手機號作為用戶的唯一標識,有以微信openid作為用戶唯一標識。在這里,我們提供以手機號作為用戶唯一標識的解法。
在這里,我們認為一個手機號就是一個用戶,一個用戶會有多個微信號。關(guān)系如下:

一個用戶2個微信號針對該問題,我們在登錄注冊的時候,會通過邏輯控制,保證一個手機號只能找到一個微信openid。處理方式如下:
- 根據(jù)當前的手機號查詢到所有的微信openid,做邏輯刪除處理
- 根據(jù)當前的openid查詢到所有的手機號,做邏輯刪除處理
- 根據(jù)當前手機號和openid查詢是否存在記錄,如果不存在則新增,如果存在則邏輯刪除標識重置為正常。
一個用戶2個手機號針對該問題,我們在業(yè)務上做處理。因為我們認為了一個手機號就是一個用戶,如果一個用戶擁有兩個手機號,那么在我們系統(tǒng)上我們認為是兩個用戶,他們的數(shù)據(jù)是相互獨立的。
另外在這個場景下,我們還需要提供一個手機號換綁的功能。這樣當用戶有2個手機號,也能給實現(xiàn)切換的需求。
方案實現(xiàn)
以上,相關(guān)解決思路我們有了。那么接下來就是設計和編碼。
根據(jù)以上,我們會設計如下2張表結(jié)構(gòu):
cus_info 用戶信息表
| 用戶ID | 用戶手機號 | 邏輯刪除 | 其他字段 |
|---|---|---|---|
| id | mobile | del_flg | ... |
cus_wx_info 用戶和微信關(guān)聯(lián)表
| ID | 用戶手機號 | 微信appId | 微信openid | 開放平臺unionid | 邏輯刪除 | 其他字段 |
|---|---|---|---|---|---|---|
| id | mobile | app_id | openid | unionid | del_flg | ... |
這里多添加了一個app_id的字段和unionid的字段,是用于當我們的業(yè)務涉及到多個入口,例如微信公眾號H5入口和微信小程序。
不同的用戶在微信公眾號H5和微信小程序產(chǎn)生的openid可能一樣也可能不一樣,所以我們需要通過app_id來區(qū)分
同時為了關(guān)聯(lián)在微信公眾號H5和微信小程序的用戶,我們會把微信公眾號和微信小程序綁定到同一個開放平臺,這個時候會產(chǎn)生一個unionid,通過該標識即可以找到微信公眾號的用戶,也可以找到微信小程序的用戶。
接著我們實現(xiàn)一個注冊方法。
@Service
public class CsInfoServiceImpl implements CsInfoService {
@Autowired
private CsInfoRepository csInfoRepository;
@Autowired
private CsWxInfoRepository csWxInfoRepository;
@Autowired
private CsInfoConvert csInfoConvert;
@Override
@Transactional(rollbackFor = Throwable.class, timeout = 60)
public CsWxInfoDTO register(CsInfoRegisterDTO param) {
// 根據(jù)手機號查詢用戶信息
CsInfo info = csInfoRepository.infoByMobile(param.getMobile());
Long id = info == null ? 0 : info.getId();
// 如果用戶不存在,則創(chuàng)建
if(id == 0){
id = csInfoRepository.create(param.getMobile(), param.getRegisterSource().getCode());
}
// 邏輯刪除當前手機號綁定的openid
// 邏輯刪除當前openid綁定的手機號
csWxInfoRepository.handleOpenidMobileUnique(param.getMobile(), param.getOpenid(), param.getAppId());
// 保證當前手機號和openid在系統(tǒng)中1:1的關(guān)系
CsWxInfo wxInfo = csWxInfoRepository.infoByMobileOpenid(param.getMobile(), param.getOpenid(), param.getAppId());
if(wxInfo == null){
wxInfo = new CsWxInfo();
wxInfo.setAppId(param.getAppId());
wxInfo.setMobile(param.getMobile());
wxInfo.setOpenid(param.getOpenid());
wxInfo.setUnionid(param.getUnionid());
wxInfo.setAvatarUrl(param.getAvatarUrl());
wxInfo.setNickName(param.getNickName());
csWxInfoRepository.save(wxInfo);
}else{
CsWxInfo model = new CsWxInfo();
model.setId(wxInfo.getId());
model.setDelFlg(Integer.valueOf(DelFlgEnum.NORMAL.getCode()));
csWxInfoRepository.updateById(model);
}
CsWxInfoDTO result = csInfoConvert.getCsWxInfoDTO(wxInfo);
result.setInfoId(id);
return result;
}
} 其中handleOpenidMobileUnique方法對應的SQL處理如下:
<update id="loginDelByOpenIdExcludeMobile">
update cs_wx_info set del_flg = 0 ,update_time = now()
<where>
del_flg = 1
<if test="appId != null">
and app_id = #{appId}
</if>
<if test="openid != null and openid != ''">
and openid = #{openid}
</if>
<if test="mobile != null and mobile != ''">
and mobile != #{mobile}
</if>
</where>
</update>
<update id="loginDelByMobileExcludeOpenid">
update cs_wx_info set del_flg = 0 ,update_time = now()
<where>
del_flg = 1
<if test="appId != null">
and app_id = #{appId}
</if>
<if test="mobile != null and mobile != ''">
and mobile = #{mobile}
</if>
<if test="openid != null and openid != ''">
and openid != #{openid}
</if>
</where>
</update>最后
至此,關(guān)于微信登錄注冊遇到的一些小問題,我們找到了一個相對比較好解決方案,你還不快實踐到你自己項目上去?
相關(guān)源碼地址:Anyin Cloud
到此這篇關(guān)于Java如何優(yōu)雅的實現(xiàn)微信登錄注冊的文章就介紹到這了,更多相關(guān)Java微信登錄注冊內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot中利用AOP和攔截器實現(xiàn)自定義注解
本文將通過攔截器+AOP實現(xiàn)自定義注解,在這里攔截器充當在指定注解處要執(zhí)行的方法,aop負責將攔截器的方法和要注解生效的地方做一個織入,感興趣的可以嘗試一下2022-06-06
java實現(xiàn)數(shù)據(jù)庫的數(shù)據(jù)寫入到txt的方法
這篇文章主要為大家詳細介紹了java實現(xiàn)數(shù)據(jù)庫的數(shù)據(jù)寫入到txt的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-07-07
Java實現(xiàn)在Word中嵌入多媒體(視頻、音頻)文件
這篇文章主要介紹了Java如何實現(xiàn)在Word中嵌入多媒體(視頻、音頻)文件,文中的示例代碼講解詳細,對我們學習java有一定的幫助,感興趣的同學可以了解一下2021-12-12

