1. 程式人生 > >第七篇:微信粉絲一鍵同步工具類

第七篇:微信粉絲一鍵同步工具類

1、前言

  在公眾號開發的過程中,一般都需要獲取粉絲資料,針對單個粉絲,我們可以通過openid獲取其粉絲資訊; 但不排除這種業務,比如目前開發的公眾號已經在使用中,,當前的框架或者功能已經不能夠滿足使用者的需求、需要重新開發,那麼這個時候你開發的新的微信專案將要接入到之前老的微信公眾號上去,把之前老的公眾號給取代掉,所以在接入的時候,你就需要將原先公眾號上的所有粉絲同步到新的專案中來管理,粉絲可能上達10萬都有可能,這個時候對單個粉絲進行同步就不滿足需求了,所以這個時候就需要一鍵同步,將所有微信公眾平臺中的粉絲給同步下來,上大10萬條或者數萬條的時候,同步過程中可能就需要一段時間,那麼這個工具類就是為這麼一個業務場景準備的(當然在對粉絲的管理中,也可以單個同步、或者多個一起同步,都可以實現)。

2、微信框架

 開源框架使用 :weixin-java-mp,   
 微信框架 參考:https://github.com/Wechat-Group/weixin-java-tools

3、微信粉絲一鍵同步工具類

package com.thinkgem.jeesite.modules.wechat.commonUtil;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.WxMpUserService;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import me.chanjar.weixin.mp.bean.result.WxMpUserList;
import net.sf.json.JSONArray;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import com.google.common.collect.Lists;
import com.thinkgem.jeesite.modules.wechat.inter.SyncInterface;
import com.thinkgem.jeesite.modules.wechat.service.WXSyncFansService;

/**
 * <pre>
 * 同步粉絲工具類
 * @author cao_wencao  
 * @date 2018年9月17日 下午11:27:06
 * </pre>
 */
@Slf4j
@Component
public class WeChatSyncFansUtils {
    @Autowired
    private WxMpService wxMpService;
    @Autowired
    private WXSyncFansService wXSyncFansService;

    private SyncInterface syncInterface;

    /**
     * 每次同步多少條資料,預設每次500條
     */
    private int syncCount = 500;

    @SuppressWarnings("unused")
    private WeChatSyncFansUtils() {

    }

    /**
     * <pre>
     * 使用者自定義每次同步多少條
     * </pre>
     */
    public WeChatSyncFansUtils setSyncCount(int syncCount) {
        this.syncCount = syncCount;
        return this;
    }

    /**
     * <pre>
     * 初始化工具類,需傳入 wxMpService 和 同步業務類
     * 同步業務類
     * @param wxMpService
     * @param syncInterface
     * @author cao_wencao
     * </pre>
     */
    public WeChatSyncFansUtils(WxMpService wxMpService, SyncInterface syncInterface) {
        this.wxMpService = wxMpService;
        this.syncInterface = syncInterface;
    }

    /**
     * <pre>
     * 同步入口
     * @author cao_wencao
     * @throws Exception
     */
    public void synchronize() throws WxErrorException {
        WxMpUserService userService = wxMpService.getUserService();
        boolean flag = true;
        // nextOpenid 為可選,第一個拉取的OPENID,null為從頭開始拉取
        String nextOpenId = null;
        // 獲取當前庫中所有的使用者openid
        List<String> existOpenIds = wXSyncFansService.getExistOpenIds() == null ? new ArrayList<>() : wXSyncFansService.getExistOpenIds();
        int i = 1;
        // 迴圈方式
        while (flag) {
            // 從微信拉取微信粉絲
            WxMpUserList wxMpUserList = userService.userList(nextOpenId);
            if (nextOpenId == null) {
                log.debug("開始同步粉絲,需同步粉絲總數:{}", wxMpUserList.getCount());
            }
            // 獲取h使用者openId列表(每次最大值為10000)
            List<String> openidsList = wxMpUserList.getOpenids();
            log.debug("openidsList :{}", JSONArray.fromObject(openidsList));
            // 獲取粉絲資訊列表
            List<WxMpUser> wxMpUsersInfoList = this.getWxMpUserList(openidsList);
            if (wxMpUserList.getCount() == 0 && !ObjectUtils.isEmpty(nextOpenId)) {
                wxMpUsersInfoList.add(userService.userInfo(nextOpenId));
            }
            log.info("開始第{}次同步,本次需同步:{}條", i, wxMpUsersInfoList.size());
            i++;
            // 同步業務
            this.batchSynchronize(wxMpUsersInfoList, existOpenIds);
            // 獲取下次獲取開始的openId
            nextOpenId = wxMpUserList.getNextOpenid();
            // 對比nextOpenId,如果相同,就是沒有下一個了
            if (ObjectUtils.isEmpty(nextOpenId)) {
                // 沒有下一個了
                flag = false;
                log.debug("同步結束");
            }
        }
        // 取消關注的粉絲需要修改狀態位
        List<String> notSubscribeList = this.unSubscribeOpenIds();
        if(null != notSubscribeList || !ObjectUtils.isEmpty(notSubscribeList)){
            wXSyncFansService.unSubscribeFans(notSubscribeList);
        }
        log.info("有" + notSubscribeList.size() + "個粉絲被取消關注了");
    }

    /**
     * <pre>
     * 粉絲列表分批同步
     * 微信粉絲資料(每次最高1w人)
     * @author cao_wencao
     * @param wxMpUsers
     * </pre>
     */
    private void batchSynchronize(List<WxMpUser> wxMpUsersInfoList, List<String> existOpenIds) {
        // 獲取庫中已經存在的粉絲
        List<WxMpUser> oldWxMpUsers = this.getOldWxMpUsers(wxMpUsersInfoList, existOpenIds);
        // 庫中已經存在的粉絲,做update操作
        wXSyncFansService.oldWxMpUser(oldWxMpUsers);
        // 分批次同步新粉絲
        this.synchronizeNewWxMpUsersBatches(wxMpUsersInfoList, syncCount);
    }

    /**
     * <pre>
     * 分批次同步所有不存在的粉絲,如:服務停止情況下關注的粉絲,是沒有新增入庫的
     * @param wxMpUsers 微信粉絲列表             
     * @param maxCount 每批最多人數,預設500            
     * @return
     * @author cao_wencao
     * </pre>
     */
    private void synchronizeNewWxMpUsersBatches(List<WxMpUser> wxMpUsers, int maxCount) {
        List<List<WxMpUser>> newFollowerList = new ArrayList<>();
        // 總數
        int count = wxMpUsers.size();
        int a = count % maxCount > 0 ? count / maxCount + 1 : count / maxCount;
        for (int i = 0; i < a; i++) {
            if (i + 1 < a) {
                List<WxMpUser> users = wxMpUsers.subList(i * maxCount, (i + 1) * maxCount);
                newFollowerList.add(users);
            }
            else {
                List<WxMpUser> users = wxMpUsers.subList(i * maxCount, count);
                newFollowerList.add(users);
            }
        }
        for (List<WxMpUser> mpUsers : newFollowerList) {
            // 庫中不存在的粉絲,需要insert 由於量可能太大,每次最多insert 500條資料
            wXSyncFansService.newWxMpUser(mpUsers);
        }
    }

    /**
     * <pre>
     * 獲取庫中已有的粉絲
     * @param wxMpUsers 全部粉絲列表
     * @param existOpenIds 庫中openId列表
     * @return 已有的粉絲列表
     * @author cao_wencao
     * </pre>
     */
    private List<WxMpUser> getOldWxMpUsers(List<WxMpUser> wxMpUsersInfoList, List<String> existOpenIds) {
        List<String> excludeOpenIds = new ArrayList<>();
        List<WxMpUser> oldWxMpUsers = new ArrayList<>();
        for (WxMpUser wxMpUser : wxMpUsersInfoList) {
            if (existOpenIds.contains(wxMpUser.getOpenId())) {
                oldWxMpUsers.add(wxMpUser);
                excludeOpenIds.add(wxMpUser.getOpenId());
            }
        }
        // 排除存在的openId列表
        existOpenIds.removeAll(excludeOpenIds);
        // 排除存在的粉絲
        wxMpUsersInfoList.removeAll(oldWxMpUsers);
        return oldWxMpUsers;
    }

    /**
     * <pre>
     * 分批次獲取微信粉絲資訊 每批100條
     * @param openids
     * @return
     * @throws WxErrorException
     * @author cao_wencao
     * </pre>
     */
    private List<WxMpUser> getWxMpUserList(List<String> openidsList) throws WxErrorException {
        // 粉絲openid數量
        int count = openidsList.size();
        if (count <= 0) {
            return new ArrayList<>();
        }
        List<WxMpUser> list = Lists.newArrayList();
        List<WxMpUser> followersInfoList = Lists.newArrayList();
        int a = count % 100 > 0 ? count / 100 + 1 : count / 100;
        for (int i = 0; i < a; i++) {
            if (i + 1 < a) {
                log.debug("i:{},from:{},to:{}", i, i * 100, (i + 1) * 100);
                followersInfoList = this.wxMpService.getUserService().userInfoList(openidsList.subList(i * 100, (i + 1) * 100));
                if (null != followersInfoList && !followersInfoList.isEmpty()) {
                    list.addAll(followersInfoList);
                }
            }
            else {
                log.debug("i:{},from:{},to:{}", i, i * 100, count - i * 100);
                followersInfoList = wxMpService.getUserService().userInfoList(openidsList.subList(i * 100, count - 1));
                if (null != followersInfoList && !followersInfoList.isEmpty()) {
                    list.addAll(followersInfoList);
                }
            }
        }
        return list;
    }

    /**
     * 取出取消關注的粉絲openid
     * 
     * @author cao_wencao
     * @param existOpenIds
     * @return
     * @throws WxErrorException
     */
    private List<String> unSubscribeOpenIds() {
        // 微信平臺取消關注的openid,需要在資料庫更新關注狀態
        List<String> notSubscribeList = Lists.newArrayList();
        String openid = null;
        // 獲取粉絲資訊
        List<WxMpUser> followersInfoList = null;
        try {
            List<String> existOpenIds = wXSyncFansService.getExistOpenIds() == null ? new ArrayList<>() : wXSyncFansService.getExistOpenIds();
            if (null != existOpenIds && !ObjectUtils.isEmpty(existOpenIds)) {
                followersInfoList = wxMpService.getUserService().userInfoList(existOpenIds);
                if (null != followersInfoList && !ObjectUtils.isEmpty(followersInfoList)) {
                    for (WxMpUser wxMpUser : followersInfoList) {
                        // 取消關注的粉絲,更新關注狀態
                        if (WxConstants.FansStatus.NOT_SUBSCRIBE.equals(wxMpUser.getSubscribe())) {
                            openid = wxMpUser.getOpenId();
                            notSubscribeList.add(openid);
                        }
                    }
                }
            }
        }
        catch (WxErrorException e) {
            log.error("獲取需要修改取消關注狀態位的粉絲異常", e.getMessage());
            e.printStackTrace();
        }
        return notSubscribeList;
    }

    // public static void main(String[] args) {
    // String json =
    // "{\"user_info_list\":[{\"username\":\"test\"},{\"pwd\":\"test2\"}]}";
    // JsonObject object = new Gson().fromJson(json, JsonObject.class);//這個解析不出來
    // JsonElement element = new
    // JsonParser().parse(json).getAsJsonObject().getAsJsonArray("user_info_list");
    // System.out.println(element);

    // }
}