【公众号开发】如何写出第一个公众号开发程序 · 动态自定义自动回复

【公众号开发】(1)

在这里插入图片描述

【公众号开发】(1)

公众号的使用和作用不必多说,很多企业都会选择公众号这种与客户粘性大的方式去推广自己或者其他的动作…

而本专栏主要讲解的就是公众号的基本开发,不囊括所有,但是可以从0到1,之后的1生万物由你完成!

我这里不列举公众号开发能咋开发,你可以查看开发者文档:开发前必读 / 首页 (qq.com)

在这里插入图片描述

这些是微信公众号自带的功能,但我们要满足我们自己的需求,当然是需要进行开发的

这些功能就是字面意思~

本专栏已开发为主,很少有理论的讲解,直接进入实战吧,公众号有啥功能我们可以开发,进入实战即可见分晓~

1. 获得一个测试号

正式的公众号的申请需要门槛,所以为了方便我们开发者上手,专门有一个“接口测试公众号”用来练习,只不过没有一些高级的接口,这些无伤大雅,有了基础就可以去学习高级接口了

开始开发 / 接口测试号申请 (qq.com)

在这里插入图片描述

按照指引注册即可,如果已经注册,登录微信即可

  • 由于是测试号,还不能登录公众号后台管理平台~
    • 所以没有那些现成的公众号提供的一些固定的操作~
  • 这个之后申请正式的公众号去登录用一用就会了~

在这里插入图片描述

这些消息可能你会有一些没有,不过没关系,之后慢慢展开

在这里插入图片描述

  • 用你的手机扫码关注后,你将在右侧看到你的关注用户

在这里插入图片描述

  • 这个之后再说

在这里插入图片描述

  • 这些就是测试号的体验的接口总览咯,使用上限,点击链接跳转到对于的开发手册页面
    • 需要就学即可
  • 我不会全讲也不会按顺序讲~

2. 公众号开发原理

在这里插入图片描述

大概就是这样的,微信公众号并不是什么功能都能实现,只能实现一些公众号提供的接口(就是刚才那些)

因为用户并不是直接访问开发者,开发者也不是直接响应给用户,微信公众号提供较为统一的页面给用户,和较为统一的接口给开发者

这样的介入,提高公众号的统一性,用户可以依照经验使用,又有公众号的特性,提供的接口给开发者开发自定义!

  • 功能的限制,对用户的请求和返回的响应需要经过公众号的检验,也提高微信的安全性和健康性

3. 创建开发者服务器

我们先创建一个项目(SpringBoot),作为开发者服务器

在这里插入图片描述

这里就是创建好的了

  1. 我导入了lombok依赖(在一开始选上就好)

  2. 我的配置文件为application.yml:

    spring:
      application:
        name: 微信公众号测试 # 项目的名称
      output:
        ansi:
          enabled: ALWAYS # 配置控制台输出的效果,彩色
      # JSON序列化配置
      jackson:
        date-format: yyyy-MM-dd HH:mm:ss # ⽇期格式
        default-property-inclusion: NON_NULL # 不为null序列化
    server:
      port: 8080
    
    logging:
      pattern:
        dateformat: MM-dd HH:mm:ss # 日期显示格式
      level:
        root: info # 日志默认级别
      file:
        path: D:/log/project/wx
    

4. 内网穿透

由于微信公众号服务器在千里之外,要想访问我们的开发者服务器,必然是要通过外网去访问的,所以我们需要一个外网ip!

  1. 云服务器
  2. 内网穿透工具

首先,云服务器是必然的,最终一定是要部署到云服务器去维持服务,但是我们开发阶段,频繁的修改和测验,云服务器的方式太麻烦了,所以我们要用内网穿透工具,将我们的内网映射成外网,让外接可以访问!

官网:NATAPP-内网穿透 基于ngrok的国内高速内网映射工具

在这里插入图片描述

在这里插入图片描述

安装到本地,并解压缩,到达natapp.exe的所在目录下:

在这里插入图片描述

右键在命令行打开:

在这里插入图片描述

回到官网注册/登录

在这里插入图片描述

这两项去做一下:

在这里插入图片描述

购买免费隧道:

在这里插入图片描述

进入配置页:

在这里插入图片描述

可以看到刚才的信息了,复制authtoken(等一下要用):

在这里插入图片描述

回到命令行输入(authtoken输入自己的):

./natapp -authtoken=72810d6d1ab6e1fe

这个就是映射的地址(综合了ip与端口的字符串):

在这里插入图片描述

不过注意的是,按ctrl c或者直接关闭或者断网或者电脑睡眠、关机(甚至你没有关闭,过一段时间就变了),这个字符串的映射就失效了,并且下次生成的也不一样哦!

  • 所以,有时候公众号访问不了,那就是这个字符串变了;之后正式公众号和部署到云服务就不会出现这种情况了

在这里插入图片描述

我们写一个接口,检测一下这个字符串是否有效:

在这里插入图片描述

浏览器访问:

在这里插入图片描述

命令行有请求的记录:

在这里插入图片描述

5. 验证开发者服务器的url

其实就是这个地方的接口配置设置:

在这里插入图片描述

点击修改:

  • URL为刚才的内网穿透的字符串
  • Token为自定义令牌字符串

在这里插入图片描述

但是点击提交后,并不会显示成功:

在这里插入图片描述

这是因为微信公众号服务器要确保这个url是开发者的url,有这些好处(我认为):

  1. 这个可以先将地址访问问题单独拎出来,如果通过,那么以后发生的问题就不会是地址的问题(除非你的外网ip变了)
  2. 这个令牌Token只有公众号和开发者知道,开发者可以通过这个验证这个请求来自微信公众号服务器,保证信息安全

具体是啥原因,太底层不需要了解,我们“坐享其成,遵循规矩”

在这里插入图片描述

点击提交:

在这里插入图片描述

但是你现在纳闷了,“凭什么我不行?”,这是因为你的服务器并没有进行相关操作~

5.1 公众号服务器对url发送get请求

公众号会对我们填写的url的根目录(就是后面不带路由,也就是/)发送一个GET请求,这个请求的目的就是验证

但是浏览器访问是这样的:

在这里插入图片描述

原因是缺少参数,我们可以在开发者文档查看:开始开发 / 接入指南 (qq.com)

5.2 消息的验证逻辑

重点看这里:

在这里插入图片描述

他的意思就是,他的请求携带了这四个参数,而我们开发者如果返回echostr这个回显字符串的话,那么就是验证成功,公众号也就确认你是,并且授权了,所以就可以匹配成功

那么我们要咋样才可以返回echostr呢?

原理就是:

在这里插入图片描述

这里 Token是只有公众号和开发者知道

所以以此与timestamp和nonce拼接之后的字符串, 加密之后的字符串作为建议身份的标志 非常合理科学

一般加密是不可逆的,所以我们并没有办法将signature解密出Token,而是将 加密出一个字符串与之对比!

加密算法:

  1. timestamp、nonce、Token按字典序排列
  2. 将排列后的字符串进行拼接
  3. 将拼接字符串进行加密(加密结果为字节数组
  4. 字节数组每个字节按照十六进制进行拼接

最后,加密拼接字符串与signature进行比较

5.3 代码实现

所需依赖

<dependency>
   <groupId>org.dom4j</groupId>
   <artifactId>dom4j</artifactId>
   <version>2.1.3</version>
</dependency>
@GetMapping("/")
public String check(@RequestParam("signature") String signature,
                    @RequestParam("timestamp") String timestamp,
                    @RequestParam("nonce") String nonce,
                    @RequestParam("echostr") String echostr) {
    if(!StringUtils.hasLength(signature) || !StringUtils.hasLength(timestamp)
            || !StringUtils.hasLength(nonce) || !StringUtils.hasLength(echostr)) {
        return "";
    }
    // 1) 将token 、 timestamp 、 nonce 三个参数进行字典序排序
    String token = "maras103";
    String[] list = {token, timestamp, nonce};
    Arrays.sort(list);
    // 2) 将三个字符串以此顺序进行拼接
    StringBuilder builder = new StringBuilder();
    for(String s : list) {
        builder.append(s);
    }
    // 2.1) 加密
    try {
        MessageDigest messageDigest = MessageDigest.getInstance("sha1");
        byte[] digest = messageDigest.digest(builder.toString().getBytes(StandardCharsets.UTF_8));
        // 2.2) 将加密后的byte数组转换为signature一样的格式(每个字节都转换为十六进制进行拼接)
        builder = new StringBuilder();
        for(byte b : digest) {
            // builder.append(Integer.toHexString(b));不能这么弄因为这样弄b如果是负,那么就凉凉
            // 这样写保证两位十六进制都存在并且正确
            builder.append(Integer.toHexString((b >> 4) & 15));//前四个字节转换为十六进制
            builder.append(Integer.toHexString(b & 15));//后四个字节转换为十六进制
        }
    } catch (NoSuchAlgorithmException e) {
        throw new RuntimeException(e);
    }
    // 3) 核对请求是否来自于微信(加密解析后的字符串与signature比较)
    if(builder.toString().equals(signature)) {
        // 相同才返回回显字符串
        // 并且返回echostr代表开发者确认了这是公众号服务器发来的请求,公众号就进行配置
        return echostr;
    } else {
        // 否则返回null
        return null;
    }
}

在这里插入图片描述

6. 接受并解析用户发来的消息

用户有时候会发一些消息给公众号,那我们的服务器怎么针对这些消息做出一些自定义的动作呢?

原理是这样的

  • 具体参考开发者文档,我这里直接说了

在这里插入图片描述

当用户发消息给公众号:

在这里插入图片描述

就相当于发请求给微服务公众号服务器,访问了它的一个接口,微信公众号就会打包我们的数据构造post请求访问我们的开发者服务器(根路径/

并且是以xml的格式!

6.1 查看post请求的数据格式

获取请求的输入流对象,读取数据

@PostMapping("/")
public String receiveMessage(HttpServletRequest request) throws IOException {
    ServletInputStream inputStream = request.getInputStream();
    byte[] b = new byte[1024];
    int len = 0;
    while((len = inputStream.read(b)) != -1) {
        System.out.println((new String(b, 0, len)));
    }
    return "";
}

注意:返回空字符串,代表什么都不回~

我们向公众号发一条消息:

在这里插入图片描述

在这里插入图片描述

6.2 解析xml字符串

@PostMapping("/")
public String receiveMessage(HttpServletRequest request) throws IOException {
    Map<String, String> map = new HashMap<>();
    SAXReader reader = new SAXReader();
    // xml字符串解析方法
    try {
        //通过请求的输入流,获取Document对象
        Document document = reader.read(request.getInputStream());
        // 获取root节点
        Element root = document.getRootElement();
        // 获取所有子节点
        List<Element> elements = root.elements();
        // 遍历集合
        for(Element e : elements) {
            map.put(e.getName(), e.getStringValue());
        }
        log.info(map.toString());
    } catch (DocumentException e) {
        throw new RuntimeException(e);
    }
    return "";
}

在这里插入图片描述

查看日志:
在这里插入图片描述

解析成功~

6.3 将xml字符串解析结构构造回复消息

注意:回复消息字符串必须是xml字符串格式,否则微信公众号不做任何动作

所需依赖

<dependency>
   <groupId>com.thoughtworks.xstream</groupId>
   <artifactId>xstream</artifactId>
   <version>1.4.11.1</version>
</dependency>
6.3.1 消息对象
@Data
@XStreamAlias("xml")
public class TextMessage {
    @XStreamAlias("ToUserName")
    private String toUserName;

    @XStreamAlias("FromUserName")
    private String fromUserName;

    @XStreamAlias("CreateTime")
    private long createTime;

    @XStreamAlias("MsgType")
    private String msgType;

    @XStreamAlias("Content")
    private String content;
}

在这里插入图片描述

这个对象进行序列化一个对象为xml字符串的时候,默认以类名为父标签,各个属性的属性名为子标签,如果一个属性为自定义类型,则这个对象也是树形结构xml标签嵌套于此xml标签(套娃套娃套娃…)

6.3.2 将map封装成消息对象
public static TextMessage getReplyTextMessage(Map<String, String> map) {
    TextMessage message = new TextMessage();
    message.setToUserName(map.get("FromUserName"));
    message.setFromUserName(map.get("ToUserName"));
    message.setCreateTime(System.currentTimeMillis() / 1000);
    message.setMsgType("text");
    message.setContent("回复" + map.get("Content") + ":就不告诉你");
    return message;
}

这里其实回复的消息可以是很多种(文本、图片、音频等等等…)

  • 复杂的回复体系这里暂时不讲,之后业务上做好分支即可~

(这里简单的回复个文本消息)

(发起者和接收者的username进行调换)

(时间戳是秒级别为当前时间)

6.3.3 将消息对象进行序列化为xml
/**
 * 将TextMessage对象序列化为xml字符串返回
 * @param message
 * @return
 */
public static String getXML(TextMessage message) {
    //获取序列化工具XStream对象
    XStream xStream = new XStream();
    //指定类型
    xStream.processAnnotations(TextMessage.class);
    //转化为xml字符串
    String xml = xStream.toXML(message);
    //返回
    return xml;
}

无非就是调用一些库方法

6.3.4 在controller实现(调用方法)
@PostMapping("/")
public String receiveMessage(HttpServletRequest request) throws IOException {
    //        ServletInputStream inputStream = request.getInputStream();
    //        byte[] b = new byte[1024];
    //        int len = 0;
    //        while((len = inputStream.read(b)) != -1) {
    //            System.out.println((new String(b, 0, len)));
    //        }
    Map<String, String> map = new HashMap<>();
    SAXReader reader = new SAXReader();
    // xml字符串解析方法
    try {
        //通过请求的输入流,获取Document对象
        Document document = reader.read(request.getInputStream());
        // 获取root节点
        Element root = document.getRootElement();
        // 获取所有子节点
        List<Element> elements = root.elements();
        // 遍历集合
        for(Element e : elements) {
            map.put(e.getName(), e.getStringValue());
        }
        log.info(map.toString());
    } catch (DocumentException e) {
        throw new RuntimeException(e);
    }
    // 回复消息
    // 1. 封装对象
    TextMessage textMessage = TextMessage.getReplyTextMessage(map);
    // 2. 序列化对象
    String message = TextMessage.getXML(textMessage);
    System.out.println(message);
    return message;
}

公众号发消息测试:

在这里插入图片描述

成功啦!

我想这么一个用户与公众号交互的程序,让大家对公众号开发有了初步的认知!


文章到此结束!谢谢观看
可以叫我 小马,我可能写的不好或者有错误,但是一起加油鸭🦆

代码:wx-demo · 游离态/马拉圈2023年10月 - 码云 - 开源中国 (gitee.com)


  • 34
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 28
    评论
Python公众号开发是使用Python编程语言开发公众号的应用程序公众号微信平台上的一个重要应用,为用户提供了一个与其互动的平台。Python作为一种简洁、易学且功能强大的编程语言,成为公众号开发的首选之一。 Python公众号开发的主要使用场景可以包括以下几个方面: 1. 自动回复:通过Python开发公众号可以根据用户的消息自动回复相应的内容,可以是文本、图片、音频或视频等。 2. 数据统计分析:Python公众号开发可以通过接入第三方数据服务,实现对用户的统计分析,包括用户关注量、分享量、地域分布等。 3. 定制菜单:通过Python公众号开发,可以实现自定义的菜单功能,用户可以通过菜单点击来执行相应的操作。 4. 推送消息:通过Python公众号开发,可以向用户的微信端推送消息,包括图文消息、模板消息、事件推送等。 5. 数据库操作:通过Python公众号开发,可以连接数据库,实现对用户的信息存储和管理。 在Python公众号开发过程中,一般会使用第三方库和框架来提高开发效率,如Flask、Django、Tornado等。同时,还可以使用微信公众号开发者工具提供的API,进行与微信平台的交互。 总结来说,Python公众号开发是一项非常有前景和实用价值的技术,可以为用户提供个性化、便捷的服务,同时也能帮助企业实现对用户的管理和推广。无论是个人还是企业,学习和掌握Python公众号开发技术都具有重要的意义。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 28
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

s:103

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值