java微信公众号新建草稿并发布

news2024/11/24 9:18:27
java实现公众号发起新建草稿,并且发布得到文章链接

首先要先去微信公众号的设置与开发–基础设置 查看公众号的各个参数,这里我是存储到数据库,方便后期使用,实体类如下:

	
@Data
public class WeChatOfficial {

    private static final long serialVersionUID=1L;

    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    /**
     * 公众号appid
     */
    private String appId;

    /**
     * 公众号appsecret
     */
    private String appSecret;

    /**
     * 文章图片链接
     */
    private String imageUrl;

    /**
     * 文章封面图片ID
     */
    private String mediaId;

    /**
     * 是否启用(0否;1是)
     */
    private Integer enable;

    /**
     * 公众号名称
     */
    private String officialName;

    /**
     * 微信公众号原始ID
     */
    private String originalId;

}

话不多说,直接上代码(新建草稿并发布代码)

public static String publish(String title, String sourceUrl, WeChatOfficial chatOfficialConfig){
        String tokenUrl = "https://api.weixin.qq.com/cgi-bin/token";
        String publishId = null;
        JSONObject paraObj = new JSONObject();
        JSONArray paraArr = new JSONArray();
        //组装草稿箱需要的参数
        JSONObject para = new JSONObject();
        para.put("title", title);
        para.put("content", "<p><a href='"+sourceUrl+"'><img src='"+chatOfficialConfig.getImageUrl()+"'/></a></p>\n" +
                "<a href='"+sourceUrl+"' style=\"color: #FFFFFF; text-decoration: none;\"><section style=\"text-align: center; margin-top: 8px; background: rgb(234, 68, 90); height: 48px; border-radius: 2px; color: rgb(255, 255, 255); line-height: 48px; font-size: 17px; text-shadow: rgb(255, 185, 149) 1px 1px 3px;\"><strong>打开剧场</strong></section></a>");
        para.put("thumb_media_id", chatOfficialConfig.getMediaId());
        para.put("content_source_url", sourceUrl);
        paraArr.add(para);
        paraObj.put("articles", paraArr);
        //先获取公众号token
        String tokenResult = HttpUtils.sendGet(tokenUrl+"?grant_type=client_credential&appid="+chatOfficialConfig.getAppId()+"&secret="+chatOfficialConfig.getAppSecret());
        if(StringUtils.isNotEmpty(tokenResult)) {
            log.info("公众号token:"+tokenResult);
            JSONObject jsonObject = JSONObject.parseObject(tokenResult);
            String accessToken = jsonObject.getString("access_token");
            String result = HttpUtils.sendPostByJSON("https://api.weixin.qq.com/cgi-bin/draft/add?access_token="+accessToken, JSONObject.toJSONString(paraObj));
            log.info("新建草稿返回:"+result);
            //{"media_id":"MEDIA_ID","item":[]} media_id 上传后的获取标志,长度不固定,但不会超过 128 字符
            JSONObject draftObj = JSONObject.parseObject(result);
            String mediaId = draftObj.getString("media_id");
            //发布草稿
            String publishUrl = "https://api.weixin.qq.com/cgi-bin/freepublish/submit?access_token="+accessToken;
            JSONObject pObj = new JSONObject();
            pObj.put("media_id", mediaId);
            String result1 = HttpUtils.sendPostByJSON(publishUrl, JSONObject.toJSONString(pObj));
            log.info("发布草稿返回:"+result1);
            JSONObject pubObj = JSONObject.parseObject(result1);
            Integer errCode = pubObj.getInteger("errcode");
            if(errCode==0){
                publishId = pubObj.getString("publish_id");
            }
            return publishId;
        }else{
            return null;
        }
    }

用到的util

public static String sendGet(String url) {
        String result = "";
        BufferedReader in = null;
        try {
            // String urlNameString = url + "?" +
            // URLEncoder.encode(param,"UTF-8");
            String urlNameString = url;
            System.out.println(urlNameString);
            URL realUrl = new URL(urlNameString);
            // 打开和URL之间的连接
            URLConnection connection = realUrl.openConnection();
            // 设置通用的请求属性
            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            // 建立实际的连接
            connection.connect();
            // 获取所有响应头字段
            Map<String, List<String>> map = connection.getHeaderFields();
            // 遍历所有的响应头字段
            for (String key : map.keySet()) {
                // System.out.println(key + "--->" + map.get(key));
            }
            // 定义 BufferedReader输入流来读取URL的响应
            in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            System.out.println("发送GET请求出现异常!" + e);
            e.printStackTrace();
        }
        // 使用finally块来关闭输入流
        finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
        return result;
    }

/**
     * 参数json为json格式的字符串
     * @param urlStr
     * @param json
     * @return
     */
    public static String sendPostByJSON(String urlStr, String json) {
        OutputStreamWriter outputStreamWriter = null;
        BufferedReader bufferedReader = null;
        String response = "";

        try {
            URL url = new URL(urlStr);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setDoInput(true);
            connection.setDoOutput(true);
            connection.setUseCaches(false);
            connection.setRequestMethod("POST");      //POST需大写
            connection.setRequestProperty("content-Type", "application/json");        //设置数据格式为json
            connection.setRequestProperty("charset", "utf-8");                        //设置编码格式为utf-8
            connection.connect();

            outputStreamWriter = new OutputStreamWriter(connection.getOutputStream());
            outputStreamWriter.append(json);
            outputStreamWriter.flush();

            bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"));
            String line = "";
            while((line = bufferedReader.readLine()) != null) {
                response += line;
            }

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                outputStreamWriter.close();
                bufferedReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return response;
    }

由于发布任务提交后,发布任务可能在一定时间后才完成,因此,发布接口调用时,仅会给出发布任务是否提交成功的提示,若发布任务提交成功,则在发布任务结束时,会向开发者在公众平台填写的开发者URL(callback URL)推送事件。

推送的XML结构成功时示例

<xml> 
  <ToUserName><![CDATA[gh_4d00ed8d6399]]></ToUserName>  
  <FromUserName><![CDATA[oV5CrjpxgaGXNHIQigzNlgLTnwic]]></FromUserName>  
  <CreateTime>1481013459</CreateTime>
  <MsgType><![CDATA[event]]></MsgType>
  <Event><![CDATA[PUBLISHJOBFINISH]]></Event>
  <PublishEventInfo>
    <publish_id>2247503051</publish_id>
    <publish_status>0</publish_status>
    <article_id><![CDATA[b5O2OUs25HBxRceL7hfReg-U9QGeq9zQjiDvy
WP4Hq4]]></article_id>
    <article_detail>
      <count>1</count>
      <item>
        <idx>1</idx>
        <article_url><![CDATA[ARTICLE_URL]]></article_url>
      </item>
    </article_detail>
  </PublishEventInfo>
</xml>

既然是微信公众号回推,那就需要在公众号的服务器配置这里配置相关的回推接口
在这里插入图片描述
下面是回推接口的实现代码:


private String token = "xxx";

@ApiOperation(value = "接收微信公众号草稿箱发布成功信息")
    @RequestMapping(value = "/receivePublishResult", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public String receivePublishResult(HttpServletRequest request){
        String signature = request.getParameter("signature");
        String timestamp = request.getParameter("timestamp");
        String nonce = request.getParameter("nonce");
        String echostr = request.getParameter("echostr");
        log.info("接收微信请求消息入参:signature-"+signature+"-timestamp-"+timestamp+"-nonce-"+nonce);
        log.info("其它信息:"+request.getParameterNames());
        String[] allStr = {token, timestamp, nonce};
        List<String> list = Arrays.asList(allStr);
        //对回推字符串进行排序
        Collections.sort(list);
        String arr = "";
        for (int i = 0; i < list.size(); i++) {
            arr += list.get(i);
        }
        //通过加密获取到本地的签名
        String decode = ShaUtils.getSha1(arr);
        //判断回推的签名是否和本地一致,一致则继续处理
        if(signature.equals(decode)) {
            try {
            //将回推的xml参数转换为HashMap
                Map<String, Object> map = InputStreamUtils.parseXml(request.getInputStream());
                log.info("微信推送消息map:");
                map.forEach((key, value) -> System.out.println(key + " = " + value));
                if (map.size() > 0) {
                    String originalId = map.get("ToUserName").toString();
                    Map<String, Object> eventInfo = (Map<String, Object>) map.get("PublishEventInfo");
                    if(eventInfo!=null){
                        String publishId = eventInfo.get("publish_id").toString();
                        Integer publishStatus = Integer.valueOf(eventInfo.get("publish_status").toString());
                        if (publishStatus == 0) {
                        //成功
                        //公众号文章链接
                            String articleUrl = eventInfo.get("article_detail").toString();
                            String url = articleUrl.substring(2);
                            String newUrl = null;
                            //这里需要注意:回推的文章链接是http的,在外部是访问不到的,需要转成https
                            if(url.contains("http") && !url.contains("https")){
                                newUrl = url.replace("http", "https");
                            }
                            
                        }else if(publishStatus == 2){
                            //失败
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            //处理完成后将echostr回推给微信
            return echostr;
        }
        return null;
    }

ShaUtils工具类

import java.security.MessageDigest;

public class ShaUtils {

    public static String getSha1(String str) {

        char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
                'a', 'b', 'c', 'd', 'e', 'f' };
        try {
            MessageDigest mdTemp = MessageDigest.getInstance("SHA1");
            mdTemp.update(str.getBytes("UTF-8"));
            byte[] md = mdTemp.digest();
            int j = md.length;
            char buf[] = new char[j * 2];
            int k = 0;
            for (int i = 0; i < j; i++) {
                byte byte0 = md[i];
                buf[k++] = hexDigits[byte0 >>> 4 & 0xf];
                buf[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(buf);
        } catch (Exception e) {
            return null;
        }
    }

}

InputStreamUtils工具类

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class InputStreamUtils {

// 将输入流使用指定编码转化为字符串
    public static String inputStream2String(InputStream inputStream, String charset) throws Exception {
        if (inputStream == null){
            return null;
        }
        // 建立输入流读取类
        InputStreamReader reader = new InputStreamReader(inputStream, charset);
        // 设定每次读取字符个数
        char[] data = new char[512];
        int dataSize = 0;
        // 循环读取
        StringBuilder stringBuilder = new StringBuilder();
        while ((dataSize = reader.read(data)) != -1) {
            stringBuilder.append(data, 0, dataSize);
        }
        return stringBuilder.toString();
    }

    @SuppressWarnings("unchecked")
    public static Map<String, Object> parseXml(InputStream inputStream) throws Exception {
        if (inputStream == null){
            return null;
        }
        Map<String, Object> map = new HashMap();// 将解析结果存储在HashMap中
        SAXReader reader = new SAXReader();// 读取输入流
        Document document = reader.read(inputStream);
        Element root = document.getRootElement();// 得到xml根元素
        java.util.List<Element> elementList = root.elements();// 得到根元素的所有子节点
        for (Element e : elementList) {        // 遍历所有子节点
            System.out.println("解析key:"+e.getName());
            System.out.println("解析val:"+e.getText());
            //解析子节点
            if(e.elements()!=null && e.elements().size()>0){
                Iterator iterator1 = e.elementIterator();
                Map<String, Object> children = new HashMap();
                while (iterator1.hasNext()){
                    Element stuChild = (Element) iterator1.next();
                    children.put(stuChild.getName(), stuChild.getStringValue());
                    System.out.println("节点名:"+stuChild.getName()+"---节点值:"+stuChild.getStringValue());
                }
                map.put(e.getName(), children);
            }else{
                map.put(e.getName(), e.getText());
            }
        }
        inputStream.close();        // 释放资源
        inputStream = null;
        return map;
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/752535.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

蛙色Web3D编辑器全面更新,会员能力解析

导语&#xff1a; 在数字化时代&#xff0c;创意设计和虚拟展示成为了营销领域的关键。然而&#xff0c;传统的创作方式往往需要复杂的软件和技术支持&#xff0c;给用户带来了诸多麻烦。 幸运的是&#xff0c;蛙色Web3D编辑器作为一款领先的在线编辑工具&#xff0c;通过全面…

Sentieon | 每周文献-Epidemiology-第五期

流行病学系列文章-1 标题&#xff08;英文&#xff09;&#xff1a;Rare Variants in Inborn Errors of Immunity Genes Associated With Covid-19 Severity标题&#xff08;中文)&#xff1a;与Covid-19严重程度相关的免疫基因先天性缺陷的罕见变异发表期刊&#xff1a;《Fron…

背包问题学习笔记

笔记&#xff0c;不是博客&#xff0c;所以就只是粗略的写写 背包问题状态设置 1.小于等于某值&#xff0c;一般用于求在限制背包体积内的情况求解 状态设置 F(n) 表示此时的背包体积小于等于n&#xff0c;F数组初始化为0即可 例题&#xff1a;423. 采药 - AcWing题库 2.恰…

用Python采用Modbus-Tcp的方式读取485电子水尺数据

README.TXT 2023/6/15 V1.0 实现了单个点位数据通信、数据解析、数据存储 2023/6/17 V2.0 实现了多个点位数据通信、数据解析、数据存储 2023/6/19 V2.1 完善log存储&#xff0c;仅保留近3天的log记录&#xff0c;避免不必要的存储&#xff1b;限制log大小&#xff0c;2MB。架…

C#生成类库dll以及调用实例

本文讲解如何用C#语言生成类库并用winform项目进行调用 目录 创建C#类库项目 Winform调用dll 创建C#类库项目 编写代码 using System.Threading;namespace ClassLibrary1 {public class Class1{private Timer myTimer = null;//定义定时器用于触发事件//定义公共的委托和调…

HW5300V3-ISCSI存储运维,看这一篇就够了01——流程图

一、存储使用流程图 二、块存储-配置流程图

【Hippo4j源码的方式安装部署教程】

&#x1f680; 线程池管理工具-Hippo4j &#x1f680; &#x1f332; AI工具、AI绘图、AI专栏 &#x1f340; &#x1f332; 如果你想学到最前沿、最火爆的技术&#xff0c;赶快加入吧✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;CSDN-Java领域优质创作者&#…

Vue3 + Ts + Vite —— 项目封装使用交互式 彩屑纷飞 示例 (亲测可用、复制即展示)

目录 &#x1fa82; 演示 &#x1f6f9; 目录树 &#x1f414; 安装 &#x1f916; global.d.ts &#x1f637; zkConfettiCanvas.vue &#x1f30d; confetti.ts &#x1f38b; confettiIndex.ts &#x1f637; index.vue &#x1f970;&#x1f609; 谢谢观看 &…

哪款蓝牙耳机通话清楚,几款拥有通话降噪技术的骨传导耳机分享

嘿&#xff0c;你是音乐爱好者吗&#xff1f;还是热衷于锻炼身体&#xff1f;那么你一定不能错过骨传导耳机&#xff01;这种神奇的耳机通过骨头的振动来传递声音&#xff0c;绝不同于传统的耳道或鼓膜传播方式。你可保持对周围环境的警觉&#xff0c;同时避免对你的听力造成任…

【雕爷学编程】Arduino动手做(149)---MAX9814咪头传感器模块5

37款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&am…

【unity实战】手搓一个网格放置功能,及装修建造种植功能(2d3d通用,附源码)

文章目录 前言开始项目和素材1. 素材来源2. 开始项目包&#xff08;两种选择一种下载导入即可&#xff09; 开始1. 修改鼠标指针显示2. 给鼠标对应的平面位置绑定对应的指示器3. 使用Shader Graph创建网格可视化3. 网格的大小缩放和颜色控制4. 优化5. 扩展说明5.1 我们就可以通…

总结:WEB流量劫持

一、背景 在整理WEB鉴权与登陆等技术的时候&#xff0c;会涉及到安全&#xff0c;而鉴权登陆不安全有个很大的可能就是流量被劫持了。 本篇文章主要是想弄明白黑客是怎么劫持的。 二、WEB流量劫持是如何做到的&#xff1f; WEB流量劫持是指黑客将受害者的网页请求重定向到攻…

python appium UI 自动化测试框架讨论

目录 前言&#xff1a; 框架共性总结 Auto_Analysis 权限弹窗识别 前言&#xff1a; Python Appium UI自动化测试框架是一种用于测试移动应用程序的工具&#xff0c;它结合了Python编程语言和Appium测试框架的功能。 框架共性总结 1 自动找设备 连接设备 2 自动启 appium …

Java设计模式之行为型-状态模式(UML类图+案例分析)

目录 一、基础概念 二、UML类图 三、角色设计 四、案例分析 五、总结 一、基础概念 状态模式允许一个对象在其内部状态改变时改变它的行为&#xff0c;对象看起来似乎修改了它的类&#xff0c;状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况&a…

有必要买apple pencil吗?ipad pencil替代品

苹果的电容笔与一般的电容笔有什么不同&#xff1f;事实上&#xff0c;从外观上来看&#xff0c;两者并没有太大的区别。唯一不同的是&#xff0c;苹果电容笔的重量更大&#xff0c;笔尖内部有专门的重力感应器&#xff0c;可以感应到重力压感对线条的影响。因此苹果的这个产品…

MongoDB复制集

文章目录 一、介绍1、存在的意义和作用&#xff1f;2、需要实现啥功能&#xff1f;3、典型案例4、注意事项 二、搭建1、安装MongoDB&#xff0c;配置环境变量2、创建数据目录3、配置文件4、启动 MongoDB 进程5、配置复制集6、验证 三、写策略writeConcern1、w参数2、j参数2.1 介…

《如何使用思维导图进行知识结构的建立和扩展》

I.思维导图作为知识管理工具的重要性 思维导图是一款强大的效率工具&#xff0c;可以帮助有效的管理知识。”一图胜千言“它用图形的方式&#xff0c;将各个主题连接起来。我们可以清晰的了解到各主题之间的关系。 在知识管理中&#xff0c;通过创建一个知识主题的中心&#xf…

PVE虚拟化平台之安装Ubuntu-server系统

PVE虚拟化平台之安装Ubuntu-server系统 一、Ubuntu介绍1.1 Ubuntu简介1.2 Ubuntu版本1.3 ubuntu命名规则 二、上传镜像到PVE存储2.1 检查PVE环境2.2 上传镜像 三、创建虚拟机3.1 设置虚拟机名称3.2 操作系统设置3.3 系统设置3.4 磁盘设置3.5 cpu设置3.6 内存设置3.7 网络设置3.…

libvirt 热迁移流程及参数介绍

01 热迁移基本原理 1.1 热迁移概念 热迁移也叫在线迁移&#xff0c;是指虚拟机在开机状态下&#xff0c;且不影响虚拟机内部业务正常运行的情况下&#xff0c;从一台宿主机迁移到另外一台宿主机上的过程。 1.2 虚拟机数据传输预拷贝和后拷贝 预拷贝(pre-copy)&#xff1a; …

3、wampserver中查看各项当前版本及简单配置PHP

wampserver点击左键&#xff0c;即可查看Apache&#xff0c;PHP&#xff0c;MySQL&#xff0c;MariaDB的当前版本 在wampserver的安装目录中&#xff0c;在相应的D:\wamp64\bin\php\php8.0.26 php.ini文件中&#xff0c;short_open_tag On&#xff08;是否允许使用 PHP代码开…