微信公众号对接 : 一键推送文章信息至公众号

1. 需求 : 企业门户 - 一键将文章内容推送至WX公众号

对接企业微信
    1、文章 - 一键推送至公众号
        1、对接 公众号
        2、定时获取公众号 token ( > 2 h )


1. 获取已知微信公众号基本信息

微信公众号对接 : 一键推送文章信息至公众号_第1张图片


2. 服务器配置

IP 白名单

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

微信公众号对接 : 一键推送文章信息至公众号_第2张图片

参考 :

微信公众号开发:服务器配置(Java)_weixin_30349597的博客-CSDN博客 ( √ )

对接微信-----微信服务器配置(java版)_往前的娘娘的博客-CSDN博客


1. 注意事项

1、服务器配置 需要进行校验,端口需要为 80

2、可自行写代码进行校验

3、校验通过,方可进行 启用 等后续流程


3. 内网穿透

natapp 存在缺陷:无法自定义选择端口号( 故此处不选择、不推荐 )


1. ngrok

 unzip /path/to/ngrok.zip
 ngrok config add-authtoken 2AYennnBRpRMLL3Ucl7kIpHevkB_2MvVwUqRhi1kYa4WMfZAi
 ngrok http 80

微信公众号对接 : 一键推送文章信息至公众号_第3张图片

微信公众号对接 : 一键推送文章信息至公众号_第4张图片


4. 服务器校验 + 启用

https://a1f3-113-57-86-45.jp.ngrok.io/cms/weixin/event.do?grant_type=client_credential&appid=wxedxxxxxxx73e&secret=ad387ede22xxxxxxx1dce8c1c1e58

微信公众号对接 : 一键推送文章信息至公众号_第5张图片

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. 校验结果

微信公众号对接 : 一键推送文章信息至公众号_第6张图片


2. 启用

微信公众号对接 : 一键推送文章信息至公众号_第7张图片


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

微信公众号对接 : 一键推送文章信息至公众号_第8张图片

微信公众号对接 : 一键推送文章信息至公众号_第9张图片

获取令牌:

"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 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 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";
	}


至此,微信公众号其他操作,按需对接、按需操作,哇咔咔......

你可能感兴趣的:(Java,篇,java,微信)