背景:公众号换主体,要迁移,粉丝(openId)的业务数据要做处理.

第一步:参照我的另一篇文章,Java 导出微信公众号粉丝。

第二部:数据处理(master-worker模式)

程序主入口:Main

我导出来的粉丝文件格式是:

{"info":[{"openId":"ogVous494ltuNmO4zHb1seHeGLSk"}      ..... 1万条]
}

package changeOpenId;import java.util.List;
import java.util.Map;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.odao.weixin.api.support.AccessTokenKit;
import com.odao.weixin.site.cases2017.change.service.ChangeService;
import com.odao.weixin.site.cases2017.push.entity.JsonDataReadUtil;/*** 多线程转换openId* @author wangfj*/
public class ChangeMain {  @SuppressWarnings({ "unchecked", "static-access", "resource" })public static void main(String[] args) throws Exception {  ApplicationContext appContext = new ClassPathXmlApplicationContext(new String[] {"odao-weixin-site-servlet.xml"});String token = AccessTokenKit.getTokenNew("APPID", "APP秘钥");String accesstoken = (String) ((Map) JSON.parseObject(token, Map.class)).get("access_token");//根据粉丝文件来读取数据JSONObject openIdJson = JsonDataReadUtil.getReadJsonByPath("第一步导出来的文件");String info= openIdJson.get("info").toString();JSONArray jsonArr = JSONObject.parseArray(info);List<Map<String,Object>> list = jsonArr.toJavaObject(jsonArr,  List.class);//如果你们是直接操作数据库,可以直接写一个业务类,从数据库获取要转换的数据,如下:/*ChangeService changeService = (ChangeService) appContext.getBean("changeService");List<Map<String,Object>> list = changeService.queryRecord(40000,50000);*///构造masterChangeMaster master = new ChangeMaster(new ChangeWorker(),100,accesstoken,appContext);//第二个参数100(worker工作线程数),这个根据你们自己的需求定for(int i=0;i<list.size();i+=100){//微信转换openId接口,腾讯说是一次只能处理100条List<Map<String,Object>> newList = list.subList(i, (i+100)>list.size()?list.size():(i+100));master.submit(newList);}//多线程执行
        master.execute();while(true){if(master.isComplate()){long allTime = master.getResult();System.out.println("主线程执行完毕,总耗时:"+allTime+"毫秒");break;}}}}  

Master:

package changeOpenId;import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import org.springframework.context.ApplicationContext;/*** Master任务指派者,分发者 * @author wangfj*/
public class ChangeMaster{private ConcurrentLinkedQueue<List<Map<String,Object>>> workerQueue =  new ConcurrentLinkedQueue<List<Map<String,Object>>>();//存放所有的工作者private HashMap<String, Thread> workers = new HashMap<String, Thread>();//存放数据的结果集private ConcurrentHashMap<String,Object> resultMap = new ConcurrentHashMap<String, Object>();//构造masterpublic ChangeMaster(Worker worker,int workerCount,String accessToken,ApplicationContext appContext){worker.setApplicationContext(appContext);worker.setWorkerQueue(this.workerQueue);worker.setAccessToken(accessToken);worker.setResultMap(resultMap);for(int i=0;i<workerCount;i++){this.workers.put("执行任务worker"+i,new Thread(worker,"子线程"+i));}}//提交public void submit(List<Map<String,Object>> list){this.workerQueue.add(list);}//执行public void execute(){for(Map.Entry<String,Thread> me :workers.entrySet()){me.getValue().start();}}//获得执行结果集public long getResult(){long result = 0l;for(Map.Entry<String,Object> me :resultMap.entrySet()){result += (Long)me.getValue();}return result;}//所有子线程是否执行完毕public boolean isComplate() {for(Map.Entry<String,Thread> me :workers.entrySet()){if(Thread.State.TERMINATED != me.getValue().getState()){return false;}}return true;}
}

Worker(转换openId核心代码):

package changeOpenId;import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HTTP;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.odao.weixin.site.cases2017.change.service.ChangeService;@Service
public class ChangeWorker extends Worker{public static String url = "http://api.weixin.qq.com/cgi-bin/changeopenid?access_token=";  //微信提供中的openId转换接口public static long handle(List<Map<String,Object>> list,String accessToken,ApplicationContext appContext) throws Exception {ChangeService changeService = (ChangeService) appContext.getBean("changeService");//我处理数据的业务类long end = System.currentTimeMillis();JSONObject params = new JSONObject();params.put("from_appid", "xxxx");//此处from_appid为原帐号的appid
        ArrayList<String> openIds = new ArrayList<String>();for(int i=0;i<list.size();i++){openIds.add(list.get(i).get("openId").toString());}params.put("openid_list", openIds);//需要转换的openid,即第1步中拉取的原帐号用户列表,这些必须是旧账号目前关注的才行,否则会出错;一次最多100个,不能多。格式:["openIdA","openIdB"]
        String reslut = JsonSMS(params.toString(),accessToken);JSONObject json = (JSONObject) JSONObject.parse(reslut);if("ok".equals(json.getString("errmsg"))){String result_list = json.get("result_list").toString();JSONArray arr= JSONObject.parseArray(result_list);List<Map<String,Object>> obj = arr.toJavaObject(arr,  List.class);if(!obj.get(0).get("err_msg").equals("ori_openid error")){List<Map<String,Object>> openIdObj = arr.toJavaObject(arr,  List.class);changeService.batchUpdateAccountsMapping(openIdObj);}}else{System.out.println("请求微信转换接口返回异常");}return System.currentTimeMillis()-end;}public static String JsonSMS(String postData, String token) {String result = "";try {//发送POST请求URL urls = new URL(url.concat(token));HttpURLConnection conn = (HttpURLConnection) urls.openConnection();conn.setRequestMethod("POST");conn.setRequestProperty("Content-Type", "application/json");conn.setRequestProperty("Connection", "Keep-Alive");conn.setUseCaches(false);conn.setDoOutput(true);conn.setRequestProperty("Content-Length", "" + postData.length());OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream(), "UTF-8");out.write(postData);out.flush();out.close();//获取响应状态if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {System.out.println("connect failed!");return "";}//获取响应内容体
            String line;BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));while ((line = in.readLine()) != null) {result += line + "\n";}in.close();} catch (IOException e) {e.printStackTrace(System.out);}return result;}
}

package changeOpenId;import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import org.springframework.context.ApplicationContext;public class Worker implements Runnable{private ConcurrentLinkedQueue<List<Map<String,Object>>> workerQueue;private ConcurrentHashMap<String,Object> resultMap;private ApplicationContext appContext;private String accessToken;public void setWorkerQueue(ConcurrentLinkedQueue<List<Map<String,Object>>> workerQueue) {this.workerQueue = workerQueue;}public void setResultMap(ConcurrentHashMap<String, Object> resultMap) {this.resultMap = resultMap;}public void setAccessToken(String accessToken) {this.accessToken = accessToken;}@Overridepublic void run() {while(true){List<Map<String,Object>> input = this.workerQueue.poll();if(input==null) break;try {Random random = new Random();long time = ChangeWorker.handle(input,accessToken,appContext);resultMap.put(String.valueOf(random.nextInt(100)), time);} catch (Exception e) {e.printStackTrace();}}}@SuppressWarnings("unused")private static void handle(List<String> list) {}public void setApplicationContext(ApplicationContext appContext) {this.appContext = appContext;}
}

处理数据的业务类:

package com.odao.weixin.site.cases2017.change.service;import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;@Service
public class ChangeService {static final Logger logger = LoggerFactory.getLogger(ChangeService.class);@Autowiredprivate JdbcTemplate jdbcTemplateWebSiteActivityDB;/*** 批量更新玩家openId* @param list*/public void batchUpdateAccountsMapping(final List<Map<String,Object>> list) {  String sql = "update 表名 set newOpenId=? ,createTime=getdate() where openId=?";  jdbcTemplateWebSiteActivityDB.batchUpdate(sql, new BatchPreparedStatementSetter() {  public int getBatchSize() {  return list.size();  //这个方法设定更新记录数,通常List里面存放的都是我们要更新的,所以返回list.size();
            }  public void setValues(java.sql.PreparedStatement ps, int i) throws SQLException {try{ps.setString(1, list.get(i).get("new_openid").toString());  ps.setString(2, list.get(i).get("ori_openid").toString());}catch(Exception e){}}  });  System.out.println(Thread.currentThread().getName()+"成功改变条数:"+list.size());}
}

业务类操作的表字段最好加上索引,基本上几秒钟几万数据就跑完了。

转载于:https://www.cnblogs.com/wangfajun/p/8399677.html

Java 微信公众号迁移相关推荐

  1. 慕课网_《Java微信公众号开发进阶》学习总结

    时间:2017年08月12日星期六 说明:本文部分内容均来自慕课网.@慕课网:http://www.imooc.com 教学源码:http://img.mukewang.com/down/... 学习 ...

  2. java微信公众号开发token验证失败的问题及解决办法

    java微信公众号开发token验证失败的问题及解决办法 参考文章: (1)java微信公众号开发token验证失败的问题及解决办法 (2)https://www.cnblogs.com/beardu ...

  3. Java微信公众号开发梳理

    Java微信公众号开发梳理 现在微信公众平台的开发已经越来越普遍,这次开发需要用到微信公众平台.因此做一个简单的记录,也算是给那些没踩过坑的童鞋一些启示吧.我将分几块来简单的描述一下,之后会做详细的说 ...

  4. java微信公众号开发及源码分享

    java微信公众号开发源码下载 刚做完微信公众号项目,分享一下代码,经验!初写博客,格式写得不好,还请见谅.有不懂的可以留言或加qq 505281494交流下. 一. 第一步进行服务器接口配置,提交信 ...

  5. java微信公众号自动回复文字加图片

    java微信公众号自动回复文字加图片 开发流程 详细流程,附上代码: 第一步服务器(url)接口配置 服务器(url)接口配置,此步骤就是微信授权接口的过程,如果域名都不改变,微信只会校验一次.此请求 ...

  6. Java微信公众号开发微信网页授权之前端传递code方式获取用户信息

    本片博客讲解的网页授权分为两步,前端先传递backUrl(回调地址)到后台网页授权接口,该接口拿到回调地址后组装授权连接,重定向到前端页面,前端页面截取Code,传入后端获取用户信息方法,获取用户信息 ...

  7. 手把手教你微信公众号迁移_四步教你怎么迁移微信公众号

    教你迁移微信公众号_迁移完成后,原账号就注销了,无法再登陆公众号后台,登进去是这样的界面 微信公众号迁移说难不难,说简单也不简单.下面用4步来教会你们操作微信公众号迁移,每一点都写的非常详细,记得收藏 ...

  8. java微信公众号JSAPI支付以及所遇到的坑

    java微信公众号JSAPI支付以及所遇到的坑 上周做了个支付宝微信扫码支付,今天总结一下.微信相比支付宝要麻烦许多 由于涉及到代理商,没办法,让我写个详细的申请流程,懵逼啊. 笔记地址 http:/ ...

  9. Java微信公众号配置验证Token

    Java微信公众号服务器配置-验证Token 一.填写服务器配置 首先我们需要在微信公众平台上填写服务器配置 重点内容 服务器地址URL(一定要外网能访问的到)         在我们提交配置的时候, ...

最新文章

  1. 开源大数据周刊-第76期
  2. DVB-C系统中QAM调制与解调仿真
  3. scala中object和class关键字的区别
  4. rancher安装和使用
  5. linux系统安装ntp,CentOS下NTP安装配置
  6. mysql公告信息管理系统_JSP班级公告管理系统+mysql 班级公告管理系统 - 下载 - 搜珍网...
  7. diskData磁盘数据分析
  8. Cocos Creator 编辑器扩展
  9. data 谷歌浏览器更改user 路径_安卓微信 7.0.13.2开启众测邀请,数据存储路径迁移...
  10. 三极管设计,理解饱和,线性区域和截止区
  11. 软考高级信息系统项目管理师经验分享
  12. Mac --显示隐藏文件
  13. Echats给柱状图及提示文字添加百分号(%)的解决办法
  14. Crucible安装与使用(代码审查Code Review)
  15. echarts实现中国地图踩过的坑--------有些省的value可以拿到,有些省的value拿不到
  16. 【论文笔记】BusTr,基于实时交通数据的公交旅行时间预测
  17. display:grid 布局实现两行两列
  18. 基于独立工作流引擎实现的SuperFlow工作流平台设计方案
  19. 压缩感知(compressed sensing)的通俗解释
  20. Apollo 3.0代码浅析(一)

热门文章

  1. 孩子学vipjr400多天,才发现vipjr外教跟其他平台最大的区别
  2. 大白话告诉你,hadoop到底是个什么鬼
  3. 线性代数学习之初等矩阵和矩阵的可逆性
  4. html是一种用于创建网页的标准标记语言,html标记是什么
  5. 程序员表情包大全 | 别以为程序员没脾气好欺负哦
  6. Internal Covariate Shift以及Batch Normalization
  7. thinkPHP5 错误页面修改
  8. 哈尔滨工程大学计算机考研复试技巧
  9. 摄影入门-之四-镜头篇
  10. 详细的摄像头模组工作原理