本文从零开始到获取用户openid并存到数据库
运用到SpringBoot+mybatis+RestTemplate
准备条件
需要一个公众号
需要简单配置一下,在左方菜单最下方----开发–基本配置—白名单这里填写电脑现自身的ip(本项目本地跑)
查看微信公众平台开发文档
https://developers.weixin.qq.com/doc/offiaccount/Getting_Started/Overview.html
获取access_token
access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token。开发者需要进行妥善保存。access_token的存储至少要保留512个字符空间。access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效。
接口调用请求说明
https请求方式: GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET`
官方的接口调式工具测试,走一遍获取用户列表流程
失败请查阅文档,了解详情
获取用户列表
公众号可通过本接口来获取帐号的关注者列表,关注者列表由一串OpenID(加密后的微信号,每个用户对每个公众号的OpenID是唯一的)组成。一次拉取调用最多拉取10000个关注者的OpenID,可以通过多次拉取的方式来满足需求。例如:
公众账号A拥有23000个关注的人,想通过拉取关注接口获取所有关注的人,那么分别请求url如下:https://api.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN 返回结果:
{
“total”:23000,
“count”:10000,
“data”:{"
openid":[
“OPENID1”,
“OPENID2”,
…,
“OPENID10000”
]
},
“next_openid”:“OPENID10000”
}https://api.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&next_openid=NEXT_OPENID1返回结果:
{
“total”:23000,
“count”:10000,
“data”:{
“openid”:[
“OPENID10001”,
“OPENID10002”,
…,
“OPENID20000”
]
},
“next_openid”:“OPENID20000”
}https://api.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&next_openid=NEXT_OPENID2返回结果(关注者列表已返回完时,返回next_openid为空):
{
“total”:23000,
“count”:3000,
“data”:{"
“openid”:[
“OPENID20001”,
“OPENID20002”,
…,
“OPENID23000”
]
},
“next_openid”:“OPENID23000”
}
接口调用请求说明
http请求方式: GET(请使用https协议)
https://api.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&next_openid=NEXT_OPENID
失败请查阅文档,了解详情
以上都成功,我们开始写代码
所有注释都已经在代码中标识,就不做多阐述,逻辑很简单,直接贴上详细代码
项目目录结构和数据库设计
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>template</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>template</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.5</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
application.yml -----填写自己的数据库信息
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: ?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=UTC&useSSL=false
username:
password:
mybatis:
mapper-locations: classpath*:mapper/*Mapper.xml
server:
port: 8888
Constast—更换自己相应的数据
package com.example.template.common;
import lombok.Data;
/**
* 微信参数
*/
@Data
public class Constast {
//开发者ID
public static final String AppId="wx1###########bfe";
//开发者密码
public static final String AppSecret="49######################667";
//接口凭证access_token
private String access_token;
//凭证时效
private int expires_in;
//我的openid
public static final String HuHaoAppId="oP######################wM";
//模板template_id
public static final String TemplateId="88d######################4ULcs";
//违章查询路径
public static final String PagePath="pages/###########index?routeKey=PC01_RE############################################tagid=104.233.5";
//违章查询的AppId
public static final String XcxAppId="wx0###########f5b2";
}
WeixinUserListVo
package com.example.template.vo;
import lombok.Data;
@Data
public class WeixinUserListVo {
private Integer total;//关注该公众账号的总用户数
private Integer count;//拉取的OPENID个数,最大值为10000
private WxOpenidInfo data;//列表数据,OPENID的列表
private String next_openid;//拉取列表的最后一个用户的OPENID
private int errcode;//错误编码
private String errmsg = "ok";//错误提示
}
WxOpenidInfo
package com.example.template.vo;
import lombok.Data;
import java.util.List;
@Data
public class WxOpenidInfo {
private List<String> openid;
}
TemplateController
package com.example.template.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.example.template.common.Constast;
import com.example.template.service.TemplateService;
import com.example.template.vo.WeixinUserListVo;
import com.example.template.vo.WxOpenidInfo;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/a")
public class TemplateController {
private static final Logger logger = LoggerFactory.getLogger(TemplateController.class);
@Autowired
private TemplateService templateService;
//获取access_token,access_token是公众号的全局唯一接口调用凭据
public static Constast getAccessToken() {
RestTemplate restTemplate = new RestTemplate();
Map<String, String> map = new HashMap<>();
map.put("AppId", Constast.AppId);
map.put("AppSecret", Constast.AppSecret);
//调用微信公众号接口
ResponseEntity<String> forEntity = restTemplate.getForEntity("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={AppId}&secret={AppSecret}", String.class, map);
String body = forEntity.getBody();
JSONObject jsonObject = JSON.parseObject(body);
String access_token = jsonObject.getString("access_token");
String expires_in = jsonObject.getString("expires_in");//时效--7200s
Constast constast = new Constast();
constast.setAccess_token(access_token);
return constast;
}
//获取用户列表的openid
@RequestMapping("/a")
public WeixinUserListVo getUserOpenIdList() {
//获取最新的access_token
String accessToken = TemplateController.getAccessToken().getAccess_token();
RestTemplate restTemplate = new RestTemplate();
WeixinUserListVo openIdList = null;
synchronized (this) {
try {
//循环获取用户openid列表--一次获取10000
String nextOpenid = null;
do {
//微信公众号获取用户列表信息接口地址
String requestUrl = null;
if (StringUtils.isBlank(nextOpenid)) {
requestUrl = new StringBuffer().append("https://api.weixin.qq.com/cgi-bin/user/get?access_token=").append(accessToken).toString();
} else {
requestUrl = new StringBuffer().append("https://api.weixin.qq.com/cgi-bin/user/get?access_token=")
.append(accessToken).append("&next_openid=").append(nextOpenid).toString();
}
openIdList = restTemplate.getForObject(requestUrl, WeixinUserListVo.class);
if (openIdList != null && openIdList.getErrcode() == 0) {
//获取用户关注列表对象
WxOpenidInfo data = openIdList.getData();
if (data != null) {
//获取当前循环的openid--10000条
List<String> openid = data.getOpenid();
if (openid != null && openid.size() > 0) {
for (int i = 0; i < openid.size(); i += 100) {
int toIndex = 100;
if (i + 100 > openid.size()) {
// 注意下标问题
toIndex = openid.size() - i;
}
//循环100次,每次拿到openid列表中的集合下标;例如:(0,100),(100,200)
List<String> sendList = openid.subList(i, i + toIndex);
//每次insert---100条
int num = templateService.insertForeach(sendList);
}
}
}
//拉取列表的最后一个用户的OPENID
nextOpenid = openIdList.getNext_openid();
System.out.println(nextOpenid);
} else {
openIdList.setErrcode(40000);
openIdList.setErrmsg("获取关注用户列表失败");
return openIdList;
}
} while (openIdList.getCount() > 0);
} catch (Exception e) {
openIdList.setErrcode(40000);
openIdList.setErrmsg("获取用户列表失败");
return openIdList;
}
}
return openIdList;
}
}
TemplateServiceImpl
package com.example.template.service.impl;
import com.example.template.mapper.TemplateMapper;
import com.example.template.service.TemplateService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@Transactional
public class TemplateServiceImpl implements TemplateService {
@Autowired
private TemplateMapper templateMapper;
@Override
public int insertForeach(List list) {
int i = templateMapper.insertForeach(list);
return i;
}
}
TemplateService
package com.example.template.service;
import java.util.List;
public interface TemplateService {
int insertForeach(List list);
}
TemplateMapper
package com.example.template.mapper;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface TemplateMapper {
int insertForeach(List list);
}
TemplateMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.example.template.mapper.TemplateMapper">
<insert id="insertForeach" parameterType="java.util.List" useGeneratedKeys="false">
insert into template (openid)
values
<foreach collection="list" item="item" index="index" separator=",">
(#{item})
</foreach>
</insert>
</mapper>
启动项目:http://localhost:8888/a/a
模板消息:微信公众号完成模板消息-----详细教程