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

目录
  • 引言
  • 问题分析
  • 解决思路
  • 方案实现
  • 最后

引言

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

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

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

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

问题分析

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

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

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

用户ID 微信openid 用户手机号 逻辑删除 其他字段
id openid mobile del_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 用户手机号 逻辑删除 其他字段
id mobile del_flg ...

cus_wx_info 用户和微信关联表

ID 用户手机号 微信appId 微信openid 开放平台unionid 逻辑删除 其他字段
id mobile app_id openid unionid del_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微信登录注册内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详解java实现简单扫码登录功能(模仿微信网页版扫码)

    java实现简单扫码登录功能 模仿微信pc网页版扫码登录 使用js代码生成qrcode二维码减轻服务器压力 js循环请求服务端,判断是否qrcode被扫 二维码超时失效功能 二维码被扫成功登录,服务端产生sessionId,传到页面使用js保存cookie 多线程 生成qrcode相关js jquery.qrcode.js 代码 页面div <div class="pc_qr_code"> <input type="hidden" id="

  • java实现微信小程序登录态维护的示例代码

    相信不少喜欢开发的朋友都已经知道微信小程序是个什么物种了,楼主也是从小程序内测期间就开始关注,并且也写过几个已经上线的微信小程序.但是基本上都是写的纯前端,最近楼主从后端到前端写一个完整的小程序项目,中间碰到了一些问题,楼主会找一些个人觉得有学习价值的点不定时的拿出来跟大家分享,希望对你有一些帮助. 本次就从最基本的微信小程序登录态维护开始吧.小程序官方api文档里面有对登录态的一个完整的解释,并且有相关的代码.想看详情,可以出门右转:https://mp.weixin.qq.com/debug

  • java实现 微博登录、微信登录、qq登录实现代码

    微信,微博,QQ,这是现在目前用的最多的手机 APP,我们做产品哪能不跟他们不沾边,对于登录,我想谁也不想要多少个帐号密码,根本记不住! 为了增加用户体验,用户能够快速的注册登录,第三方账号进行登录注册的的需求也就由此而诞生 1.微信 1) 微信登录也是最坑人的,需要花300大洋成为开发者账户,没办法谁让微信用户群体大呢所以也就只好认了:然后登录网站后台需要创建网站应用,填写授权回调域(登录网站的域名)只填写域名即可 申请地址: https://open.weixin.qq.com/cgi-bi

  • 第三方网站微信登录java代码实现

    前两个星期在公司中的项目加上了微信登录.绑定的功能,在这里做个记录! 一.开发前知识 1.微信开放平台与微信公众平台的区别 1.1 微信公众平台: ① 地址:https://mp.weixin.qq.com/cgi-bin/loginpage?t=wxm2-login&lang=zh_CN ② 微信公众平台面向的是普通的用户,比如自媒体和媒体,企业官方微信公众账号运营人员使用,当然你所在的团队或者公司有实力去开发一些内容,也可以调用公众平台里面的接口,比如自定义菜单,自动回复,查询功能. 1.2

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

    目录 引言 问题分析 解决思路 方案实现 最后 引言 今天我们来聊一聊微信登录注册遇到的一些事儿. 在我们的业务系统中,一个用户在系统中肯定会有一个唯一标识,并且这个唯一标识一般是从系统外部获取的,而不是系统自动生成的,例如:手机号或者身份证. 我们在微信的场景下(微信公众号H5或者小程序),对于用户的唯一标识一般都是手机号或者openid.在正常情况下,我们遇到的都是一个用户只有一个微信号,一个微信号绑定了一个手机号,所以我们就认为三者的关系如下: 但是,理想很丰满,现实很骨感,我们遇到的情况

  • 基于IO版的用户登录注册实例(Java)

    今天学的是用户登录注册功能. 4个包: itcast.cn.user包 User.java 用户类,描述用户基本信息,包括成员变量,无参构造函数,带参构造(可有可无).get和set方法 package itcast.cn.day22; /* * 用户基本描述包类 */ public class User { private int userName; private int passWord; public User(){ super(); } public User(int userName

  • java实现  微博登录、微信登录、qq登录实现代码

    微信,微博,QQ,这是现在目前用的最多的手机 APP,我们做产品哪能不跟他们不沾边,对于登录,我想谁也不想要多少个帐号密码,根本记不住! 为了增加用户体验,用户能够快速的注册登录,第三方账号进行登录注册的的需求也就由此而诞生 1.微信 1) 微信登录也是最坑人的,需要花300大洋成为开发者账户,没办法谁让微信用户群体大呢所以也就只好认了:然后登录网站后台需要创建网站应用,填写授权回调域(登录网站的域名)只填写域名即可 申请地址: https://open.weixin.qq.com/cgi-bi

  • Java简易登录注册小程序

    登录注册小代码,将学过的一些小知识融合在一起进行了使用,加深印象.本例中如果有注释不详细的地方,详见其它博客. 功能介绍:简单的登录注册系统,使用了数据库sqlserver.单例模式.正则表达式以及图形化开发等知识. 1.在登录界面,可以登录或者注册用户. 注册用户界面,按照正则表达式规定的格式要求来输入信息,若有误,则重新输入. 2.点击注册,首先连接SQLserver数据库,连接成功则会判断该用户名是否已经存在,若存在,则给出提示.反之则进行注册. 3.登录界面,点击登录按钮时,首先与数据库

  • 详解微信小程序入门从这里出发(登录注册、开发工具、文件及结构介绍)

    (一) 准备工作 (1) 登录注册 注册账号:这就不谈了,只需要注意使用一个全新的邮箱,别之前注册过公众号小程序等就可以了 https://mp.weixin.qq.com/wxopen/waregister?action=step1 登录账号:通过邮箱密码登录,亦或者绑定微信后使用扫码也是可以的 https://mp.weixin.qq.com/ (2) 获取 APPID 登录后,在开发入门的阶段有一个比较重要的内容需要了解,那就是 APPID,很好理解,就是这个小程序的唯一标识,就类似我们的

  • vue3如何优雅的实现移动端登录注册模块

    前言 近期开发的移动端项目直接上了 vue3 ,新特性 composition api 确实带来了全新的开发体验.开发者在使用这些特性时可以将高耦合的状态和方法放在一起统一管理,并能视具体情况将高度复用的逻辑代码单独封装起来,这对提升整体代码架构的健壮性很有帮助. 如今新启动的每个移动端项目基本上都包含注册登录模块,本次实践过程中针对登录注册中的表单控件做了一些经验上的总结,通过抽离提取共性代码来提升代码的可维护性和开发效率. 接下来观察一下美工同学提供的图片. 注册页面 登录页面 忘记密码页面

  • 微信小程序实现登录注册功能

    本文实例为大家分享了微信小程序实现登录注册的具体代码,供大家参考,具体内容如下 html: <form bindsubmit="handleSubmit" wx:if="{{ onoff }}"> 用户名: <input type="text" name='username'/> 密码: <input type="password" name='password'/> 手机号: <in

  • Java实现简单登录注册

    本文实例为大家分享了Java实现简单登录注册的具体代码,供大家参考,具体内容如下 一.登录 1. 内容介绍 定义一个内置的账号和密码,写好账号输入.密码输入.随机验证码生成.验证码输入方法(3个输入方法没有使用重载)以及账号密码验证码比较方法.调用这些方法实现简单的控制台登录. 2. 思路解析 方法调用.优先判断验证码,在判断账号最后判断密码. 3. 代码实现 import java.util.Random; import java.util.Scanner; public class Logi

随机推荐