本文主要描述了判断小程序用户是否关注公众号的逻辑实现及部分代码
首先阐述一下大致流程:
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