首页 > 编程语言 >JAVA实现判断小程序用户是否关注公众号

JAVA实现判断小程序用户是否关注公众号

时间:2024-08-10 11:53:56浏览次数:10  
标签:openid JAVA String accessToken 用户 private 公众 import weixinUserInfoVo

本文主要描述了判断小程序用户是否关注公众号的逻辑实现及部分代码

首先阐述一下大致流程:

1、在将小程序和公众号绑定至同一个微信开发平台下;

2、后端拉取公众号已关注用户列表,并获取其中每一个用户的unionID, 建立已关注用户表;

3、后端可做定时任务更新该表;

4、用户在小程序中登录注册时后端用code拿到用户的unionID并保存;

5、前端请求查询时,后端根据发起请求用户的unionID查表,判断该用户是否已关注;

 一、数据库表和Mapper层

这里简单给出了建表语句和实体类, 具体mapper/service层可自行实现

CREATE TABLE `public_user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `open_id` varchar(50) DEFAULT NULL COMMENT 'openId',
  `union_id` varchar(50) DEFAULT NULL COMMENT 'union',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1DEFAULT CHARSET=utf8mb4;

@Table(name = "public_user")
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Data
public class PublicUser implements Serializable {
    @Id
    @GeneratedValue(
            strategy = GenerationType.IDENTITY
    )
    private Long id;
    @Column(name = "open_id")
    private String openId;
    @Column(name = "union_id")
    private String unionId;

}

public interface PublicUserMapper {

}

二、微信公众号对接接口相关逻辑代码

        1.三个基础接收对象类
 

@Data
public class WeixinUserInfoVo {
  private String openid;
  private String unionid;
  /**
   * 该值为0值 则没有openId和unionId
   */
  private Integer subscribe;

  private Integer errcode;
}


@Data
public class WeixinUserListVo {
  private Integer errcode;
  @ApiModelProperty("关注该公众账号的总用户数")
  private Integer total;
  @ApiModelProperty("拉取的OPENID个数,最大值为10000")
  private Integer count;
  @ApiModelProperty("列表数据,OPENID的列表")
  private WxOpenidInfo data;
  @ApiModelProperty("拉取列表的最后一个用户的OPENID")
  private String next_openid;
}

@Data
public class WxOpenidInfo {
  private List<String> openid;
}

        2.调用微信接口相关

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Strings;
import com.mzlion.easyokhttp.HttpClient;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import tk.mybatis.mapper.entity.Example;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;


@Slf4j
@Service
public class WeixinPublicService {

    @Autowired
    private RedisTemplate redisTemplate;

    //公众号appId
    @Value("${weixin.mp.account:xxxxxxxx}")
    private String miniappAppId;
    //公众号secret
    @Value("${weixin.mp.secret:xxxxxxxxxxxxxxxxx}")
    private String miniappSecret;
    @Resource
    private PublicUserMapper publicUserMapper;
    public static final String ACCESS_TOKEN="weixin:access_token";


    /**
     * 判断小程序用户是否否关注的主要方法-根据unionId来查询用户观众公众号信息
     * @param unionId
     * @return
     */
    public WeixinUserInfoVo selectWeixinPublicUserInfoByUnionId(String unionId) {
        //现查询数据库-根据unionid获取到openid-逻辑可自行实现
        PublicUser dbPublicUser = publicUserMapper.selectPublicUserByUnionId(unionId);
        WeixinUserInfoVo weixinUserInfoVo = null;
        if (Objects.isNull(dbPublicUser)) {
            //查询数据库-逻辑可自行实现
            List<PublicUser> existPublicUsers = publicUserMapper.selectPublicUserList();
            // 查询所有 openid
            HashSet<String> openidSet = getUserOpenIdList();
            if (!CollectionUtil.isEmpty(openidSet)) {
                if (!openidSet.isEmpty()) {
                    // 差集
                    for (PublicUser user : existPublicUsers) {
                        openidSet.remove(user.getOpenId());
                    }
                }
            }
            // 更新 未入库的 公众号信息
            String openid = null;
            RestTemplate restTemplate = new RestTemplate();
            List<PublicUser> publicUserList = new ArrayList<>();
            for (String id : openidSet) {
                // 根据openid查询unionId
                String requestUrl = "https://api.weixin.qq.com/cgi-bin/user/info?access_token="
                        + getAccessToken()
                        + "&openid=" + id + "&lang=zh_CN";
                weixinUserInfoVo = restTemplate.getForObject(requestUrl, WeixinUserInfoVo.class);
                if (!ObjectUtil.isNull(weixinUserInfoVo) && ObjectUtil.isNull(weixinUserInfoVo.getErrcode())) {
                    if (!StrUtil.isEmpty(weixinUserInfoVo.getUnionid())) {
                        publicUserList.add(PublicUser.builder().openId(weixinUserInfoVo.getOpenid()).unionId(weixinUserInfoVo.getUnionid()).build());
                        if (unionId.equals(weixinUserInfoVo.getUnionid())) {
                            openid = id;
                        }
                    }
                }
            }
            if (!CollectionUtil.isEmpty(publicUserList)) {
                this.publicUserMapper.insertList(publicUserList);
            }
        }else {
            RestTemplate restTemplate = new RestTemplate();
            String requestUrl = "https://api.weixin.qq.com/cgi-bin/user/info?access_token="
                    + getAccessToken()
                    + "&openid=" + dbPublicUsers.get(0).getOpenId() + "&lang=zh_CN";
            weixinUserInfoVo = restTemplate.getForObject(requestUrl, WeixinUserInfoVo.class);
        }
        return weixinUserInfoVo;
    }

    /**
     * 获取请求token
     * @return
     */
    private String getAccessToken() {
        String accessToken = (String) this.redisTemplate.opsForValue().get(ACCESS_TOKEN);
        if (StrUtil.isEmpty(accessToken)) {
            String result = HttpClient.get(
                            "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET".replace(
                                    "APPID", this.miniappAppId).replace("APPSECRET", this.miniappSecret))
                    .asString();
            log.info("getAccessToken---result===>"+result);
            if (!Strings.isNullOrEmpty(result)) {
                Integer expiresIn = null;
                JSONObject jsonObject = JSON.parseObject(result);
                if (ObjectUtil.isNotNull(jsonObject)) {
                    expiresIn = (Integer) jsonObject.get("expires_in");
                    accessToken = (String) jsonObject.get("access_token");
                }
                log.info("getAccessToken---accessToken===>"+accessToken);
                if (StrUtil.isNotEmpty(accessToken) && ObjectUtil.isNotNull(expiresIn)) {
                    this.redisTemplate.opsForValue().set(ACCESS_TOKEN, accessToken, expiresIn - 20);
                }
            }
        }
        return accessToken;
    }


    /**
     * 初始化所有公众号用户数据
     */
    public void init() {
        //查询数据库-逻辑可自行实现
        List<PublicUser> dbPublicUsers = publicUserMapper.selectPublicUserList();
        List<String> existOpenIds = new ArrayList<>();
        if (dbPublicUsers != null && !dbPublicUsers.isEmpty()) {
            existOpenIds.addAll(dbPublicUsers.stream().map(PublicUser::getOpenId)
                    .collect(Collectors.toList()));
        }
        // 查询所有 openid
        HashSet<String> openidSet = getUserOpenIdList();
        //去除已经存在的
        openidSet.removeIf(existOpenIds::contains);
        // 更新 未入库的 公众号信息
        RestTemplate restTemplate = new RestTemplate();
        List<PublicUser> publicUserList = new ArrayList<>();
        for (String openId : openidSet) {
            // 根据openid查询unionId
            String requestUrl = "https://api.weixin.qq.com/cgi-bin/user/info?access_token="
                    + getAccessToken()
                    + "&openid=" + openId + "&lang=zh_CN";
            WeixinUserInfoVo weixinUserInfoVo = restTemplate.getForObject(requestUrl, WeixinUserInfoVo.class);
            if (!ObjectUtil.isNull(weixinUserInfoVo) && ObjectUtil.isNull(weixinUserInfoVo.getErrcode())) {
                if (!StrUtil.isEmpty(weixinUserInfoVo.getUnionid())) {
                    publicUserList.add(PublicUser.builder().openId(weixinUserInfoVo.getOpenid()).unionId(weixinUserInfoVo.getUnionid()).build());
                }
            }
            //一次性插入一百条 防止服务断掉 导致全没拉下来
            if (!CollectionUtil.isEmpty(publicUserList) && publicUserList.size() == 100) {
                this.publicUserMapper.insertList(publicUserList);
                publicUserList.clear();
            }
        }
        if (!CollectionUtil.isEmpty(publicUserList)) {
            this.publicUserMapper.insertList(publicUserList);
        }
    }


    /**
     * 获取公众号关注用户列表的openid
     * @return
     */
    public HashSet<String> getUserOpenIdList() {
        //获取最新的access_token
        String accessToken = getAccessToken();
        log.info("accessToken===>"+new String(accessToken));
        RestTemplate restTemplate = new RestTemplate();
        WeixinUserListVo openIdList = null;
        HashSet<String> openidSet = new HashSet<String>();
        synchronized (this) {
            try {
                //循环获取用户openid列表--一次获取10000
                String nextOpenid = null;
                do {
                    //微信公众号获取用户列表信息接口地址
                    String requestUrl = null;
                    if (StringUtil.isBlank(nextOpenid)) {
                        requestUrl = "https://api.weixin.qq.com/cgi-bin/user/get?access_token="
                                + accessToken;
                    } else {
                        requestUrl = "https://api.weixin.qq.com/cgi-bin/user/get?access_token="
                                + accessToken + "&next_openid=" + nextOpenid;
                    }
                    openIdList = restTemplate.getForObject(requestUrl, WeixinUserListVo.class);
                    if (openIdList != null && Objects.nonNull(openIdList.getData())) {
                        //获取用户关注列表对象
                        WxOpenidInfo data = openIdList.getData();
                        //获取当前循环的openid--10000条
                        openidSet.addAll(data.getOpenid());
                        //拉取列表的最后一个用户的OPENID
                        nextOpenid = openIdList.getNext_openid();
                    }
                } while (Objects.nonNull(openIdList.getData()));
            } catch (Exception e) {
                log.debug("获取用户列表失败:{}", openIdList);
                return null;
            }
        }
        return openidSet;
    }


}

3.判断是否关注的逻辑

根据调用selectWeixinPublicUserInfoByUnionId的返回判断是否关注

        ①已关注(subscribe字段判断 1:已关注) 

 

标签:openid,JAVA,String,accessToken,用户,private,公众,import,weixinUserInfoVo
From: https://blog.csdn.net/qq_40083897/article/details/141087983

相关文章

  • 从零开始的JAVAday36~day42
    定义方法语句格式:publicstaticvoid方法名(){}这是没有参数没有返回值的方法。格式:publicstaticviod方法名(参数1,参数2,参数3){}这是有参数没有返回值的方法。格式:publicstatic返回值类型方法名(参数1,参数2,参数3){return返回值}这是有参数有返回值的方法。......
  • bat cmd javaw -jar
    rem使用者应根据自身平台编码自行转换防止乱码例如win使用gbk编码@echooffchcp65001remjar平级目录setAppName=medicare-down.jarsetpathx=%CD%setpathxx=%pathx%\Java\jdk1.8.0_101\::echo%pathxx%set"JAVA_HOME=%pathxx%::set"CLASSPATH=%JAVA_HOME%\lib\dt.jar;......
  • 学生Java学习路程-6
    ok,到了一周一次的总结时刻,我大致会有下面几个方面的论述:1.这周学习了Java的那些东西2.这周遇到了什么苦难3.未来是否需要改进方法等几个方面阐述我的学习路程。复习面向对象数组数组的三种初始化方法:默认,静态,动态引用类型Man放入数组中的测试代码数组的拷贝使用规范使......
  • Java网络编程——Request Response 对象
    Response-网页上一章我们学习了Java中使用Okhttp3库请求网页或调用API的知识。使用一条语句执行调用请求,并取得返回结果字符串:call.execute().body().string()execute()方法是真正执行发送请求,前面的一系列代码是做前置准备。这段代码获得服务器返回内容的......
  • JAVA常见异常
    Java.io.NullPointerExceptionnull空的,不存在的NullPointer空指针空指针异常,该异常出现在我们操作某个对象的属性或方法时,如果该对象是null时引发。Stringstr=null;str.length();//空指针异常上述代码中引用类型变量str的值为null,此时不能通过它调用字符串的方法......
  • [网络] 关键类及源码分析:java.net包
    0序1java.net包概述2关键类及源码分析2.1java.net.InetAddresspublicstaticvoidmain(String[]args)throwsUnknownHostException{ //1.获取本机的InetAddress对象 InetAddresslocalHost=InetAddress.getLocalHost(); System.out.println(localHost);//LAPT......
  • [JVM] 应用诊断工具之java命令
    0序本章对java命令的使用、最佳实践进行全方位的总结。1java命令1.0场景:查看版本方法1#java-versionjavaversion"1.8.0_261"Java(TM)SERuntimeEnvironment(build1.8.0_261-b12)JavaHotSpot(TM)64-BitServerVM(build25.261-b12,mixedmode)方法2......
  • 前端黑科技:使用 JavaScript 实现网页扫码功能
    在数字化时代,二维码已经渗透到我们生活的方方面面。从移动支付到产品溯源,二维码凭借其便捷性和高效性,成为了信息传递的重要载体。而随着前端技术的不断发展,我们甚至可以使用JavaScript在网页端实现二维码扫描功能,为用户提供更加便捷的操作体验。本文将带您深入了解如何使用Jav......
  • 接收用户的输入
    staticvoidMain(string[]args){Console.WriteLine("美女,你喜欢吃什么水果?");stringstrFruit=Console.ReadLine();//接收用户输入的字符串;Console.WriteLine("这么巧吗,我也喜欢吃"+strFruit+";");Con......
  • javacpp使用入门
    代码仓库预构建软件的仓库TheJavaCPPPresetsmodulescontainJavaconfigurationandinterfaceclassesforwidelyusedC/C++libraries.项目wikiAguideonhowtorunJavaCPPtogetherwithMaven2or3.修改项目的pom.xml,增加如下配置:<!--https://mvnrepos......