Java如何优雅的实现微信登录注册

 更新时间:2022年02月21日 11:12:52   作者:Anyin  
这篇文章主要给大家介绍了关于Java如何优雅的实现微信登录注册的相关资料,文中通过实例代码介绍的非常详细,对大家学习或者使用java具有一定的参考学习价值,需要的朋友可以参考下

引言

今天我们来聊一聊微信登录注册遇到的一些事儿。

在我们的业务系统中,一个用户在系统中肯定会有一个唯一标识,并且这个唯一标识一般是从系统外部获取的,而不是系统自动生成的,例如:手机号或者身份证。

我们在微信的场景下(微信公众号H5或者小程序),对于用户的唯一标识一般都是手机号或者openid。在正常情况下,我们遇到的都是一个用户只有一个微信号,一个微信号绑定了一个手机号,所以我们就认为三者的关系如下:

但是,理想很丰满,现实很骨感,我们遇到的情况肯定不会如此的简单。

问题分析

当一个系统运行的足够久,用户量足够多,那么你总会遇到各种奇奇怪怪的问题。

在上一节,我们知道正常情况遇到的场景会比较简单,用户、微信号、手机号三者是1:1:1的关系,也就说三者可以等价,我用其中一个信息,总是可以查询出另外两个的信息,例如:我可以用手机号,查询出用户ID和微信openid。

所以,根据以上思路,我们很容易设计出用户表:cus_info ,基本表结构如下:

用户ID微信openid用户手机号逻辑删除其他字段
idopenidmobiledel_flg...

但是当遇到以下2个场景的时候,这个表结构设计就无法满足需求了。

一个用户2个微信号有些用户是拥有两个微信号,并且绑定同一个手机号(这个逻辑可以通过微信换绑手机号实现)。

在这个场景下,一旦用户换了个微信号登录进入系统的时候,根据微信openid进行登录,因为表数据找不到该openid,则走注册流程;在注册的时候,又根据手机号查询用户信息,发现用户已经存在,返回登录流程,最终造成逻辑死循环。

一个用户2个手机号另外还有一些用户拥有2个手机号,并且绑定同一个手机号(这个逻辑在用户授权手机号的时候添加另外一个手机号实现)。

在这个场景下,第一次用户使用手机号A注册并登录,我们在后端绑定了手机号A和对应的微信openid;第二次用户使用手机号B注册并登录,这时候数据库会有2条记录,不同手机号相同的openid。这样子会导致在某些场景下(例如支付回调),根据openid获取用户信息的时候,找到2个用户,从而导致业务异常。

解决思路

以上2个问题,在不同的业务场景下,不同的人会有不同的解法。有以手机号作为用户的唯一标识,有以微信openid作为用户唯一标识。在这里,我们提供以手机号作为用户唯一标识的解法。

在这里,我们认为一个手机号就是一个用户,一个用户会有多个微信号。关系如下:

一个用户2个微信号针对该问题,我们在登录注册的时候,会通过逻辑控制,保证一个手机号只能找到一个微信openid。处理方式如下:

  • 根据当前的手机号查询到所有的微信openid,做逻辑删除处理
  • 根据当前的openid查询到所有的手机号,做逻辑删除处理
  • 根据当前手机号和openid查询是否存在记录,如果不存在则新增,如果存在则逻辑删除标识重置为正常。

一个用户2个手机号针对该问题,我们在业务上做处理。因为我们认为了一个手机号就是一个用户,如果一个用户拥有两个手机号,那么在我们系统上我们认为是两个用户,他们的数据是相互独立的。

另外在这个场景下,我们还需要提供一个手机号换绑的功能。这样当用户有2个手机号,也能给实现切换的需求。

方案实现

以上,相关解决思路我们有了。那么接下来就是设计和编码。

根据以上,我们会设计如下2张表结构:

cus_info 用户信息表

用户ID用户手机号逻辑删除其他字段
idmobiledel_flg...

cus_wx_info 用户和微信关联表

ID用户手机号微信appId微信openid开放平台unionid逻辑删除其他字段
idmobileapp_idopenidunioniddel_flg...

这里多添加了一个app_id的字段和unionid的字段,是用于当我们的业务涉及到多个入口,例如微信公众号H5入口和微信小程序。

不同的用户在微信公众号H5和微信小程序产生的openid可能一样也可能不一样,所以我们需要通过app_id来区分

同时为了关联在微信公众号H5和微信小程序的用户,我们会把微信公众号和微信小程序绑定到同一个开放平台,这个时候会产生一个unionid,通过该标识即可以找到微信公众号的用户,也可以找到微信小程序的用户。

接着我们实现一个注册方法。

@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) {
        // 根据手机号查询用户信息
        CsInfo info = csInfoRepository.infoByMobile(param.getMobile());
        Long id = info == null ? 0 : info.getId();
        // 如果用户不存在,则创建
        if(id == 0){
            id = csInfoRepository.create(param.getMobile(), param.getRegisterSource().getCode());
        }
        // 逻辑删除当前手机号绑定的openid
        // 逻辑删除当前openid绑定的手机号
        csWxInfoRepository.handleOpenidMobileUnique(param.getMobile(), param.getOpenid(), param.getAppId());
        
        // 保证当前手机号和openid在系统中1:1的关系
        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>

最后

至此,关于微信登录注册遇到的一些小问题,我们找到了一个相对比较好解决方案,你还不快实践到你自己项目上去?

相关源码地址:Anyin Cloud

到此这篇关于Java如何优雅的实现微信登录注册的文章就介绍到这了,更多相关Java微信登录注册内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • JAVA通过HttpClient发送HTTP请求的方法示例

    JAVA通过HttpClient发送HTTP请求的方法示例

    本篇文章主要介绍了JAVA通过HttpClient发送HTTP请求的方法示例,详细的介绍了HttpClient使用,具有一定的参考价值,有兴趣的可以了解一下
    2017-09-09
  • Java实现斗地主案例

    Java实现斗地主案例

    这篇文章主要为大家详细介绍了Java实现斗地主案例,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-04-04
  • Java中的对象和引用详解

    Java中的对象和引用详解

    这篇文章主要介绍了Java中的对象和引用详解的相关资料,需要的朋友可以参考下
    2017-05-05
  • spring5新特性全面介绍

    spring5新特性全面介绍

    本文将全面介绍 Spring 5。我将介绍 Java SE 8 和 Java EE 7 API 的基准升级、Spring 5 的新反应式编程模型、HTTP/2 支持,以及 Spring 通过 Kotlin 对函数式编程的全面支持。
    2020-10-10
  • 简单讲解Android开发中触摸和点击事件的相关编程方法

    简单讲解Android开发中触摸和点击事件的相关编程方法

    这篇文章主要介绍了Android开发中触摸和点击事件的相关编程方法,包括事件侦听器等安卓开发中常用的接口的基本使用方法,需要的朋友可以参考下
    2015-12-12
  • Spring如何在xml文件中配置Bean

    Spring如何在xml文件中配置Bean

    这篇文章主要介绍了Spring如何在xml文件中配置Bean的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-07-07
  • Java语言实现简单FTP软件 FTP协议分析(1)

    Java语言实现简单FTP软件 FTP协议分析(1)

    这篇文章主要介绍了Java语言实现简单FTP软件的第一篇,针对FTP协议进行分析,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-03-03
  • Java Metrics系统性能监控工具的使用详解

    Java Metrics系统性能监控工具的使用详解

    Metrics是一个Java库,可以对系统进行监控,统计一些系统的性能指标。本文就来和大家详细聊聊这个工具的具体使用,希望对大家有所帮助
    2022-11-11
  • Spring MVC---数据绑定和表单标签详解

    Spring MVC---数据绑定和表单标签详解

    本篇文章主要介绍了Spring MVC---数据绑定和表单标签详解,具有一定的参考价值,有兴趣的可以了解一下。
    2017-01-01
  • 如何在springMVC的controller中获取request

    如何在springMVC的controller中获取request

    这篇文章主要介绍了如何在springMVC的controller中获取request,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12

最新评论