微信公众号开发(一)——开发模式接入,消息的接收与响应

2023-11-15

微信公众号

1

想自己开一个公众号,先学习一下用 Java 进行微信公众号的开发。

微信公众号的管理有开发模式和编辑模式两种,两者是互斥的。

腾讯是这么讲的:

编辑模式:编辑模式指所有的公众号运营者都可以通过简单的编辑,设置“按关键字回复”等功能。您可以设定常用的文字/语言/图片/录音作为回复消息,并制定自动回复的规则。当订阅用户的行为符合自动回复规则的时候,就会收到自动回复的消息。

开发模式:开发模式是为开发者提供与用户进行消息交互的能力。对于成功接入消息接口的公众账号,当用户发消息给公众号,微信公众平台服务器会使用http请求对接入的网址进行消息推送,第三方服务器可通过响应包回复特定结构,从而达到回复消息的目的。

所以接下来要讲的是如果使用微信的开发模式。

2 准备工作

微信的开发模式如果要调用他的接口需要微信认证300元。微信有公共平台测试号:

开发 — 开发者工具 — 公众号平台测试账号

地址映射工具

微信的 URL 要求必须是: http:// 80端口,且必须是能够在公网访问的,本地的不行。所以这里用到一个映射工具叫做 ngrok 。下载之后使用,cmd

ngrok http 8080

这里写图片描述

3 开发者模式接入

准备完毕开始开发,包结构如下:

包结构

开发者模式接入

通过 servlet 的 GET 请求进行校验

校验参数

微信需要对以上四个参数进行校验,将 timestamp,nonce,token 三者排序拼接成字符串,再进行 Sha1 加密之后,如果和 signature 相同则表示校验通过:

public static boolean checkSignature(String signature,String timestamp,String nonce){
        //排序
        String[] arr = new String[]{token,timestamp,nonce};
        Arrays.sort(arr);

        //生成字符串
        StringBuffer content = new StringBuffer();
        for(int i = 0; i < arr.length; i++){
            content.append(arr[i]);
        }

        //sha1 加密 java实现消息摘要加密
        String temp = getSha1(content.toString());

        //和微信传递过来的参数进行校验
        return temp.equals(signature);
    }

sha1加密

public static String getSha1(String str) {
        if (str == null || str.length() == 0) {
            return null;
        }
        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;
        }
    }

进行校验的servlet

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //验证消息的确来自微信服务器 校验四个参数
        String signature = request.getParameter("signature"); //微信加密签名
        String timestamp = request.getParameter("timestamp"); //时间戳
        String nonce = request.getParameter("nonce"); //随机数
        String echostr = request.getParameter("echostr"); //随机字符串

        PrintWriter out = response.getWriter();
        if(CheckUtil.checkSignature(signature, timestamp, nonce)){
            out.print(echostr);
        }
    }

配置web.xml

<servlet>
    <servlet-name>weixinServlet</servlet-name>
    <servlet-class>com.shuiyujie.servlet.WeiXinServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>weixinServlet</servlet-name>
    <url-pattern>/wx.do</url-pattern>
  </servlet-mapping>

访问效果

访问是500,说明已经通了。接下来用 ngrok 映射工具生成映射地址,到公网上去访问看看行不行,这个在前面讲过不做演示。

在访问成功之后,对微信中的服务器配置进行填写提交。

配置成功

可以提交并且启用开发模式了,启用了开发模式则编辑模式下的配置全部失效。

4 消息的接收与响应

图片来自与网络
图片来自于网络

数据交互的过程如上图所示,通过 Post 请求进行。根据请求类型的不同,微信规定了不同的参数,并且通过 XML 的格式进行传递。通过查看开发文档,我们就可以了解所需要的参数。又由于是通过 XML 的格式传递的,为了便于后台程序的解析,所以将 XML 装换成集合类型。

4.1 文本消息的 PO 类

参数列表

通过微信文档可以知道,文本消息传递的参数列表如上图所示,所以要新建一个 Po 类。

public class TextMessage {
        private String ToUserName;
        private String FromUserName;
        private long CreateTime;
        private String MsgType;
        private String Content;
        private String MsgId;

添加 get, set方法

4.2 XML 和集合互相转换的工具类

XML 转集合

public static Map<String,String> xmlToMap(HttpServletRequest request) throws IOException, DocumentException{

        Map<String,String> map = new HashMap<String,String>();
        SAXReader reader = new SAXReader();

        InputStream ins = request.getInputStream();
        Document doc = reader.read(ins);

        //获取根节点
        Element root = doc.getRootElement();

        List<Element> list = root.elements();

        for(Element e : list){
            map.put(e.getName(), e.getText());
        }
        ins.close();

        return map;
    }

文本信息转 XML

public static String textMessageToXml(TextMessage textMessage){
        XStream xstream = new XStream();
        xstream.alias("xml", textMessage.getClass());
        return xstream.toXML(textMessage);
    }

servlet doPost 接收响应

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        PrintWriter out = response.getWriter();
        try {
            Map<String,String> map = MessageUtil.xmlToMap(request);
            String fromUserName = map.get("FromUserName");
            String toUserName = map.get("ToUserName");
            String msgType = map.get("MsgType");
            String content = map.get("Content");

            String message = null;
            if("text".equals(msgType)){
                TextMessage text = new TextMessage();
                text.setFromUserName(toUserName); //原来的信息发送者,将变成信息接受者
                text.setToUserName(fromUserName); //原理的接受者,变成发送者
                text.setMsgType("text"); //表示消息的类型是text类型
                text.setCreateTime(new Date().getTime());
                text.setContent("您发送的信息是:" + content);
                message = MessageUtil.textMessageToXml(text); //装换成 xml 格式发送给微信解析

                System.out.println(message);
            }
            out.print(message);
        } catch (DocumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

接下来需要启动 tomcat 运行程序。

效果图

这样消息回复的效果已经完成了,最后来让他能够接收更多类型的消息。比如常见的一些:关注后的消息回复,取消关注之后的消息回复,还有关键字的消息回复

5 更多接收消息

由于会接收多种消息类型,修改 MessageUtil 消息工具类,为了方便把常用的消息类型都定义成常量,并且将需要回复的消息,例如关注之后回复的消息,关键词回复的消息都定义好

定义常量

public class MessageUtil {  

    public static final String MESSAGE_TEXT = "text";
    public static final String MESSAGE_NEWS = "news";
    public static final String MESSAGE_IMAGE = "image";
    public static final String MESSAGE_VOICE = "voice";
    public static final String MESSAGE_MUSIC = "music";
    public static final String MESSAGE_VIDEO = "video";
    public static final String MESSAGE_LINK = "link";
    public static final String MESSAGE_LOCATION = "location";
    public static final String MESSAGE_EVNET = "event";
    public static final String MESSAGE_SUBSCRIBE = "subscribe";
    public static final String MESSAGE_UNSUBSCRIBE = "unsubscribe";
    public static final String MESSAGE_CLICK = "CLICK";
    public static final String MESSAGE_VIEW = "VIEW";
    public static final String MESSAGE_SCANCODE= "scancode_push";
/**
     * 拼接文本消息
     * @param toUserName
     * @param fromUserName
     * @param content
     * @return
     */
    public static String initText(String toUserName,String fromUserName,String content){
        TextMessage text = new TextMessage();
        text.setFromUserName(toUserName);
        text.setToUserName(fromUserName);
        text.setMsgType(MessageUtil.MESSAGE_TEXT);
        text.setCreateTime(new Date().getTime());
        text.setContent(content);
        return textMessageToXml(text);
    }

    /**
     * 关注回复
     * @return
     */
    public static String menuText(){
        StringBuffer sb = new StringBuffer();
        sb.append("欢迎关注公众号弄浪的鱼:\n\n");
        sb.append("1 回复关键字1\n");
        sb.append("2 回复关键字2\n");
        sb.append("3 回复关键字3\n\n");
        sb.append("本公众号还在开发中,没啥能看的,别玩坏了哈~~");
        return sb.toString();
    }

servlet对接收到的消息进行判断并作出响应

protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        PrintWriter out = response.getWriter();
        try {
            Map<String, String> map = MessageUtil.xmlToMap(request);
            String fromUserName = map.get("FromUserName");
            String toUserName = map.get("ToUserName");
            String msgType = map.get("MsgType");
            String content = map.get("Content");

            String message = null;

            if (MessageUtil.MESSAGE_TEXT.equals(msgType)) {
                if ("1".equals(content)) {
                    message = MessageUtil.initText(toUserName, fromUserName, MessageUtil.firstMenu());
                } else if ("2".equals(content)) {
                    message = MessageUtil.initText(toUserName, fromUserName, MessageUtil.secondMenu());
                } else if ("3".equals(content)) {
                    message = MessageUtil.initText(toUserName, fromUserName, MessageUtil.threeMenu());
                } else if ("?".equals(content) || "?".equals(content)) {
                    message = MessageUtil.menuText();
                }
            } else if (MessageUtil.MESSAGE_EVNET.equals(msgType)) {// 事件推送
                String eventType = map.get("Event"); // 事件分成多种,分别判断处理
                if (MessageUtil.MESSAGE_SUBSCRIBE.equals(eventType)) { // 这里先写一个关注之后的事件
                    message = MessageUtil.initText(toUserName, fromUserName, MessageUtil.menuText());
                }
            }

            System.out.println(message);

            out.print(message);
        } catch (DocumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

成功

以上,关注回复和关键词回复成功。

最后再把微信程序部署到服务器上就可以正常访问了,下一篇就总结怎么部署到阿里云。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

微信公众号开发(一)——开发模式接入,消息的接收与响应 的相关文章

随机推荐

  • 新手如何使用pycharm

    开启coding之旅 我在写代码的时候 我总是因为安装包和环境的问题 代码总是bug不断 短段的两天时间 我整天扑在上面研究 不断地抓头 短段两天 我感觉我的头发都凸了一点了 后来我实在解决不了 于是直接付费请教别人帮我装机 就为了完成最简
  • Jenkins 设置镜像_在k8s上安装Jenkins及常见问题

    持续集成和部署是DevOps的重要组成部分 Jenkins是一款非常流行的持续集成和部署工具 最近试验了一下Jenkins 发现它是我一段时间以来用过的工具中最复杂的 一个可能的原因是它需要与各种其它工具集成才能完成任务 而集成的方法又各不
  • XML转JavaBean的简单实现

    一个基于JSON的简单的XML转为Bean的方法 之前在做一个WEB SERVICE的交互的时候 写的一个基于JSON的XML转Bean的方法 就把它整理处理 如下 gt pom xml 所有需要的依赖包如下
  • 使用ChatGPT自动编写Python爬虫脚本

    都知道最近ChatGPT聊天机器人爆火 我也想方设法注册了账号 据说后面要收费了 ChatGPT是一种基于大语言模型的生成式AI 换句话说它可以自动生成类似人类语言的文本 把梳理好的有逻辑的答案呈现在你面前 这完全不同于传统搜索工具 Cha
  • Unity Mesh网格编程(三) Shader实现水面或旗帜飘扬效果

    Upgrade NOTE replaced Object2World with unity ObjectToWorld Upgrade NOTE replaced mul UNITY MATRIX MVP with UnityObjectT
  • 【Unity3D小功能】Unity3D中实现UI擦除效果、刮刮卡功能

    推荐阅读 CSDN主页 GitHub开源地址 Unity3D插件分享 简书地址 我的个人博客 大家好 我是佛系工程师 恬静的小魔龙 不定时更新Unity开发技巧 觉得有用记得一键三连哦 一 前言 使用Unity3D实现UI的擦拭效果 刮刮卡
  • php图片居中显示图片,CSS实现图片居中的三种方式

    在我们的WEB前端css开发过程中 我们避免会遇到让图片居中的情况 为了网页美观以及用户的体验 我们有时候就要让图片居中 那么我们也都知道图片居中的方法有很多 今天我们就给大家详细介绍下CSS实现图片居中的三种方式 1 利用display
  • Docker入门命令

    文章目录 1 安装Docker 2 搜索 下载镜像 3 查询本地镜像 4 启动镜像到容器 5 查询已启动镜像 容器 6 进入容器环境 7 创建镜像 7 1 基于已有镜像的容器创建 7 2 基于本地模板导入 7 3 基于Dockerfile创
  • AI绘图:教你几个提示词 100%生成美丽小姐姐

    许多常用提示对于确保高质量的成像结果至关重要 我们将教您一些基本的提示词和设置 以节省您在初始探索过程中的时间 本次用到的模型ChilloutMix 基础设置 默认设置包括图片 大小 512 x 512 采样器 DPM SDE Karras
  • 逆序栈(使用递归)

    题目 一个栈依次压入1 2 3 4 5那么从栈顶到栈底分别为5 4 3 2 1 将这个栈转置后 从栈顶到栈底为1 2 3 4 5 也就是实现了栈中元素的逆序 请设计一个算法实现逆序栈的操作 但是只能用递归函数来实现 而不能用另外的数据结构
  • springBoot添加自定义拦截器

    文章目录 前言 步骤如下 首先新建一个自己的拦截器 其次 把自己的拦截器注册到spring中 让其生效 前言 新的项目需要校验用户是否登录 在springBoot项目中添加一个自定义的拦截器拦截到所有请求进行逻辑判断 步骤如下 首先新建一个
  • 资讯汇总230429

    230429 11 44 大华股份 重点投入大模型和多模态方向 会持续按需扩容算力 大华股份在业绩说明会表示 GPT 的发展具有里程碑式的意义 公司会重点投入大模型和多模态方向 过去在大模型领域的算法和工程能力已经有一定的积累 先进技术研究
  • 内行看门道:看似“佛系”的《QQ炫舞手游》,背后的音频技术一点都不简单

    欢迎大家前往腾讯云 社区 获取更多腾讯海量技术实践干货哦 本文由腾讯游戏云发表于云 社区专栏 内行看门道 看似 佛系 的 QQ炫舞手游 背后的音频技术一点都不简单 3月14日 腾讯旗下知名手游 QQ炫舞 正式上线各大应用商店 并迅速登上Ap
  • 卡尔曼滤波与目标跟踪(由cv模型的kf推理到CTRV模型的radar与lidar))(一)

    引用AdamShan 引用知乎陈光 基于cv模型的行人状态预测 卡尔曼滤波与目标追踪 卡尔曼的理论 一 初始化 我们认为小车在第1秒时的状态x与测量值z相等 二 预测 Prediction 完成初始化后 我们开始写Prediction部分的
  • Ubuntu20.04安装各种库----简洁版

    目录 Eigen3 Sophus Pangolin Ceres g2o 建议先装anaconda再装ros python opencv啥该有的都有了 下面仅仅安装ros没有的库 Eigen3 作用 线性代数开源库 提供了有关线性代数 矩阵和
  • 汽配企业如何利用MES管理系统解决生产防错难题

    汽车配件制造业是一个高效率 低成本 高质量的生产领域 但同时也面临着一系列的挑战 其中最为突出的挑战之一是如何在生产过程中避免错误 提高产品的合格率 本文将介绍汽车配件的制造特点以及如何通过MES管理系统解决方案实现生产防错 从而提高产品合
  • 爬虫逆向(js逆向)

    异步爬虫的实现方式 线程池 多任务的异步协程 多线程 生产者消费者模型 线程池 前提 from flask import Flask render template from time import sleep app Flask name
  • 【NLP】文本聚类和主题建模

    大家好 我是Sonhhxg 柒 希望你看完之后 能对你有所帮助 不足请指正 共同学习交流 个人主页 Sonhhxg 柒的博客 CSDN博客 欢迎各位 点赞 收藏 留言 系列专栏 机器学习 ML 自然语言处理 NLP 深度学习 DL fore
  • Chrome浏览器更新之后在开发者工具中查看格式化后的js不显示行号问题

    最近更新了谷歌浏览器 然后在调试代码的时候发现一个问题 就是当js代码是压缩后的 将其格式化之后就只显示压缩之前的行号了 如下 未格式化的 格式化之后 这样就很无语了 突然没有了行号就很不习惯了 经过在浏览器设置里面一番找之后终于找到设置这
  • 微信公众号开发(一)——开发模式接入,消息的接收与响应

    1 想自己开一个公众号 先学习一下用 Java 进行微信公众号的开发 微信公众号的管理有开发模式和编辑模式两种 两者是互斥的 腾讯是这么讲的 编辑模式 编辑模式指所有的公众号运营者都可以通过简单的编辑 设置 按关键字回复 等功能 您可以设定