当前位置:网站首页>微信公众号对接 : 一键推送文章信息至公众号
微信公众号对接 : 一键推送文章信息至公众号
2022-06-21 07:41:00 【猫猫聚会Ing】
1. 需求 : 企业门户 - 一键将文章内容推送至WX公众号
对接企业微信
1、文章 - 一键推送至公众号
1、对接 公众号
2、定时获取公众号 token ( > 2 h )
1. 获取已知微信公众号基本信息

2. 服务器配置
IP 白名单
IP 白名单的配置了,你的服务器 IP 是一定要配置进去的,其余的 IP 酌情添加。

参考 :
1. 注意事项
1、服务器配置 需要进行校验,端口需要为 80
2、可自行写代码进行校验
3、校验通过,方可进行 启用 等后续流程
3. 内网穿透
natapp 存在缺陷:无法自定义选择端口号( 故此处不选择、不推荐 )
1. ngrok
unzip /path/to/ngrok.zip
ngrok config add-authtoken 2AYennnBRpRMLL3Ucl7kIpHevkB_2MvVwUqRhi1kYa4WMfZAi
ngrok http 80


4. 服务器校验 + 启用
https://a1f3-113-57-86-45.jp.ngrok.io/cms/weixin/event.do?grant_type=client_credential&appid=wxedxxxxxxx73e&secret=ad387ede22xxxxxxx1dce8c1c1e58
URL:https://a1f3-113-57-86-45.jp.ngrok.io/cms/weixin/event.do 对应代码
package net.mingsoft.cms.action.web;
import net.mingsoft.cms.action.BaseAction;
import net.mingsoft.cms.util.AesException;
import net.mingsoft.cms.util.SHA1;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import springfox.documentation.annotations.ApiIgnore;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @Author: menghuan
* @Date: 2022/6/14 14:57
*/
// @Slf4j
@ApiIgnore
@Controller("cmsWeiXin")
@RequestMapping("/cms/weixin")
public class WeiXinAction extends BaseAction {
private static final String TOKEN = "ECMS_BOLIYUAN_QIYEMENHU";
@GetMapping("/event")
public void event(HttpServletRequest request, HttpServletResponse response) throws IOException {
//微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp,nonce参数
String signature = request.getParameter("signature");
//时间戳
String timestamp = request.getParameter("timestamp");
//随机数
String nonce = request.getParameter("nonce");
//随机字符串
String echostr = request.getParameter("echostr");
String token = TOKEN;
String jiami="";
try {
jiami = SHA1.getSHA1(token, timestamp, nonce,"");//这里是对三个参数进行加密
} catch (AesException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("加密"+jiami);
System.out.println("本身"+signature);
PrintWriter out=response.getWriter();
if(jiami.equals(signature)){
out.print(echostr);
}
}
}1. 校验结果

2. 启用

5. 缓存 access_token ( 1h50min 国期 + 重新获取 / 更新缓存 )
公众平台以 access_token 为接口调用凭据,来调用接口,
所有接口的调用需要先获取 access_token,access_token 在 2 小时内有效,过期需要重新获取,
但1天内获取次数有限,开发者需自行存储,详见获取接口调用凭据(access_token)文档。
2. 微信公众号对接开发
1. 获取Token令牌:https://api.weixin.qq.com/cgi-bin/token


获取令牌:
"access_token": "57_jnXVM7QzA8zGAGIsxil5accpU40IYI-kFC7rw5aPWV763Zjp0hqd9seepmIMweT9XUunCsa9aQEy7F0CRfr_K0lSoG086k6LWrHNlwpcgGhYlW2TiQFKJ3yMJSlDYQC2nY2Kqt0Pk6hNtqX_TXZgAIAWAC"
2. 通过API+Token 发送请求 : 新增素材
https://api.weixin.qq.com/cgi-bin/draft/add?access_token={ {access_token}}
{
"articles": [
{
"title": "caca",
"author": "猫猫聚会",
"content": "cacacacacacacacaca",
"thumb_media_id": "EA69IHOkcmKWQxqpOrq8UeEaBovm_n3H_0kkGyiMi_ATihrP7KDku1zZDSozsNjQ",
"need_open_comment": 0,
"only_fans_can_comment": 0
}
]
}详参:
3. Java 端模拟客户端发起 get / post 请求
1. HttpUtil.java
亲测,可用
package net.mingsoft.cms.util;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.util.Map;
/**
* http请求工具
*/
@Slf4j
public class HttpUtil {
// private static final Logger logger = LoggerFactory.getLogger(HttpUtil.class);
/**
* 发送post请求
* @param json 参数体
* @param URL 请求地址
* @return 返回结果
*/
public static String sendPost(JSONObject json, String URL) {
CloseableHttpClient client = HttpClients.createDefault();
HttpPost post = new HttpPost(URL);
post.setHeader("Content-Type", "application/json");
post.setHeader("User-Agent", "Apipost client Runtime/+https://www.apipost.cn/");
// post.addHeader("Authorization", "Basic YWRtaW46");
String result;
try {
StringEntity s = new StringEntity(json.toString(), "utf-8");
s.setContentType(new BasicHeader(HTTP.CONTENT_TYPE,
"application/json"));
post.setEntity(s);
// 发送请求
HttpResponse httpResponse = client.execute(post);
// 获取响应输入流
InputStream inStream = httpResponse.getEntity().getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader( inStream, "utf-8"));
StringBuilder strBuilder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null)
strBuilder.append(line + "\n");
inStream.close();
result = strBuilder.toString();
if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
log.info("请求服务器SUCCESS");
// System.out.println("请求服务器成功,做相应处理");
} else {
log.info("请求服务端FALSE");
// System.out.println("请求服务端失败");
}
} catch (Exception e) {
log.error("请求异常EXCEPTION:"+e.getMessage());
throw new RuntimeException(e);
}
return result;
}
/**
* 发送get请求
* @param url 请求URL
* @param param 请求参数 key:value url携带参数 或者无参可不填
* @return
*/
public static String sendGet(String url, Map<String, String> param) {
// 创建Httpclient对象
CloseableHttpClient httpclient = HttpClients.createDefault();
String resultString = "";
CloseableHttpResponse response = null;
try {
// 创建uri
URIBuilder builder = new URIBuilder(url);
if (param != null) {
for (String key : param.keySet()) {
builder.addParameter(key, param.get(key));
}
}
URI uri = builder.build();
// 创建http GET请求
HttpGet httpGet = new HttpGet(uri);
// 执行请求
response = httpclient.execute(httpGet);
// 判断返回状态是否为200
if (response.getStatusLine().getStatusCode() == 200) {
resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (response != null) {
response.close();
}
httpclient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return resultString;
}
public static void main(String[] args) {
JSONObject EventTraceInput = new JSONObject();
String url="https://api.weixin.qq.com/cgi-bin/draft/add?access_token=57_espiUswWO3w-v7qQQavrnPVOcmpwZ6UDZ12k7iLBWGbzflCe01NvDAQUnEqzBzKxGHJpkmo6PfbcMjKmPz9-toqDnXpCJ0GDeDvIFxIyy3x3yaf7jUIpr8MoNhcE51VzdN3RLneP_g43MB1cBZKbADAKIT";
JSONArray EventArray = new JSONArray();
JSONObject jsonArray = new JSONObject();
jsonArray.put("title","caca");
jsonArray.put("author","猫猫聚会");
jsonArray.put("content","cacacacacacacacaca");
jsonArray.put("thumb_media_id","EA69IHOkcmKWQxqpOrq8UeEaBovm_n3H_0kkGyiMi_ATihrP7KDku1zZDSozsNjQ");
jsonArray.put("need_open_comment",0);
jsonArray.put("only_fans_can_comment",0);
EventArray.add(jsonArray);
EventTraceInput.put("articles",EventArray);
String strResult = sendPost(EventTraceInput, url);
System.out.println(
strResult
);
log.info("strResult:{}",strResult);
}
}
2. 代码示例
1. 新增文章草稿
/**
* 新增文章草稿
* @return String 返回新增草稿 media_id,用于后续发布
*/
private String insertContentDraft(WxCore wxCore, ContentEntity contentEntity){
String accessToken = "access_token=" + wxCore.getWxAccessToken();
// 构造参数消息体
JSONObject eventTraceInput = new JSONObject();
String url="https://api.weixin.qq.com/cgi-bin/draft/add?" + accessToken;
JSONArray eventArray = new JSONArray();
JSONObject jsonArray = new JSONObject();
jsonArray.put("title",contentEntity.getContentTitle());
jsonArray.put("content",contentEntity.getContentDetails());
jsonArray.put("thumb_media_id","EA69IHOkcmKWQxqpOrq8UeEaBovm_n3H_0kkGyiMi_ATihrP7KDku1zZDSozsNjQ");
jsonArray.put("author",wxCore.getWxName());
jsonArray.put("need_open_comment",0);
jsonArray.put("only_fans_can_comment",0);
eventArray.add(jsonArray);
eventTraceInput.put("articles",eventArray);
// 发送请求
String strResult = HttpUtil.sendPost(eventTraceInput, url);
log.info("strResult:{}",strResult);
try{
Map mapResult = objectMapper.readValue(strResult, Map.class);
if (null != mapResult){
if (mapResult.containsKey("errcode") && StringUtils.isNotBlank(mapResult.get("errcode").toString()) && "42001".equals(mapResult.get("errcode").toString())){
throw new MCmsException("新增文章草稿异常:访问令牌过期,请核实后操作");
}
if(StringUtils.isNotBlank(mapResult.get("media_id").toString())){
log.info("同步新增文章草稿SUCCESS,草稿MEDIA_ID:{}",mapResult.get("media_id").toString());
return mapResult.get("media_id").toString();
}
}
throw new MCmsException("新增文章草稿异常,请核实后操作");
} catch (IOException e) {
log.error("解析失败...");
e.printStackTrace();
throw new MCmsException("文章草稿信息解析失败,请核实后操作");
}
}2. 发布文章(草稿)
/**
* 发布文章(草稿)
* @return String 返回新增草稿 media_id,用于后续发布
*/
private Boolean pushContentDraft(WxCore wxCore, String mediaId){
String accessToken = "access_token=" + wxCore.getWxAccessToken();
// 构造参数消息体
JSONObject eventTraceInput = new JSONObject();
String url = "https://api.weixin.qq.com/cgi-bin/freepublish/submit?" + accessToken;
eventTraceInput.put("media_id",mediaId);
// 发送请求
String strResult = HttpUtil.sendPost(eventTraceInput, url);
try{
Map mapResult = objectMapper.readValue(strResult, Map.class);
if (null != mapResult && StringUtils.isNotBlank(mapResult.get("errcode").toString())){
if ("0".equals(mapResult.get("errcode").toString())){
log.info("发布文章(草稿)SUCCESS,ERRCODE状态码:{}",0);
return true;
}
if ("40001".equals(mapResult.get("errcode").toString())){
throw new MCmsException("AppSecret错误或失效,请开发者确认 AppSecret 的正确性");
}
}
} catch (IOException e) {
log.error("解析失败...");
e.printStackTrace();
}
return false;
}
3. 查询激活状态微信公众号的access_token
/**
* 查询激活状态微信公众号的access_token
* @return Boolean.TRUE or Boolean.FALSE
*/
public String queryWXAccessToken(WxCore wxCore){
String accessToken = "access_token=" + wxCore.getWxAccessToken();
// 构造参数消息体
// JSONObject eventTraceInput = new JSONObject();
String url = "https://api.weixin.qq.com/cgi-bin/token?" + accessToken;
// eventTraceInput.put("media_id",mediaId);
Map<String, String> param = new HashMap<>();
param.put("grant_type","client_credential");
param.put("appid",wxCore.getWxAppId());
param.put("secret",wxCore.getWxAppSecret());
// 发送请求
// String strResult = HttpUtil.sendPost(eventTraceInput, url);
String strResult = HttpUtil.sendGet(url, param);
try{
Map mapResult = objectMapper.readValue(strResult, Map.class);
if (null != mapResult){
if (StringUtils.isNotBlank(mapResult.get("access_token").toString())){
return mapResult.get("access_token").toString();
}
if ("40013".equals(mapResult.get("errcode").toString())){
throw new MCmsException("AppID错误或无效,请开发者确认 AppID 的正确性");
}
if ("0".equals(mapResult.get("errcode").toString())){
log.info("查询access_token请求发送成功SUCCESS");
}
}
} catch (IOException e) {
log.error("解析失败...");
e.printStackTrace();
}
return "FALSE";
}至此,微信公众号其他操作,按需对接、按需操作,哇咔咔......
边栏推荐
- Yyds dry goods inventory rapid establishment of CEPH cluster
- [DB written interview 390] what is the external table of oracle?
- QML control type: drawer
- China uncoated intermittent catheter market trend report, technical innovation and market forecast
- Singleton mode in multithreaded environment
- Seat number of Pat grade B 1041 test (15 points)
- 如何让mysql不区分大小写
- ETF operation practice record: February 22, 2022
- Cloud native enthusiast weekly: Chaos mesh upgraded to CNCF incubation project
- 32单片机——pwm波输出
猜你喜欢

JVM内存模型概念

16 general measurement of data skewness and kurtosis

How to modify system language in win7

2022年的WordPress网站安全问题

Talk about MySQL's locking rule "hard hitting MySQL series 15"

How to make MySQL case insensitive

20 statistics and their sampling distribution -- Sampling Distribution of sample proportion

RPA(影刀)无需写代码抓取某东的商品信息

Getting started with MATLAB

Life cycle of kubernetes pod
随机推荐
Postman publishing API documentation
数学是用于解决问题的工具
Exists and in
Ansa secondary development - external programs use socket to communicate with ansa
In order to thoroughly understand the problem of garbled code, I dug up the history of the character set in a rage
Best practice | how to use Tencent cloud micro build to develop enterprise portal applications from 0 to 1
How MySQL closes a transaction
Best practice | how to use Tencent cloud micro build to develop enterprise portal applications from 0 to 1
Root cause analysis | inventory of nine scenarios with abnormal status of kubernetes pod
app安全滲透測試詳細方法流程
Best practice | how to use Tencent cloud micro build to develop enterprise portal applications from 0 to 1
应用程序卡死,如何快速退出?
How to solve the problem that MySQL is not an internal command
2021-07-28 STM32F103 I2C Hardware Transfer Include previous IO Clock EXIT USB use firmware library
2021-07-28 STM32F103配置信息
MATLAB快速入门
The reality camera in unity operates the mirror and lookat to the front of the object based on dotween
Rdkit | molecular similarity based on molecular fingerprint
A shell script to realize automatic expiration of Prometheus push gateway indicators
unity里现实摄像头运镜并LookAt到物体前方 基于Dotween