使用SpringBoot同步微信公众号的粉丝详情

时间:2024-02-26 07:58:01

使用SpringBoot同步微信公众号的粉丝详情,由于粉丝数量不多,一次拉取足矣,数量很多的话要改造为多线程模式。

项目结构如下:

 

POM添加依赖:

        <!-- json工具类 -->
        <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.9</version>
        </dependency>

        <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>

        <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
View Code

 

常量类:

RequestMethod:

package com.gaopeng.weixin.wexinuser.constants;

/**
 *
 * @description 请求方式枚举类
 *
 * @author gaopeng
 *
 */
public enum RequestMethod {

    GET, POST

}
RequestMethod

WeixinConfigs:

package com.gaopeng.weixin.wexinuser.constants;

/**
 *
 * @description 设置APP_ID和APP_SECRET
 *
 * @author gaopeng
 * 
 */
public class WeixinConfigs {

    // 公众号的APP_ID
    public static final String APP_ID = "wxcedbccc419db0dca";
    // 公众号的APP_SECRET
    public static final String APP_SECRET = "fb9f57e0a3cbcc15844e07f7b83c079b";

}
WeixinConfigs

 

MpWeChatUserMapper:

package com.gaopeng.weixin.wexinuser.dao;


import com.gaopeng.weixin.wexinuser.pojo.MpWeChatUser;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

/**
 * @author gaopeng
 *
 */
@Mapper
public interface MpWeChatUserMapper {

    public int insertUser(MpWeChatUser user) throws Exception;

    MpWeChatUser findMpWeChatUserByOpenId(@Param("openid") String openid) throws Exception;

}
MpWeChatUserMapper

 

实体类:

MpWeChatUser:

package com.gaopeng.weixin.wexinuser.pojo;

/**
 * 
 * @description 微信用户基本信息(UnionID机制)
 *
 *  接口调用请求说明
 *    http请求方式: GET
 *    https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
 * 
 * @author gaopeng
 *
 *
 */

public class MpWeChatUser {

    // 用户的标识,对当前公众号唯一
    private String openId;

    // 关注状态(1是关注,0是未关注),未关注时获取不到其余信息
    private int subscribe;

    // 用户昵称
    private String nickname;

    // 用户的性别,值为1时是男性,值为2时是女性,值为0时是未知
    private int sex;

    // 用户的唯一标识
    private String city;

    // 用户的唯一标识
    private String country;

    // 用户的唯一标识
    private String province;

    // 用户的语言,简体中文为zh_CN
    private String language;

    // 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像)
    // 用户没有头像时该项为空。若用户更换头像,原有头像URL将失效。
    private String headimgurl;

    // 用户关注时间,为时间戳。如果用户曾多次关注,则取最后关注时间
    private String subscribeTime;

    // 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。
    private String unionId;

    // 公众号运营者对粉丝的备注,公众号运营者可在微信公众平台用户管理界面对粉丝添加备注
    private String remark;

    // 用户所在的分组ID(兼容旧的用户分组接口)
    private String groupId;

    // 用户被打上的标签ID列表
    private String tagidList;

    // 返回用户关注的渠道来源,ADD_SCENE_SEARCH 公众号搜索,ADD_SCENE_ACCOUNT_MIGRATION
    // 公众号迁移,ADD_SCENE_PROFILE_CARD 名片分享,ADD_SCENE_QR_CODE 扫描二维码,ADD_SCENE_PROFILE_
    // LINK 图文页内名称点击,ADD_SCENE_PROFILE_ITEM 图文页右上角菜单,ADD_SCENE_PAID
    // 支付后关注,ADD_SCENE_OTHERS 其他
    private String subscribeScene;

    // 二维码扫码场景(开发者自定义)
    private String qrScene;

    // 二维码扫码场景描述(开发者自定义)
    private String qrSceneStr;

    public String getOpenId() {
        return openId;
    }

    public void setOpenId(String openId) {
        this.openId = openId;
    }

    public int getSubscribe() {
        return subscribe;
    }

    public void setSubscribe(int subscribe) {
        this.subscribe = subscribe;
    }

    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }

    public int getSex() {
        return sex;
    }

    public void setSex(int sex) {
        this.sex = sex;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

    public String getProvince() {
        return province;
    }

    public void setProvince(String province) {
        this.province = province;
    }

    public String getLanguage() {
        return language;
    }

    public void setLanguage(String language) {
        this.language = language;
    }

    public String getHeadimgurl() {
        return headimgurl;
    }

    public void setHeadimgurl(String headimgurl) {
        this.headimgurl = headimgurl;
    }

    public String getSubscribeTime() {
        return subscribeTime;
    }

    public void setSubscribeTime(String subscribeTime) {
        this.subscribeTime = subscribeTime;
    }

    public String getUnionId() {
        return unionId;
    }

    public void setUnionId(String unionId) {
        this.unionId = unionId;
    }

    public String getRemark() {
        return remark;
    }

    public void setRemark(String remark) {
        this.remark = remark;
    }

    public String getGroupId() {
        return groupId;
    }

    public void setGroupId(String groupId) {
        this.groupId = groupId;
    }

    public String getTagidList() {
        return tagidList;
    }

    public void setTagidList(String tagidList) {
        this.tagidList = tagidList;
    }

    public String getSubscribeScene() {
        return subscribeScene;
    }

    public void setSubscribeScene(String subscribeScene) {
        this.subscribeScene = subscribeScene;
    }

    public String getQrScene() {
        return qrScene;
    }

    public void setQrScene(String qrScene) {
        this.qrScene = qrScene;
    }

    public String getQrSceneStr() {
        return qrSceneStr;
    }

    public void setQrSceneStr(String qrSceneStr) {
        this.qrSceneStr = qrSceneStr;
    }

    @Override
    public String toString() {
        return "MpWeChatUser{" +
                "openId=\'" + openId + \'\\'\' +
                ", subscribe=" + subscribe +
                ", nickname=\'" + nickname + \'\\'\' +
                ", sex=" + sex +
                ", city=\'" + city + \'\\'\' +
                ", country=\'" + country + \'\\'\' +
                ", province=\'" + province + \'\\'\' +
                ", language=\'" + language + \'\\'\' +
                ", headimgurl=\'" + headimgurl + \'\\'\' +
                ", subscribeTime=\'" + subscribeTime + \'\\'\' +
                ", unionId=\'" + unionId + \'\\'\' +
                ", remark=\'" + remark + \'\\'\' +
                ", groupId=\'" + groupId + \'\\'\' +
                ", tagidList=\'" + tagidList + \'\\'\' +
                ", subscribeScene=\'" + subscribeScene + \'\\'\' +
                ", qrScene=\'" + qrScene + \'\\'\' +
                ", qrSceneStr=\'" + qrSceneStr + \'\\'\' +
                \'}\';
    }

}
MpWeChatUser

MpWeChatUserList:

package com.gaopeng.weixin.wexinuser.pojo;

import java.util.List;

/**
 * 
 * @description 关注用户列表
 *
 * http请求方式: GET(请使用https协议)
 * https://api.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&next_openid=NEXT_OPENID
 * 
 * @author gaopeng
 *
 */
public class MpWeChatUserList {

    // 关注该公众账号的总用户数
    private int total;

    // 拉取的OPENID个数,最大值为10000
    private int count;

    // 列表数据,OPENID的列表
    private List<String> openIdList;

    // 拉取列表的最后一个用户的OPENID
    private String nextOpenId;

    public int getTotal() {
        return total;
    }

    public void setTotal(int total) {
        this.total = total;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public List<String> getOpenIdList() {
        return openIdList;
    }

    public void setOpenIdList(List<String> openIdList) {
        this.openIdList = openIdList;
    }

    public String getNextOpenId() {
        return nextOpenId;
    }

    public void setNextOpenId(String nextOpenId) {
        this.nextOpenId = nextOpenId;
    }

}
MpWeChatUserList

Token:

package com.gaopeng.weixin.wexinuser.pojo;

/**
 * @author gaopeng
 *
 */
public class Token {
    // 接口访问凭证
    private String accessToken;

    // 凭证有效期,单位:秒
    private int expiresIn;

    public String getAccessToken() {
        return accessToken;
    }

    public void setAccessToken(String accessToken) {
        this.accessToken = accessToken;
    }

    public int getExpiresIn() {
        return expiresIn;
    }

    public void setExpiresIn(int expiresIn) {
        this.expiresIn = expiresIn;
    }

}
Token

 

工具类:

AdvancedUtil:

package com.gaopeng.weixin.wexinuser.utils;


import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.gaopeng.weixin.wexinuser.constants.RequestMethod;
import com.gaopeng.weixin.wexinuser.pojo.MpWeChatUser;
import com.gaopeng.weixin.wexinuser.pojo.MpWeChatUserList;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.List;


/**
 * @author gaopeng
 * 
 */
public class AdvancedUtil {

    private static Logger log = LogManager.getLogger(AdvancedUtil.class);


    /**
     * 获取用户基本信息(UnionID机制)
     *
     * 接口调用请求说明
     * http请求方式: GET
     * https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
     *
     * @param accessToken
     *            接口访问凭证
     * @param openId
     *            普通用户的标识,对当前公众号唯一
     * @return WeixinUserInfo
     */
    public static MpWeChatUser getUserInfo(String accessToken, String openId) {
        MpWeChatUser mpWeChatUser = null;

        // 拼接请求地址
        String requestUrl = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";

        requestUrl = requestUrl.replace("ACCESS_TOKEN", accessToken);
        requestUrl = requestUrl.replace("OPENID", openId);

        // 获取网页授权获取用户信息
        JSONObject jsonObject = CommonUtil.httpsRequest(requestUrl, RequestMethod.GET, null);

        if (null != jsonObject) {
            try {
                mpWeChatUser = new MpWeChatUser();
                // 用户的唯一标识
                mpWeChatUser.setOpenId(jsonObject.getString("openid"));
                // 关注状态(1是关注,0是未关注),未关注时获取不到其余信息
                mpWeChatUser.setSubscribe(jsonObject.getIntValue("subscribe"));
                // 用户关注时间
                mpWeChatUser.setSubscribeTime(jsonObject.getString("subscribe_time"));
                // 昵称
                mpWeChatUser.setNickname(EmojiFilter.filterEmoji(jsonObject.getString("nickname"),"?"));
                // 用户性别(1是男性,2是女性,0是未知)
                mpWeChatUser.setSex(jsonObject.getIntValue("sex"));
                // 用户所在国家
                mpWeChatUser.setCountry(jsonObject.getString("country"));
                // 用户所在省份
                mpWeChatUser.setProvince(jsonObject.getString("province"));
                // 用户所在城市
                mpWeChatUser.setCity(jsonObject.getString("city"));
                // 用户的语言,简体中文为zh_CN
                mpWeChatUser.setLanguage(jsonObject.getString("language"));
                // 用户头像
                mpWeChatUser.setHeadimgurl(jsonObject.getString("headimgurl"));
                //只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段
                mpWeChatUser.setUnionId(jsonObject.getString("unionid"));
                //公众号运营者对粉丝的备注,公众号运营者可在微信公众平台用户管理界面对粉丝添加备注
                mpWeChatUser.setRemark(jsonObject.getString("remark"));
                //返回用户关注的渠道来源
                mpWeChatUser.setSubscribeScene(jsonObject.getString("subscribe_scene"));
                //二维码扫码场景
                mpWeChatUser.setQrScene(jsonObject.getString("qr_scene"));
                //二维码扫码场景描述
                mpWeChatUser.setQrSceneStr(jsonObject.getString("qr_scene_str"));

            } catch (Exception e) {
                if (0 == mpWeChatUser.getSubscribe()) {
                    log.error("用户{}已取消关注", mpWeChatUser.getOpenId());
                } else {
                    int errorCode = jsonObject.getIntValue("errcode");
                    String errorMsg = jsonObject.getString("errmsg");
                    log.error("获取用户信息失败 errcode:{} errmsg:{}", errorCode, errorMsg);
                }
            }
        }

        return mpWeChatUser;
    }

    /**
     * 获取用户列表
     *
     * http请求方式: GET(请使用https协议)
     * https://api.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&next_openid=NEXT_OPENID
     * 
     * @param accessToken
     *            调用接口凭证
     * @param nextOpenId
     *            第一个拉取的OPENID,不填默认从头开始拉取
     * @return
     */
    public static MpWeChatUserList getUserList(String accessToken, String nextOpenId) {
        MpWeChatUserList mpWeChatUserList = null;

        if (StringUtils.isBlank(nextOpenId)) {
            nextOpenId = "";
        }
        // 拼接请求地址
        String requestUrl = "https://api.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&next_openid=NEXT_OPENID";

        requestUrl = requestUrl.replace("ACCESS_TOKEN", accessToken);
        requestUrl = requestUrl.replace("NEXT_OPENID", nextOpenId);

        // 获取用户列表
        JSONObject jsonObject = CommonUtil.httpsRequest(requestUrl, RequestMethod.GET, null);

        if (null != jsonObject) {
            try {
                int count = jsonObject.getIntValue("count");
                if (count > 0) {
                    mpWeChatUserList = new MpWeChatUserList();
                    mpWeChatUserList.setTotal(jsonObject.getIntValue("total"));
                    mpWeChatUserList.setCount(jsonObject.getIntValue("count"));
                    mpWeChatUserList.setNextOpenId(jsonObject.getString("next_openid"));

                    JSONObject dataObject =  jsonObject.getJSONObject("data");
                    JSONArray openidArray = dataObject.getJSONArray("openid");
                    List<String> openIdList = openidArray.toJavaList(String.class);

                    mpWeChatUserList.setOpenIdList(openIdList);

                }
            } catch (Exception e) {
                mpWeChatUserList = null;
                int errorCode = jsonObject.getIntValue("errcode");
                String errorMsg = jsonObject.getString("errmsg");
                log.error("获取用户列表失败 errcode:{} errmsg:{}", errorCode, errorMsg);
            }
        }

        return mpWeChatUserList;
    }
    
}
AdvancedUtil

CommonUtil:

package com.gaopeng.weixin.wexinuser.utils;

import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.gaopeng.weixin.wexinuser.constants.RequestMethod;
import com.gaopeng.weixin.wexinuser.constants.WeixinConfigs;
import com.gaopeng.weixin.wexinuser.pojo.Token;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.URL;


/**
 * @author gaopeng
 * 
 */
public class CommonUtil {

    private static Logger log = LogManager.getLogger(CommonUtil.class);

    public static JSONObject httpsRequest(String requestUrl, RequestMethod requestMethod, String outputStr) {
        JSONObject jsonObject = null;

        try {
            // 创建SSL对象,并使用我们指定的信任管理器初始化
            TrustManager[] tm = { new MyX509TrustManager() };
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            sslContext.init(null, tm, new java.security.SecureRandom());

            // 从上述SSLContext对象中得到SSLSocketFactory对象
            SSLSocketFactory ssf = sslContext.getSocketFactory();
            URL url = new URL(requestUrl);

            HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
            conn.setSSLSocketFactory(ssf);
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            // 设置请求方式(GET/POST)
            conn.setRequestMethod(requestMethod.toString());

            // 当outputStr不为null时,向输出流写数据
            if (null != outputStr) {
                OutputStream outputStream = conn.getOutputStream();
                // 注意编码格式
                outputStream.write(outputStr.getBytes("UTF-8"));
                outputStream.close();
            }

            // 从输入流读取返回内容
            InputStream inputStream = conn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

            // 读取响应内容
            StringBuffer buffer = new StringBuffer();
            String str = null;

            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }

            // 关闭释放资源
            bufferedReader.close();
            inputStreamReader.close();
            inputStream.close();
            inputStream = null;
            conn.disconnect();

            jsonObject = JSONObject.parseObject(buffer.toString());

        } catch (ConnectException ce) {
            log.error("连接超时:{}", ce);
        } catch (Exception e) {
            log.error("https请求异常:{}", e);
        }

        return jsonObject;
    }

    public static String httpsRequestAsString(String requestUrl, RequestMethod requestMethod, String outputStr) {
        String result = "";

        try {
            // 创建SSL对象,并使用我们指定的信任管理器初始化
            TrustManager[] tm = { new MyX509TrustManager() };
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            sslContext.init(null, tm, new java.security.SecureRandom());

            // 从上述SSLContext对象中得到SSLSocketFactory对象
            SSLSocketFactory ssf = sslContext.getSocketFactory();
            URL url = new URL(requestUrl);
            HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
            conn.setSSLSocketFactory(ssf);
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            // 设置请求方式(GET/POST)
            conn.setRequestMethod(requestMethod.toString());

            // 当outputStr不为null时,向输出流写数据
            if (null != outputStr) {
                OutputStream outputStream = conn.getOutputStream();
                // 注意编码格式
                outputStream.write(outputStr.getBytes("UTF-8"));
                outputStream.close();
            }

            // 从输入流读取返回内容
            InputStream inputStream = conn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

            // 读取响应内容
            StringBuffer buffer = new StringBuffer();
            String str = null;

            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }

            // 关闭释放资源
            bufferedReader.close();
            inputStreamReader.close();
            inputStream.close();
            inputStream = null;
            conn.disconnect();

            result = buffer.toString();

        } catch (ConnectException ce) {
            log.error("连接超时:{}", ce);
        } catch (Exception e) {
            log.error("https请求异常:{}", e);
        }

        return result;
    }

    /**
     * 获取接口访问凭证
     *
     * @return
     */
    public static Token getToken() {

        Token token = null;
        String requestUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
        requestUrl = requestUrl.replace("APPID", WeixinConfigs.APP_ID);
        requestUrl = requestUrl.replace("APPSECRET", WeixinConfigs.APP_SECRET);

        // 发起GET请求获取凭证
        JSONObject jsonObject = httpsRequest(requestUrl, RequestMethod.GET, null);

        if (null != jsonObject) {
            try {
                token = new Token();
                token.setAccessToken(jsonObject.getString("access_token"));
                token.setExpiresIn(jsonObject.getIntValue("expires_in"));
            } catch (JSONException e) {
                token = null;
                // 获取token失败
                log.error("获取token失败errcode:{} errmsg:{}", jsonObject.getIntValue("errcode"),
                        jsonObject.getString("errmsg"));
            }

        }
        return token;
    }


}
CommonUtil

EmojiFilter:

package com.gaopeng.weixin.wexinuser.utils;
import org.apache.commons.lang3.StringUtils;

/**
 * @author gaopeng
 * @description 表情符号替换
 */

public class EmojiFilter {

    /**
     * 检测是否有emoji字符
     *
     * @param source
     * @return 一旦含有就抛出
     */
    public static boolean containsEmoji(String source) {
        if (StringUtils.isBlank(source)) {
            return false;
        }
        int len = source.length();
        for (int i = 0; i < len; i++) {
            char codePoint = source.charAt(i);
            if (!isNotEmojiCharacter(codePoint)) {
                //判断到了这里表明,确认有表情字符
                return true;
            }
        }
        return false;
    }

    /**
     * 判断是否为非Emoji字符
     *
     * @param codePoint 比较的单个字符
     * @return
     */
    private static boolean isNotEmojiCharacter(char codePoint) {
        return (codePoint == 0x0) ||
                (codePoint == 0x9) ||
                (codePoint == 0xA) ||
                (codePoint == 0xD) ||
                ((codePoint >= 0x20) && (codePoint <= 0xD7FF)) ||
                ((codePoint >= 0xE000) && (codePoint <= 0xFFFD)) ||
                ((codePoint >= 0x10000) && (codePoint <= 0x10FFFF));
    }

    /**
     * 过滤emoji 或者 其他非文字类型的字符
     *
     * @param source
     * @param replaceStr 替换的字符,为null的话只是简单的过滤
     * @return
     */
    public static String filterEmoji(String source, String replaceStr) {
        if (StringUtils.isBlank(source)) {
            return source;
        }
        if (!containsEmoji(source)) {
            return source;//如果不包含,直接返回
        }
        StringBuilder buf = new StringBuilder(source.length());
        int len = source.length();
        for (int i = 0; i < len; i++) {
            char codePoint = source.charAt(i);
            if (isNotEmojiCharacter(codePoint)) {
                buf.append(codePoint);
            }else if (replaceStr!= null){
                buf.append(replaceStr);
            }
        }

        return buf.toString().trim();
    }
}
EmojiFilter

MyX509TrustManager:

package com.gaopeng.weixin.wexinuser.utils;

import javax.net.ssl.X509TrustManager;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

/**
 * @author gaopeng
 * 
 */
public class MyX509TrustManager implements X509TrustManager {

    // 检查客户端证书
    @Override
    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {

    }

    // 检查服务器端证书
    @Override
    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {

    }

    // 返回受信任的X509证书数组
    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return null;
    }

}
MyX509TrustManager

 

配置文件:

MpWeChatUser.map.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.gaopeng.weixin.wexinuser.dao.MpWeChatUserMapper">

    <resultMap id="BaseResultMap" type="com.gaopeng.weixin.wexinuser.pojo.MpWeChatUser">
        <result property="openId"                column="openid"             jdbcType="VARCHAR"/>
        <result property="subscribe"             column="subscribe"          jdbcType="INTEGER"/>
        <result property="nickname"             column="nickname"          jdbcType="VARCHAR"/>
        <result property="sex"                     column="sex"             jdbcType="INTEGER"/>
        <result property="city"                 column="city"              jdbcType="VARCHAR"/>
        <result property="country"                column="country"         jdbcType="VARCHAR"/>
        <result property="province"              column="province"           jdbcType="VARCHAR"/>
        <result property="language"                column="language"         jdbcType="VARCHAR"/>
        <result property="headimgurl"                column="headimgurl"      jdbcType="VARCHAR"/>
        <result property="subscribeTime"        column="subscribe_time"     jdbcType="VARCHAR"/>
        <result property="unionId"                  column="unionid"           jdbcType="VARCHAR"/>
        <result property="remark"                column="remark"             jdbcType="VARCHAR"/>
        <result property="groupId"                   column="groupid"         jdbcType="VARCHAR"/>
        <result property="tagidList"             column="tagid_list"      jdbcType="VARCHAR"/>
        <result property="subscribeScene"        column="subscribe_scene" jdbcType="VARCHAR"/>
        <result property="qrScene"             column="qr_scene"          jdbcType="VARCHAR"/>
        <result property="qrSceneStr"         column="qr_scene_str"      jdbcType="VARCHAR"/>
    </resultMap>


    <sql id="Base_Column_List" >
        openid            ,
        subscribe         ,
        nickname         ,
        sex                ,
        city             ,
        country            ,
        province         ,
        language         ,
        headimgurl         ,
        subscribe_time  ,
        unionid         ,
        remark            ,
        groupid            ,
        tagid_list         ,
        subscribe_scene    ,
        qr_scene         ,
        qr_scene_str
    </sql>



    <insert id="insertUser" parameterType="com.gaopeng.weixin.wexinuser.pojo.MpWeChatUser">
        INSERT INTO mp_wechat_user
        (<include refid="Base_Column_List"/>)
        VALUES
        (
        #{openId} ,#{subscribe} ,#{nickname} ,#{sex} ,#{city} ,
        #{country} ,#{province} ,#{language} ,#{headimgurl} ,#{subscribeTime} ,
        #{unionId} ,#{remark} ,#{groupId} ,#{tagidList} ,#{subscribeScene},
        #{qrScene} ,#{qrSceneStr}
        )
    </insert>

    <select id="findMpWeChatUserByOpenId" resultMap="BaseResultMap" parameterType="java.lang.String" >
        select
        <include refid="Base_Column_List" />
        from mp_wechat_user
        where openid = #{openid,jdbcType=VARCHAR}
    </select>



</mapper>
MpWeChatUser.map.xml

mp_weixin_users.sql:

CREATE TABLE mp_wechat_user (
    openid    varchar(100) NOT NULL COMMENT \'用户的标识,对当前公众号唯一\',
    subscribe smallint(1) COMMENT \'用户是否订阅该公众号标识,值为0时,代表此用户没有关注该公众号,拉取不到其余信息\',
    nickname varchar(255) NOT NULL COMMENT \'用户的昵称\',
    sex    smallint(1) COMMENT \'用户的性别,值为1时是男性,值为2时是女性,值为0时是未知\',
    city varchar(255) COMMENT \'用户所在城市\',
    country    varchar(100) COMMENT \'用户所在国家\',
    province varchar(100) COMMENT \'用户所在省份\',
    language varchar(100) COMMENT \'用户的语言,简体中文为zh_CN\',
    headimgurl varchar(255) COMMENT \'用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空。若用户更换头像,原有头像URL将失效\',
    subscribe_time varchar(255) COMMENT \'用户关注时间,为时间戳。如果用户曾多次关注,则取最后关注时间\',
    unionid varchar(100) COMMENT \'只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段\',
    remark    varchar(255) COMMENT \'公众号运营者对粉丝的备注,公众号运营者可在微信公众平台用户管理界面对粉丝添加备注\',
    groupid    varchar(255) COMMENT \'用户所在的分组ID(兼容旧的用户分组接口)\',
    tagid_list varchar(255) COMMENT \'用户被打上的标签ID列表\',
    subscribe_scene    varchar(255) COMMENT \'返回用户关注的渠道来源,ADD_SCENE_SEARCH 公众号搜索,ADD_SCENE_ACCOUNT_MIGRATION 公众号迁移,ADD_SCENE_PROFILE_CARD 名片分享,ADD_SCENE_QR_CODE 扫描二维码,ADD_SCENE_PROFILE_ LINK 图文页内名称点击,ADD_SCENE_PROFILE_ITEM 图文页右上角菜单,ADD_SCENE_PAID 支付后关注,ADD_SCENE_OTHERS 其他\',
    qr_scene varchar(255) COMMENT \'二维码扫码场景(开发者自定义)\',
    qr_scene_str varchar(255) COMMENT \'二维码扫码场景描述(开发者自定义)\',
    PRIMARY KEY (`openid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=\'微信公众号粉丝表\';
mp_weixin_users.sql

application.properties:

spring.datasource.driverClassName = com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://192.168.100.200:3306/jk0828?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=round&allowMultiQueries=true
spring.datasource.username=jinkong
spring.datasource.password=jinkong

mybatis.type-aliases-package=com.gaopeng.weixin.wexinuser.pojo
mybatis.mapper-locations=classpath:mapper/*.xml
application.properties

 

测试类:

WexinuserApplicationTests:

package com.gaopeng.weixin.wexinuser;

import com.gaopeng.weixin.wexinuser.dao.MpWeChatUserMapper;
import com.gaopeng.weixin.wexinuser.pojo.MpWeChatUser;
import com.gaopeng.weixin.wexinuser.pojo.MpWeChatUserList;
import com.gaopeng.weixin.wexinuser.utils.AdvancedUtil;
import com.gaopeng.weixin.wexinuser.utils.CommonUtil;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;

/**
 * @author gaopeng
 * @description 测试
 * @date:2019/11/28
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class WexinuserApplicationTests {

    @Resource
    private MpWeChatUserMapper userMapper;

    @Test
    public void testFindByOpenId() throws Exception {
      //  MpWeChatUser user = userMapper.findMpWeChatUserByOpenId("1");
      //  System.out.println("第一条记录:"+user.toString());

        // 获取接口访问凭证
        String accessToken = CommonUtil.getToken().getAccessToken();


        MpWeChatUserList weChatUserList = AdvancedUtil.getUserList(accessToken, null);

        System.out.println("总关注用户数=" + weChatUserList.getTotal());
        System.out.println("本次获取用户数=" + weChatUserList.getCount());
        System.out.println("OpenID列表=" + weChatUserList.getOpenIdList().toString());
        System.out.println("next_openid=" + weChatUserList.getNextOpenId());

        MpWeChatUser user = null;
        int count = 0;
        for(String openid : weChatUserList.getOpenIdList()){
            user = AdvancedUtil.getUserInfo(accessToken,openid);
            int result = userMapper.insertUser(user);
            count += result;
            System.out.println("count="+count);
        }
    }
}
WexinuserApplicationTests