微信公眾號統一管理平台之微信粉絲定時同步任務


在開發一套微信公眾號統一管理平台,因需要微信粉絲同步功能,結合網上看到的各種方法以及微信公眾號提供的接口,使用FluentScheduler定時框架在Asp.Net MVC中實現了多公眾號的粉絲定時同步到本地庫的功能,實現步驟分享:

一、本地數據庫的創建,因設計多公眾號的管理,分析微信接口中的用戶實體信息,創建表如下:

表結構截圖

/*
Navicat MySQL Data Transfer

Source Server         : 127.0.0.1
Source Server Version : 50627
Source Host           : 127.0.0.1:3306
Source Database       : fensishenghuo

Target Server Type    : MYSQL
Target Server Version : 50627
File Encoding         : 65001

Date: 2018-04-20 11:16:26
*/

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for `wechat_user`
-- ----------------------------
DROP TABLE IF EXISTS `wechat_user`;
CREATE TABLE `wechat_user` (
  `id` varchar(40) NOT NULL DEFAULT '' COMMENT '主鍵',
  `subscribe` smallint(1) DEFAULT NULL COMMENT '用戶是否訂閱該公眾號標識,值為0時,代表此用戶沒有關注該公眾號,拉取不到其余信息',
  `openid` varchar(40) DEFAULT NULL COMMENT '用戶的標識,對當前公眾號唯一',
  `nickname` varchar(30) DEFAULT '' COMMENT '用戶的昵稱',
  `sex` smallint(1) DEFAULT NULL COMMENT '用戶的性別,值為1時是男性,值為2時是女性,值為0時是未知',
  `language` varchar(20) DEFAULT NULL COMMENT '用戶的語言,簡體中文為zh_CN',
  `city` varchar(50) DEFAULT NULL COMMENT '用戶所在城市',
  `province` varchar(50) DEFAULT NULL COMMENT '用戶所在省份',
  `country` varchar(50) DEFAULT NULL COMMENT '用戶所在國家',
  `head_img_url` varchar(200) DEFAULT NULL COMMENT '用戶頭像,最后一個數值代表正方形頭像大小(有0、46、64、96、132數值可選,0代表640*640正方形頭像),用戶沒有頭像時該項為空。若用戶更換頭像,原有頭像URL將失效。',
  `subscribe_time` bigint(20) DEFAULT NULL COMMENT '用戶關注時間,為時間戳。如果用戶曾多次關注,則取最后關注時間',
  `union_id` varchar(40) DEFAULT NULL COMMENT '只有在用戶將公眾號綁定到微信開放平台帳號后,才會出現該字段',
  `remark` varchar(200) DEFAULT NULL COMMENT '公眾號運營者對粉絲的備注,公眾號運營者可在微信公眾平台用戶管理界面對粉絲添加備注',
  `group_id` int(6) DEFAULT NULL COMMENT '用戶所在的分組ID(兼容舊的用戶分組接口)',
  `tagid_list` varchar(20) DEFAULT NULL COMMENT '用戶標簽',
  `wechat_account_id` varchar(40) DEFAULT NULL COMMENT '該粉絲是屬於哪一個公眾號下的粉絲',
  `company_id` varchar(40) DEFAULT NULL COMMENT '公司主鍵,該微信用戶屬於哪一個網點的粉絲',
  `company_name` varchar(50) DEFAULT NULL COMMENT '公司名稱,該微信用戶屬於哪一個網點的粉絲',
  `user_id` varchar(255) DEFAULT NULL COMMENT '員工主鍵,該微信用戶屬於哪一個員工的粉絲',
  `user_name` varchar(50) DEFAULT NULL COMMENT '員工用戶名稱,該微信用戶屬於哪一個用戶的粉絲',
  `modified_on` date DEFAULT NULL COMMENT '更新時間',
  `modified_user_id` varchar(40) DEFAULT NULL COMMENT '修改人主鍵',
  `modified_by` varchar(40) DEFAULT NULL COMMENT '修改人',
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_wechat_account_id_openid` (`wechat_account_id`,`openid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='微信公眾號關注的用戶信息';

-- ----------------------------
-- Records of wechat_user
-- ----------------------------

MySQL數據庫粉絲表的創建語句,因nickname存在表情字符,表結構需要做一下調整,將nickname的字符集改為utf8mb4_unicode_ci,當然可以將全部字符集改為utf8mb4_unicode_ci

CREATE TABLE `wechat_user` (
    `id` VARCHAR(40) NOT NULL DEFAULT '' COMMENT '主鍵',
    `subscribe` SMALLINT(1) NULL DEFAULT NULL COMMENT '用戶是否訂閱該公眾號標識,值為0時,代表此用戶沒有關注該公眾號,拉取不到其余信息',
    `openid` VARCHAR(40) NULL DEFAULT NULL COMMENT '用戶的標識,對當前公眾號唯一',
    `nickname` VARCHAR(30) NULL DEFAULT '' COMMENT '用戶的昵稱' COLLATE 'utf8mb4_unicode_ci',
    `sex` SMALLINT(1) NULL DEFAULT NULL COMMENT '用戶的性別,值為1時是男性,值為2時是女性,值為0時是未知',
    `language` VARCHAR(20) NULL DEFAULT NULL COMMENT '用戶的語言,簡體中文為zh_CN',
    `city` VARCHAR(50) NULL DEFAULT NULL COMMENT '用戶所在城市',
    `province` VARCHAR(50) NULL DEFAULT NULL COMMENT '用戶所在省份',
    `country` VARCHAR(50) NULL DEFAULT NULL COMMENT '用戶所在國家',
    `head_img_url` VARCHAR(200) NULL DEFAULT NULL COMMENT '用戶頭像,最后一個數值代表正方形頭像大小(有0、46、64、96、132數值可選,0代表640*640正方形頭像),用戶沒有頭像時該項為空。若用戶更換頭像,原有頭像URL將失效。',
    `subscribe_time` BIGINT(20) NULL DEFAULT NULL COMMENT '用戶關注時間,為時間戳。如果用戶曾多次關注,則取最后關注時間',
    `union_id` VARCHAR(40) NULL DEFAULT NULL COMMENT '只有在用戶將公眾號綁定到微信開放平台帳號后,才會出現該字段',
    `remark` VARCHAR(200) NULL DEFAULT NULL COMMENT '公眾號運營者對粉絲的備注,公眾號運營者可在微信公眾平台用戶管理界面對粉絲添加備注',
    `group_id` INT(6) NULL DEFAULT NULL COMMENT '用戶所在的分組ID(兼容舊的用戶分組接口)',
    `tagid_list` VARCHAR(20) NULL DEFAULT NULL COMMENT '用戶標簽',
    `wechat_account_id` VARCHAR(40) NULL DEFAULT NULL COMMENT '該粉絲是屬於哪一個公眾號下的粉絲',
    `company_id` VARCHAR(40) NULL DEFAULT NULL COMMENT '公司主鍵,該微信用戶屬於哪一個網點的粉絲',
    `company_name` VARCHAR(50) NULL DEFAULT NULL COMMENT '公司名稱,該微信用戶屬於哪一個網點的粉絲',
    `user_id` VARCHAR(255) NULL DEFAULT NULL COMMENT '員工主鍵,該微信用戶屬於哪一個員工的粉絲',
    `user_name` VARCHAR(50) NULL DEFAULT NULL COMMENT '員工用戶名稱,該微信用戶屬於哪一個用戶的粉絲',
    `modified_on` DATE NULL DEFAULT NULL COMMENT '更新時間',
    `modified_user_id` VARCHAR(40) NULL DEFAULT NULL COMMENT '修改人主鍵',
    `modified_by` VARCHAR(40) NULL DEFAULT NULL COMMENT '修改人',
    PRIMARY KEY (`id`),
    UNIQUE INDEX `idx_wechat_account_id_openid` (`wechat_account_id`, `openid`)
)
COMMENT='微信公眾號關注的用戶信息'
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;

對應mysql.data.dll驅動下載:https://files.cnblogs.com/files/hnsongbiao/MySql.Data.zip

數據庫連接字符串:

 <add key="UserCenterDbConnection" value="host=127.0.0.1;uid=root;password=123456;database=shenghuo;pooling=true;charset=utf8mb4;Min Pool Size=5;Max Pool Size=50;" />

二、定時任務計划實現,微信接口的調用使用了Senparc的SDK。

//-----------------------------------------------------------------------
// <copyright file="WechatUserScheduler" company="FenSiShengHuo, Ltd.">
//     Copyright (c) 2018 , All rights reserved.
// </copyright>
//-----------------------------------------------------------------------

using System;
using System.Collections.Generic;
using FluentScheduler;

namespace DotNet.WeChat.MVC.Assist
{
    using DotNet.MVC.Infrastructure.Utilities;
    using DotNet.WeChat.Business;
    using DotNet.WeChat.Model;
    using Senparc.Weixin.MP.AdvancedAPIs;
    using Senparc.Weixin.MP.AdvancedAPIs.User;
    using Utilities;

    /// <summary>
    /// WechatUserScheduler
    /// 
    /// 微信粉絲定時同步任務
    /// 
    /// 修改紀錄
    /// 
    /// 2018-04-18 版本:1.0 SongBiao 創建文件。     
    /// 
    /// <author>
    ///     <name>SongBiao</name>
    ///     <date>2018-04-18</date>
    /// </author>
    /// </summary>
    public class WechatUserScheduler
    {
        static Registry registry;
        /// <summary>
        /// 靜態構造函數
        /// </summary>
        static WechatUserScheduler()
        {
            registry = new Registry();
        }
        static List<string> jobList;
        /// <summary>
        /// 終止任務
        /// </summary>
        public static void RemoveJob()
        {
            try
            {
                foreach (var jobName in jobList)
                {
                    JobManager.RemoveJob(jobName);
                }
            }
            catch (Exception ex)
            {
                NLogHelper.Warn(ex, "Scheduler.RemoveJob");
            }
        }

        /// <summary>
        /// 初始化 啟動任務
        /// </summary>
        public static void Initialize()
        {
            jobList = new List<string>();
            try
            {
                WechatAccountSettingManager manager = new WechatAccountSettingManager();
                List<WechatAccountSettingEntity> list = manager.GetList<WechatAccountSettingEntity>(new KeyValuePair<string, object>(WechatAccountSettingEntity.FieldEnabled, 1), new KeyValuePair<string, object>(WechatAccountSettingEntity.FieldDeletionStateCode, 0));
                string jobName = string.Empty;
                foreach (var model in list)
                {
                    jobName = "SyncUser_" + model.Id;
                    jobList.Add(jobName);
                    // WithName 給這個定時任務唯一ID,這個任務ID是用於顯示控制任務,后面終止任務會用到 立即執行,而且每間隔10秒(Seconds)/10分鍾執行一遍
                    registry.Schedule(() => SynchroWechatUser(model)).WithName(jobName).ToRunNow().AndEvery(10).Minutes();
                }
                JobManager.Initialize(registry);
            }
            catch (Exception ex)
            {
                NLogHelper.Warn(ex, "Scheduler.Initialize");
            }
        }

        /// <summary>
        /// 設置實體
        /// </summary>
        /// <param name="wechatUser"></param>
        /// <param name="userInfo"></param>
        /// <param name="wechatAccountSetting"></param>
        private static void SetModel(WechatUserEntity wechatUser, UserInfoJson userInfo, WechatAccountSettingEntity wechatAccountSetting)
        {
            wechatUser.Subscribe = userInfo.subscribe;
            wechatUser.Openid = userInfo.openid;
            wechatUser.Nickname = userInfo.nickname;
            wechatUser.Sex = userInfo.sex;
            wechatUser.Language = userInfo.language;
            wechatUser.City = userInfo.city;
            wechatUser.Province = userInfo.province;
            wechatUser.Country = userInfo.country;
            wechatUser.HeadImgUrl = userInfo.headimgurl;
            wechatUser.SubscribeTime = userInfo.subscribe_time;
            wechatUser.UnionId = userInfo.unionid;
            wechatUser.Remark = userInfo.remark;
            wechatUser.GroupId = userInfo.groupid;
            wechatUser.TagidList = string.Join(",", userInfo.tagid_list);
            // 粉絲屬於哪一個公眾號的
            wechatUser.WechatAccountId = wechatAccountSetting.Id;
            wechatUser.CompanyId = wechatAccountSetting.CompanyId;
            wechatUser.CompanyName = wechatAccountSetting.Company;
        }

        /// <summary>
        /// 同步微信用戶數據,按公眾號各自同步粉絲
        /// 每次同步完畢記錄最后一次同步的用戶的openId,每隔一段時間繼續自動同步
        /// </summary>
        /// <param name="wechatAccountSetting"></param>
        private static void SynchroWechatUser(WechatAccountSettingEntity wechatAccountSetting)
        {
            try
            {
                var accessToken = Senparc.Weixin.MP.Containers.AccessTokenContainer.TryGetAccessToken(wechatAccountSetting.AppId, wechatAccountSetting.AppSecret);
                OpenIdResultJson openIdResultJson;
                OpenIdResultJson_Data openIdResultJsonData;
                UserInfoJson userInfo;
                WechatUserManager wechatUserManager = new WechatUserManager();
                WechatUserEntity wechatUserEntity = null;
                string tempNextOpenId = wechatAccountSetting.NextOpenid;
                do
                {
                    openIdResultJson = UserApi.Get(accessToken, tempNextOpenId);
                    openIdResultJsonData = openIdResultJson.data;
                    foreach (var openId in openIdResultJsonData.openid)
                    {
                        // 根據openId逐個拉取用戶
                        userInfo = UserApi.Info(accessToken, openId);
                        // 判斷該公眾號的openId的粉絲是否存在
                        wechatUserEntity = wechatUserManager.GetObjectByWechatAccountIdByOpenId(wechatAccountSetting.Id, openId);
                        if (wechatUserEntity == null)
                        {
                            wechatUserEntity = new WechatUserEntity();
                            SetModel(wechatUserEntity, userInfo, wechatAccountSetting);
                            wechatUserManager.Add(wechatUserEntity, false, false);
                        }
                        else
                        {
                            SetModel(wechatUserEntity, userInfo, wechatAccountSetting);
                            wechatUserManager.Update(wechatUserEntity);
                        }
                        tempNextOpenId = openId;
                    }
                    // 執行完畢再賦值穩妥一些 上面執行過程失敗 下次會繼續
                    wechatAccountSetting.NextOpenid = tempNextOpenId;
                }
                while (openIdResultJson.count == 10000);
            }
            catch (Exception ex)
            {
                NLogHelper.Warn(ex, "Scheduler.SynchroWechatUser,model=" + Serializer.ToJson(wechatAccountSetting));
            }
            finally
            {
                WechatAccountSettingManager manager = new WechatAccountSettingManager();
                manager.Update(wechatAccountSetting);
            }
        }
    }
}

 

三,定時任務方法的調用,直接集成到Asp.Net MVC 的Global事件里,當然也可以作為Window服務。

 

//-----------------------------------------------------------------------
// <copyright file="MvcApplication.cs" company="FenSiShengHuo, Ltd.">
//     Copyright (c) 2018 , All rights reserved.
// </copyright>
//-----------------------------------------------------------------------

using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;

namespace DotNet.WeChat.MVC
{
    using DotNet.Utilities;
    using DotNet.WeChat.MVC.Assist;

    /// <summary>
    ///  MvcApplication
    ///  應用全局事件   
    /// 
    /// 修改記錄
    ///
    ///        2018-04-20 版本:1.0 SongBiao 創建文件。
    ///
    /// <author>
    ///     <name>SongBiao</name>
    ///     <date>2018-04-20</date>
    /// </author>
    /// </summary>
    public class MvcApplication : System.Web.HttpApplication
    {
        /// <summary>
        /// 應用啟動
        /// </summary>
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            // 讀取配置
            ConfigurationHelper.GetConfig();
            // 啟動微信粉絲定時同步任務
            WechatUserScheduler.Initialize();
        }

        /// <summary>
        /// 修改 標頭報文 Server
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Application_PreSendRequestHeaders(object sender, EventArgs e)
        {
            HttpApplication app = sender as HttpApplication;
            if (app != null &&
                app.Context != null)
            {
                app.Context.Response.Headers.Remove("Server");
            }
        }

        /// <summary>
        /// 應用程序結束
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Application_End(object sender, EventArgs e)
        {
            // 停止微信粉絲定時同步任務
            WechatUserScheduler.RemoveJob();
        }
    }
}

 

 

 

 

頁面展示效果如上

 

 

歡迎大家參考,指點~~~

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM