本文只是某项目的一个记录。 

需求:

官方给出的流程如下:

我们先按这个图中流程实现。 

第一步:获取open_id,首先得获取一个code,根据code进一步查询open_id。

		wx.login({
			success: res => {
				//获取code
				resolve(res.code)
			}
		})

我们把这个方法封装为getcode()

 ps:wx.login(Object object) | 微信开放文档

第二步:在微信小程序首页的onload中,调用getWechatInfo方法,把code传到后台服务,进一步查询open_id:

	async getWeChatInfo() {
			//获取code
			const code = await getCode()
			let  that=this;
			//将code发给后端请求token
			await uni.request({
				url: loginRequest.baseURL + "getWeChat",
				method: 'POST',
				data: {
					code
				},
				success: res => {
					if (res.data.code === 200) {
						this._openId = res.data.data.openId;
						//自定义登录状态存入缓存
						wx.setStorageSync('token', res.data.data.token);
						//后面2个最好不要存在缓存中  xj
						wx.setStorageSync('openId', res.data.data.openId);
						wx.setStorageSync('loginFlag', res.data.data.loginFlag);

						that.getUserInfoByOpenId();   
						//this.getUserInfoByOpenId();
					} else {
						this._openId = "-1";
						uni.showToast({
							title: res.data.msg,
							icon: 'error',
							duration: 2000
						})
						return;
					}
				}
			})
		},

 第三步:服务端进行登录凭证校验接口appid+appsect+code:

我们通过集成第三方 WxMaService 在服务端进行登录凭证校验(参数:appid+appsect+code),从而获取session_key及openid。

服务端具体代码如下:

   public JSONObject getWeChat(WeChatDTO weChatDTO) {
        String code = weChatDTO.getCode();
        log.info("code: {}", code);
        if (StrUtil.isBlank(code)) {
            throw new BizException("非法的授权码信息!");
        }
        WxMaProperties.Config config = wxMaProperties.getConfigs().stream().findFirst().get();

        if (!wxMaService.switchover(config.getAppid())) {
            throw new BizException(String.format("未找到对应appid=[%s]的配置,请核实!", config.getAppid()));
        }

        try {
            WxMaJscode2SessionResult session = wxMaService.getUserService().getSessionInfo(code);
            String sessionKey = session.getSessionKey();
            String openid = session.getOpenid();
            String unionid = session.getUnionid();
            if (!StrUtil.isAllNotBlank(sessionKey, openid)) {
                throw new BizException("登录失败!");
            }
            log.info("current sessionKey : {} ,openId:{}, unionid:{}", sessionKey, openid, unionid);
            //new json object
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("openId", openid);
            jsonObject.put("unionId", unionid);
            jsonObject.put("sessionKey", sessionKey);
            jsonObject.put("code", code);
            jsonObject.put("loginFlag", 1);   // 1: online 0: offline
            //产生一个随机数token
            String token = StrUtil.uuid();
            jsonObject.put("token", token);
            //以token为key,将jsonObject存入redis
            redisTemplate.opsForValue().set(token, jsonObject, 30, TimeUnit.MINUTES);
            return jsonObject;   // todo  返回值应该只有token  后面有时间再改
            //return openid;
        } catch (Exception exception) {
            log.error("获取微信信息失败:{}", exception.getLocalizedMessage());
            throw new BizException("获取微信信息失败!");
        } finally {
            WxMaConfigHolder.remove();//清理ThreadLocal
        }
    }

ps:WxMaService使用方式如下:

 配置:

       <dependency>
            <groupId>com.github.binarywang</groupId>
            <artifactId>weixin-java-miniapp</artifactId>
            <version>4.5.0</version>
        </dependency>

它的使用方法及配置可以参见: 

如何实现spring boot整合微信小程序订阅推送WxMaService的具体操作步骤 

WxMaUserService (WxJava - MiniApp Java SDK 4.6.0 API)

我们把token 存放在小程序缓存当中。

业务请求的时候:

正常情况,每次微信小程序向业务端发起业务请求,都应该带上该token,后台服务根据该token,查询openId、session_key 等信息,做相关业务处理。

我们目前是用open_id作为token,这个办法值得商榷,下一版本再做修改!

另外一个问题是,某君希望我们把主页换掉,我们原理微信小程序主页是个列表页面,某君希望是改为业务主页面! 

没钱?~~~~~~~~~~~~? 

我们进入小程序主页的时候,就要获取用户信息,以此为依据控制展示内容。

获取用户信息(getUserInfoByOpenId):

首先说明一下,getUserInfoByOpenId  ,这个方法就是根据openId,查询用户信息。

如果数据库没有这个openId的记录,说明这个用户不存在或者没有登录过,这个时候,页面还是主页面,但是,应该呈现登录按钮,点击登录按钮的时候,获取本机手机号,传递到后台,对比手机号记录,判断该用户是否注册用户。  当然 每次请求后台的时候,应该带上该openId,

如果后台数据库有这个openId记录,说明是合法且已经登录过的用户,这个时候,可以直接呈现主页面信息!同时呈现出直接进入按钮。否则这个按钮应该是登录按钮。

		async getUserInfoByOpenId() {
			uni.request({
				url: loginRequest.baseURL +
					"getUserInfoByOpenId",
				method: 'POST',
				data: {
					openId: this._openId,
					token: wx.getStorageSync('token')
				},
				success: res => {
					console.log('------------------res-----------: ', res)
					if (res.data.code === 200) {
						res.data.data.doctors = res.data.data.doctors == null ? "" : res.data.data.doctors
						//if   res.data.data.phone  is not null and not empty and doctors is not null and not empty ,then login success,to home page
						if ( res.data.data.doctors != null && res.data.data.doctors != "") {
							//将token保存本地
							//wx.setStorageSync('token', res.data.data.openId)
							// wx.setStorageSync('token', this._openId)
							// wx.setStorageSync('loginFlag', 1)
							//将用户信息保存本地
							let userInfo = res.data.data.doctors
							console.log('userInfo:', userInfo)
							wx.setStorageSync('userInfo', userInfo)
							//uni navigate to home page
							let _status=res.data.data.doctors.loginStatus;
							if(_status==1){     //后台已经有记录 直接登录
								this.loginButtonType = 1;
							}else{
								this.loginButtonType = 0;	
							}

						} else {
							this.loginButtonType = 0;	
						}


					} else {
						// 需要获取手机号按钮 
						this.loginButtonType = 0;
						return;
					}
				}
			})
		},

当loginButtonType=0的时候,按钮是多个获取手机号的按钮!

获取手机号:

系统获取手机号,手机号和后台存储的数据比对。

参考:uniapp开发微信小程序:用户手机号授权获取全流程详解与实战示例

 先测试一下:

首先获取token:

用微信提供的功能获取code:

<template>
  <view>
    <!-- 其他界面元素 -->
    <button open-type="getPhoneNumber" @getphonenumber="onGetPhoneNumber">授权并获取手机号</button>
  </view>
</template>
getPhoneNumber (e) {
  console.log(e.detail.code)  // 动态令牌
   console.log(e.detail.errMsg) // 回调信息(成功失败都会返回)
   console.log(e.detail.errno)  // 错误码(失败时返回)
 }

getPhoneNumber 返回的 code 与 wx.login 返回的 code 作用是不一样的,不能混用。 

有了ACCESS_TOKEN与code: 就可以调用wx api进一步测试:

POST https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=ACCESS_TOKEN

这一步返回就能获取手机号了。

获取到手机号后,我们要和后台记录比对。

先看一下其中的:

    /**
     * 处理医生信息
     *
     * @param phoneNumber 手机号
     * @param userInfo    用户信息
     * @param openId      openId
     * @param unionId     unionId
     * @return {@link Doctors}
     */
    private Doctors handleDoctorInfo(String phoneNumber, WxMaUserInfo userInfo, String openId, String unionId) {
        // 验证输入参数
        if (StrUtil.isAllBlank(openId, phoneNumber)) {
            throw new BizException("用户参数错误!");
        }

        // 构建查询条件
        LambdaQueryWrapper<Doctors> queryWrapper = new QueryWrapper<Doctors>().lambda()
                .eq(Doctors::getDelFlag, 1)   // 未删除
                .eq(Doctors::getAuditStatus, 1)  // 已审核
                .orderByAsc(Doctors::getCreateTime);

        // 根据手机号或openid查询医生信息
        String encodedPhone = StrUtil.isNotBlank(phoneNumber) ? PwdUtil.base64Encode(phoneNumber) : null;
        if (encodedPhone != null) {
            queryWrapper.eq(Doctors::getPhone, encodedPhone).or().eq(Doctors::getOpenId, openId);
        } else {
            queryWrapper.eq(Doctors::getOpenId, openId);
        }

        List<Doctors> doctorsList = iDoctorsService.list(queryWrapper);
        if (CollUtil.isNotEmpty(doctorsList)) {
            Doctors doctors = doctorsList.get(0);

            // 更新医生信息
            //doctors.setUserName(userInfo.getNickName());
            //doctors.setPhone(StrUtil.isNotBlank(encodedPhone) ? phoneNumber : doctors.getPhone());
            //doctors.setOpenId(openId);

            // 从Redis获取头像URL或使用用户信息中的头像URL
            if (StrUtil.isNotBlank(doctors.getOpenId())) {
                Object imgUrl = redisTemplate.opsForValue().get(RedisUserKeyConstants.getUserImgUrlKey(doctors.getOpenId()));
                doctors.setImgUrl(imgUrl != null ? imgUrl.toString() : userInfo.getAvatarUrl());
            } else {
                doctors.setImgUrl(userInfo.getAvatarUrl());
            }

            // 设置unionId(如果提供)
            if (StrUtil.isNotBlank(unionId)) {
                doctors.setUnionId(unionId);
            }

            // 更新数据库
            doctors.setUpdateTime(new Date());
            iDoctorsService.updateById(doctors);

            // 缓存医生信息
            if(StrUtil.isNotBlank(phoneNumber)){
                redisTemplate.opsForValue().set(RedisUserKeyConstants.getPhoneKey(phoneNumber), doctors);
            }
            //if open`id is not null, then cache the openId and doctors


            if(StrUtil.isNotBlank(openId)) {
                redisTemplate.opsForValue().set(RedisUserKeyConstants.getOpenIdKey(doctors.getOpenId()), doctors);
            }


//            redisTemplate.opsForValue().set(
//                    StrUtil.isNotBlank(phoneNumber) ? RedisUserKeyConstants.getPhoneKey(phoneNumber) : RedisUserKeyConstants.getOpenIdKey(doctors.getOpenId()),
//                    doctors
//            );

            // 转换并返回医生信息(如果需要)
            // doctors = doctorsConvertMapper.toExchangeDeptCodeOne(doctors); // 根据需要启用或注释掉

            return doctors;
        }
        return null;
    }

        这段代码的作用,就是生成类似SELECT * FROM doctors WHERE (phone = ? OR open_id = ?) AND del_flag = 1 AND audit_status = 1 ORDER BY create_time ASC; 的语句,查询医生信息,然后刷新缓存。

能够查询到医生信息,用户就可以登录了.

现在我们已经实现用户第一次登录 又没有退出的啥情况 下次登录的时候 不用取得手机号

如果用户手机号是正确的,且通过了审核,再检查open_id,如果不存在 说明是第一次登录,那要保存open_id。

如果用户手机号是正确的,且通过了审核,再检查open_id,如果存在 说明该用户曾经登录过系统,值得信赖,可以直接登录。注意,手机号与绑定微信号是一致的,没问题,如果手机号与微信号不一致,则可能存在问题!(我们系统逻辑上控制了)

退出登录 :

用户第一次通过手机号登录后,为记录用户是否登录过, 同时 应该修改数据库用户表中的flag标志。当用户点击退出按钮的时候   要修改这个flag。

还有一个问题,原则上,我们不容许不用本机号码登录的情况。这个如何判断?还要查一下

费用:

ps:手机号快速验证组件 | 微信开放文档 

顺便记个其他的东西,年级大,记性不好,常忘事~

ps:启动服务的命令:

#!/bin/bash

# 设置 Spring Boot 项目的 JAR 文件名
SPRING_BOOT_JAR="business-chat.jar"

# 检查该项目是否已经在运行中
RUNNING_PID=$(ps -ef | grep $SPRING_BOOT_JAR | grep -v grep | awk '{print $2}')

if [ -z "$RUNNING_PID" ]; then
  # 如果项目未在运行中,则启动它
  nohup java -jar $SPRING_BOOT_JAR > business-chat.log 2>&1 &
  echo "Spring Boot 项目已启动"
else
  echo "Spring Boot 项目已在运行中,进程ID为 $RUNNING_PID"
  kill -9 $RUNNING_PID
  echo "business-chat 项目已停止"
  sleep 1
  nohup java -jar $SPRING_BOOT_JAR > business-chat.log 2>&1 &
  echo "restart success"
  tail -f business-chat.log
fi
[root@VM-0-14-centos ~]# find / -name nginx.conf
/usr/local/nginx/nginx-1.24.0/conf/nginx.conf
/usr/local/nginx/conf/nginx.conf
[root@VM-0-14-centos ~]# cd /usr/locla
-bash: cd: /usr/locla: No such file or directory
[root@VM-0-14-centos ~]# cd /usr/local
[root@VM-0-14-centos local]# ls -l
total 56
drwxr-xr-x.  2 root root 4096 Nov 26  2023 bin
drwxr-xr-x.  2 root root 4096 Apr 11  2018 etc
drwxr-xr-x.  2 root root 4096 Apr 11  2018 games
drwxr-xr-x.  2 root root 4096 Apr 11  2018 include
drwxr-xr-x.  2 root root 4096 Apr 11  2018 lib
drwxr-xr-x.  2 root root 4096 Apr 11  2018 lib64
drwxr-xr-x.  2 root root 4096 Apr 11  2018 libexec
drwxr-xr-x  13 root root 4096 Nov 26  2023 nginx
drwxr-xr-x  17 root root 4096 Nov 24  2023 qcloud
drwxrwxr-x   7 root root 4096 Nov 16 15:26 redis-6.0.0
drwxr-xr-x.  2 root root 4096 Apr 11  2018 sbin
drwxr-xr-x.  5 root root 4096 Mar  7  2019 share
drwxr-xr-x.  2 root root 4096 Apr 11  2018 src
drwxr-xr-x   3 root root 4096 Nov 26  2023 yulang
[root@VM-0-14-centos local]# cd nginx
[root@VM-0-14-centos nginx]# ls -l
total 44
drwxr-xr-x  2 root   root  4096 Nov 26  2023 cert
drwx------  2 nobody root  4096 Oct 11 11:48 client_body_temp
drwxr-xr-x  2 root   root  4096 May  2  2024 conf
drwx------  2 nobody root  4096 Nov 26  2023 fastcgi_temp
drwxr-xr-x  9 root   root  4096 Mar 15  2024 html
drwxr-xr-x  2 root   root  4096 Oct 16 13:37 logs
drwxr-xr-x  9   1001 mysql 4096 Nov 26  2023 nginx-1.24.0
drwx------ 12 nobody root  4096 Nov 30  2023 proxy_temp
drwxr-xr-x  2 root   root  4096 Nov 26  2023 sbin
drwx------  2 nobody root  4096 Nov 26  2023 scgi_temp
drwx------  2 nobody root  4096 Nov 26  2023 uwsgi_temp
[root@VM-0-14-centos nginx]# cd sbin
[root@VM-0-14-centos sbin]# ls -l
total 8240
-rwxr-xr-x 1 root root 8434768 Nov 26  2023 nginx
[root@VM-0-14-centos sbin]# ./nginx
[root@VM-0-14-centos sbin]#

   

 

更多推荐