微信公众号暂不支持更换主体,进行操作一般需要迁移账号
注意点⚠️:
2023年11月24日起,新提交订单的迁移内容选择“全部关注用户”时,目标账号关注用户数必须小于等于1000,否则不支持发起迁移。
操作流程:
1.准备并提交审核
审核(几个小时)--(中间可能需要接听审核电话)--审核通过---
2.操作确认迁移
双方管理员微信上点确认迁移;微信自动通知用户迁移公告
3.操作迁移(无任何处理)
账号A冻结24小时(这时账号A只能看迁移进度)---开始迁移(冻结24小时后才操作)---
4.迁移成功
迁移成功(A账号被回收,B账号正常使用)
补充
2.1 如果需要转换用户openId,
需要在确认迁移时,保存关注旧公众号用户openId
在迁移成功后,调用用户openId转换接口进行处理
2.2 双方管理员可以在【微信】上点迁移确认了(两个号同一个管理员的话只要老号确认)
3.1常见功能以下4项不能迁移:如果想延用老号的设置内容,需要提前在新号设置一下
【1】头像【2】介绍【3】自定义菜单【4】自动回复
3.2 冻结24小时后才开始迁移, 结束时间以具体的内容量为准(一般冻结后等2小时左右成功)。
3.3 迁移完成后老号主管理员的手机微信上会收到一个【迁移完成】的通知
4.1 迁移成功之前,公众号使用者没有任何影响,菜单配置内容均可正常使用
转换用户openId 代码
public static void changeOpenId throws Exception {
String tokenResult = getAccessToken();
JSONObject wxAccessTokenObj = JSON.parseObject(tokenResult);
String token = wxAccessTokenObj.getString("access_token");
if (StringUtil.isBlank(token)) throw new RuntimeException("获取核心信息缺失");
String path = "https://api.weixin.qq.com/cgi-bin/changeopenid?access_token=" + token;
//需要转换的openId列表
List<String> convertOpenIds = Arrays.asList(
"a", "b", "c");
int batchSize = 100;
for (int i = 0; i < convertOpenIds.size(); i += batchSize) {
int end = Math.min(i + batchSize, convertOpenIds.size());
List<String> batchList = convertOpenIds.subList(i, end);
JSONObject reqParam = new JSONObject();
reqParam.put("from_appid", "wxa"); //此处为原账号的appid
reqParam.put("openid_list", batchList);
String result = sendPost(path, JSON.toJSONString(reqParam));
log.info("result={}", result);
if (StringUtil.isBlank(result)) throw new RuntimeException("获取新openId结果失败");
JSONObject resultObj = JSON.parseObject(result);
String errcode = resultObj.getString("errcode");
if (!"0".equals(errcode)) throw new RuntimeException("获取新openId响应状态异常" + errcode+"["+resultObj.getString("errmsg")+"]");
JSONArray resultList = resultObj.getJSONArray("result_list");
if (ObjectUtils.isEmpty(resultList)) throw new RuntimeException("获取新openId响应列表异常");
for (Object item : resultList) {
JSONObject itemObj = JSON.parseObject(JSON.toJSONString(item));
String new_openid = itemObj.getString("new_openid");
if (StringUtil.isBlank(new_openid)) continue;
//对用户进行操作openId...
System.out.println("new_openid=" + new_openid);
}
}
}
/**
* 获取微信accessToken
*/
private static String getAccessToken() {
StringBuffer accessTokenUrl = new StringBuffer();
accessTokenUrl.append(WeChatProperties.wxAccessTokenPath)
.append("?grant_type=client_credential")
.append("&appid=")
//新appId
.append(WeChatProperties.appId)
.append("&secret=")
//新secret
.append(WeChatProperties.secret);
String url = accessTokenUrl.toString();
log.info("getAccessToken url:{}", url);
String tokenResult = null;
try {
tokenResult = sendGet(url, null, false);
} catch (Exception e) {
log.error("getAccessToken Exception ", e);
}
log.info("getAccessToken result:{}", tokenResult);
return tokenResult;
}
/**
* @param url 发送请求的URL
* @param param
* @param isJson 请求参数param是否为json格式
*/
public static String sendGet(String url, Map<String,Object> param,boolean isJson) throws IOException {
log.debug("sendGet url={},param={}",url,param);
String result = "";
BufferedReader in = null;
OutputStreamWriter writer = null;
try {
if(!isJson && param != null && param.size() > 0){
StringBuffer sbuff = new StringBuffer(url);
sbuff.append("?");
Iterator<Map.Entry<String, Object>> iterator =
param.entrySet().iterator();
while (iterator.hasNext()){
Map.Entry<String, Object> next = iterator.next();
sbuff.append(next.getKey()).append("=").append(next.getValue().toString()).append("&");
}
url = sbuff.substring(0, sbuff.length() - 1);
}
log.debug("sendGet real url={}",url);
URL realUrl = new URL(url);
// 打开和URL之间的连接
URLConnection connection = openConnection(realUrl);
// 设置通用的请求属性
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
if(isJson && param != null && param.size() > 0){
OutputStream outputStream = connection.getOutputStream();
outputStream.write(JSONObject.toJSONString(param).getBytes());
}
//建立连接
connection.connect();
in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (IOException e) {
log.error("发送GET请求出现异常!",e);
e.printStackTrace();
throw e;
}
// 使用finally块来关闭输入流
finally {
try {
if (in != null) {
in.close();
}
if (writer != null){
writer.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
return result;
}
public static String sendPost(String url, String param) throws IOException {
log.info("sendPost url={},param={}",url,param);
OutputStreamWriter out = null;
BufferedReader in = null;
String result = "";
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
HttpURLConnection conn = (HttpURLConnection) openConnection(realUrl);
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setRequestMethod("POST"); // POST方法
// 设置通用的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.connect();
// 获取URLConnection对象对应的输出流
out = new OutputStreamWriter(conn.getOutputStream(), "UTF-8");
// 发送请求参数
out.write(param);
// flush输出流的缓冲
out.flush();
// 定义BufferedReader输入流来读取URL的响应
int responseCode = conn.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
// 读取响应内容
in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} else {
log.error("发送 POST 请求失败,响应状态码: {}", responseCode);
throw new IOException("HTTP request failed with status code: " + responseCode);
}
} catch (IOException e) {
log.error("发送 POST 请求出现异常!",e);
e.printStackTrace();
throw e;
}
// 使用finally块来关闭输出流、输入流
finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
return result;
}
参考内容
官方地址:
https://kf.qq.com/faq/170112Q7vIfi1701122AVZvY.html