Bootstrap

SpringBoot对接微信公众平台(2)--- 接收普通消息Demo

SpringBoot对接微信公众平台(2)--- 接收普通消息

说明

这里记录下自己学习SpringBoot对接微信公众平台的成长过程,以防止后面继续踩坑且方便以后直接使用。这里使用微信公众号的接口测试号来开发微信公众平台。这里承接自己的博客SpringBoot对接微信公众平台(1)— 配置微信公众平台测试号URL并校检这篇博客,在该博客项目的基础上增加接收普通消息的代码示例。

微信公众号-基础消息能力/接收普通消息:https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_standard_messages.html

后端代码

当用户给微信公众号发送消息时,根据官网给的文档说明,它会去调用之前你在测试号里面配置的URL接口地址,并且是以POST请求方式调用。所以你会在下面的Controller层看到2个/check,一个get的/check接口是用来测试微信公众号能否调用你的接口,一个Post的/check接口是用户给微信公众号发送消息时,会去调用该接口。这个接口才是实际环境中你要的功能接口。
在这里插入图片描述
SpringBoot项目目录如下:
在这里插入图片描述

pom.xml代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>wechat-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>wechat-service</name>
    <description>wechat-service</description>
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.6.13</spring-boot.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <!--web依赖,内嵌入tomcat,RestTempLate使用该依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--用来将string的json格式字符串转换成json对象-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.49</version>
        </dependency>
        <!--lombok依赖,用来对象省略写set、get方法-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
        </dependency>
        <!--解析xml-->
        <dependency>
            <groupId>org.dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>2.1.3</version>
        </dependency>
        <!--用来将string的json格式字符串转换成json对象-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.49</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <configuration>
                    <mainClass>com.example.wechatservice.WechatServiceApplication</mainClass>
                    <skip>true</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

application.yml代码:

server:
  port: 8080

wxChat:
  appID:你的测试公众号appID
  appsecret:你的测试公众号appsecret

config下的RestTemplateConfig配置代码如下:

package com.example.wechatservice.config;

import org.springframework.context.annotation.Bean;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

@Component
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate(){
        RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory());
        return restTemplate;
    }

    // 设置超时时间
    public ClientHttpRequestFactory clientHttpRequestFactory(){
        //创建一个httpClient简单工厂
        SimpleClientHttpRequestFactory factory=new SimpleClientHttpRequestFactory();
        //设置连接超时时间,单位ms
        factory.setConnectTimeout(15000);
        //设置读取超时时间,单位ms
        factory.setReadTimeout(10000);
        return factory;
    }
}

button文件夹下的AbstractButton抽象类代码:

package com.example.wechatservice.button;

public abstract class AbstractButton {

    private String name;

    public AbstractButton(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

button文件夹下的Button类代码:

package com.example.wechatservice.button;

import java.util.List;

public class Button {

    private List<AbstractButton> button;

    public List<AbstractButton> getButton() {
        return button;
    }

    public void setButton(List<AbstractButton> button) {
        this.button = button;
    }
}

button文件夹下的ClickButton类代码:

package com.example.wechatservice.button;

public class ClickButton extends AbstractButton{
    public ClickButton(String name) {
        super(name);
        this.type = "click";
    }

    private String type;
    private String key;

    public String getType() {
        return type;
    }

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }
}

button文件夹下的PhotoOrAlbumButton类代码:

package com.example.wechatservice.button;

public class PhotoOrAlbumButton extends AbstractButton{
    public PhotoOrAlbumButton(String name) {
        super(name);
        this.type = "pic_photo_or_album";
    }

    private String type;
    private String key;

    public String getType() {
        return type;
    }

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }
}

button文件夹下的SubButton类代码:

package com.example.wechatservice.button;

import java.util.List;

public class SubButton extends AbstractButton{
    public SubButton(String name) {
        super(name);
    }

    private List<AbstractButton> sub_button;

    public List<AbstractButton> getSub_button() {
        return sub_button;
    }

    public void setSub_button(List<AbstractButton> sub_button) {
        this.sub_button = sub_button;
    }
}

button文件夹下的ViewButton类代码:

package com.example.wechatservice.button;

public class ViewButton extends AbstractButton{
    public ViewButton(String name,String url) {
        super(name);
        this.type = "view";
        this.url = url;
    }

    private String type;
    private String url;

    public String getUrl() {
        return url;
    }

    public String getType() {
        return type;
    }
}

WeChatController代码如下:

package com.example.wechatservice.controller;

import com.alibaba.fastjson.JSONObject;
import com.example.wechatservice.button.*;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.security.MessageDigest;
import java.util.*;

@RestController
@RequestMapping(value = "/weChat")
public class WeChatController {

	@Resource
    private RestTemplate restTemplate;

    //测试内网穿透后在外网访问接口
    @GetMapping(value = "/hello")
    public String hello(){
        return "hello";
    }

    //测试微信公众平台里面的接口配置信息里面的URL能否调用成功,这种只是测试微信公众平台能否调用接口,但是不能识别它是否真的来自于微信公众平台来调用你的,所以才需要做验证
    @GetMapping(value = "/test")
    public String test(@RequestParam(value = "signature", required = false) String signature,
                       @RequestParam(value = "timestamp", required = false) String timestamp,
                       @RequestParam(value = "nonce", required = false) String nonce,
                       @RequestParam(value = "echostr", required = false) String echostr){
        System.out.println("微信测试公众平台调用我了!!!!");
        System.out.println("signature="+signature);
        System.out.println("timestamp="+timestamp);
        System.out.println("nonce="+nonce);
        System.out.println("echostr="+echostr);
        //必须原封不动将echostr返回给微信公众号,微信公众测试号才能配置成功那个URL,返回其他值都会导致配置失败
        return echostr;
    }

    //测试微信公众平台里面的接口配置信息,并验证它是否真的来自微信公众平台
    @GetMapping(value = "/check")
    public String check(@RequestParam(value = "signature", required = false) String signature,
                       @RequestParam(value = "timestamp", required = false) String timestamp,
                       @RequestParam(value = "nonce", required = false) String nonce,
                       @RequestParam(value = "echostr", required = false) String echostr){
        System.out.println("微信公众平台调用我了!!!!");
        //微信公众平台配置的token值
        String token="testToken";
        //1.将token、timestamp、nonce三个参数进行字典序排序
        List<String> list= Arrays.asList(token,timestamp,nonce);
        //排序
        Collections.sort(list);
        //2.将三个参数字符串拼接成一个字符串进行sha1加密
        StringBuilder stringBuilder=new StringBuilder();
        for(String s:list){
            stringBuilder.append(s);
        }
        //加密
        try{
            MessageDigest instance = MessageDigest.getInstance("SHA-1");
            //使用sha1进行加密获得byte数组
            byte[] digest=instance.digest(stringBuilder.toString().getBytes());
            StringBuilder sum=new StringBuilder();
            for(byte b:digest){
                sum.append(Integer.toHexString((b>>4)&15));
                sum.append(Integer.toHexString(b&15));
            }
            //3.开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
            if(!StringUtils.isEmpty(signature)&&signature.equals(sum.toString())){
                System.out.println("与微信公众平台一致,确认来自微信公众平台。");
                //必须原封不动将echostr返回给微信公众号,微信公众测试号才能配置成功那个URL,返回其他值都会导致配置失败
                return echostr;
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    //给微信公众号发送普通消息时(重中之重,与微信公众号进行交互全靠这个接口),微信公众号会调用配置好的URL接口,并且是以POST形式,所以这里有个POST的check方法,这里需要把get请求中的/check里面的验证是否真的来自微信公众平台的逻辑给加上,因为是demo所以没加验证
    //MsgType为text时,表示用户给微信公众号发的是文本消息
    //MsgType为image时,表示用户给微信公众号发的是图片消息
    //MsgType为event时,表示用户点击微信公众号里面的菜单
    @PostMapping(value = "/check")
    public String receiveMessage(@RequestBody String requestBody,
                        @RequestParam("signature") String signature,
                        @RequestParam("timestamp") String timestamp,
                        @RequestParam("nonce") String nonce,
                        @RequestParam("openid") String openid){
        System.out.println("用户给我发消息了!!");
        System.out.println("requestBody="+requestBody);
        System.out.println("signature="+signature);
        System.out.println("timestamp="+timestamp);
        System.out.println("nonce="+nonce);
        System.out.println("openid="+openid);
        Map<String,String> map=new HashMap<>();
        try{
            SAXReader reader=new SAXReader();
            Document document = reader.read(new ByteArrayInputStream(requestBody.getBytes("utf-8")));//读取微信传的xml字符串,注意这里要转成输入流
            Element root = document.getRootElement();//获取根元素
            List<Element> elementList = root.elements();//获取当前元素下的全部子元素
            for (Element e : elementList) {
                map.put(e.getName(), e.getText());
            }
            System.out.println(map);
        }catch (Exception e){
            e.printStackTrace();
        }
        //这里需要对不同的回复消息xml模板做不同封装,因为是demo所以就直接拿来用先看一看效果。
        String message="";
        //如果用户给公众号发送的是文本消息
        if(map.get("MsgType").equals("text")){
        	//如果用户发送的内容是111(相当于条件匹配),则返回主菜单文本消息
        	if(map.get("Content").equals("111")){
                message="<xml><ToUserName><![CDATA[ooiyP6HjMn7v42TtTkeZtj89OLKc]]></ToUserName><FromUserName><![CDATA[gh_7fe728a71cd6]]></FromUserName><CreateTime>1715665213</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[您好,欢迎你访问该微信公众号!]]></Content></xml>";
            }
        }else if(map.get("MsgType").equals("event")){//用户点击菜单栏菜单按钮时
        	//这里我只写了一个样例,这里肯定是要写所有点击菜单的判断的,因为是demo所以就不写多了
        	//如果用户点击了菜单2子级1,通过key来匹配,回复图文消息
            if(map.get("EventKey").equals("菜单2子级1")){
                //如果用户点击了菜单2子级1,回复图文消息
                message="<xml><ToUserName><![CDATA[ooiyP6HjMn7v42TtTkeZtj89OLKc]]></ToUserName><FromUserName><![CDATA[gh_7fe728a71cd6]]></FromUserName><CreateTime>1715656909</CreateTime><MsgType><![CDATA[news]]></MsgType><ArticleCount>1</ArticleCount><Articles><item><Title><![CDATA[菜单2子级1]]></Title><Description><![CDATA[点击进入页面,即可进入查询>>]]></Description><PicUrl><![CDATA[http://mmbiz.qpic.cn/sz_mmbiz_jpg/76BCY09cHYSZ60MBaHyHOJPibesjP6ibeRziabuSHZ4jYrITTlmVqFazCzlm8DdQ8QRUrfCulTNrEUyhUcydUiayuQ/0]]></PicUrl><Url><![CDATA[http://www.soso.com/]]></Url></item></Articles></xml>";
            }
        }else if(map.get("MsgType").equals("image")){//用户发送的是图片消息
        	//回复图片消息示例,可以先给微信公众平台发送图片消息,可以在后端控制台获取到图片的MediaId值和PicUrl值
        	message="<xml><ToUserName><![CDATA[ooiyP6HjMn7v42TtTkeZtj89OLKc]]></ToUserName><FromUserName><![CDATA[gh_7fe728a71cd6]]></FromUserName><CreateTime>1715665213</CreateTime><MsgType><![CDATA[image]]></MsgType><Image><MediaId><![CDATA[A3UqbFuQxw2gVlIk1_JGw57YlBrmPA4-stcjyk8yA1MBB7pgGSgD_UxbmfwswSN4]]></MediaId></Image></xml>";
        }
        //回复文本消息示例
        //String messageText="<xml><ToUserName><![CDATA[ooiyP6HjMn7v42TtTkeZtj89OLKc]]></ToUserName><FromUserName><![CDATA[gh_7fe728a71cd6]]></FromUserName><CreateTime>1715665213</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[你好]]></Content></xml>";
        //回复图片消息示例,可以先给微信公众平台发送图片消息,可以在后端控制台获取到图片的MediaId值和PicUrl值
        //String messageImage="<xml><ToUserName><![CDATA[ooiyP6HjMn7v42TtTkeZtj89OLKc]]></ToUserName><FromUserName><![CDATA[gh_7fe728a71cd6]]></FromUserName><CreateTime>1715665213</CreateTime><MsgType><![CDATA[image]]></MsgType><Image><MediaId><![CDATA[A3UqbFuQxw2gVlIk1_JGw57YlBrmPA4-stcjyk8yA1MBB7pgGSgD_UxbmfwswSN4]]></MediaId></Image></xml>";
        //回复语音消息示例,可以先给微信公众平台发送语音消息,可以在后端控制台获取到它的MediaId值
        //String messageVoice="<xml><ToUserName><![CDATA[ooiyP6HjMn7v42TtTkeZtj89OLKc]]></ToUserName><FromUserName><![CDATA[gh_7fe728a71cd6]]></FromUserName><CreateTime>1715656909</CreateTime><MsgType><![CDATA[voice]]></MsgType><Voice><MediaId><![CDATA[d15tL6-BeVLR_v1sijEi8K5nv17RDdz1jDN1DhHVnstKFGbqB8n3riY_d3e2OJlL]]></MediaId></Voice></xml>";
        //回复视频消息示例,可以先给微信公众平台发送语音消息,可以在后端控制台获取到它的MediaId值,有点问题,回复不了,需要查找原因
        //String messageVideo="<xml><ToUserName><![CDATA[ooiyP6HjMn7v42TtTkeZtj89OLKc]]></ToUserName><FromUserName><![CDATA[gh_7fe728a71cd6]]></FromUserName><CreateTime>1715656909</CreateTime><MsgType><![CDATA[video]]></MsgType><Video><MediaId><![CDATA[d15tL6-BeVLR_v1sijEi8HHaaJYRI5baAHJNz-Rsy9nhyAocMVwbdz-uFwPIzpGs2uwQC6BbBpcoK-dpNJ4QEA]]></MediaId><Title><![CDATA[test title]]></Title><Description><![CDATA[test description]]></Description></Video></xml>";
        //回复图文消息示例
        //String messageNews="<xml><ToUserName><![CDATA[ooiyP6HjMn7v42TtTkeZtj89OLKc]]></ToUserName><FromUserName><![CDATA[gh_7fe728a71cd6]]></FromUserName><CreateTime>1715656909</CreateTime><MsgType><![CDATA[news]]></MsgType><ArticleCount>1</ArticleCount><Articles><item><Title><![CDATA[我是标题]]></Title><Description><![CDATA[测试描述]]></Description><PicUrl><![CDATA[http://mmbiz.qpic.cn/sz_mmbiz_jpg/76BCY09cHYSZ60MBaHyHOJPibesjP6ibeRziabuSHZ4jYrITTlmVqFazCzlm8DdQ8QRUrfCulTNrEUyhUcydUiayuQ/0]]></PicUrl><Url><![CDATA[http://www.soso.com/]]></Url></item></Articles></xml>";
        return message;
    }

	//获取公众号的全局唯一接口调用凭据access_token,失效时间120分钟
    @GetMapping(value = "/getAccessToken")
    public String getAccessToken(){
        // 请求地址
        String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={appid}&secret={secret}";
        //提交参数设置,这里map里面的key要与请求地址里面占位符名一样,{username}对应map的key:username
        Map<String, Object> map = new HashMap<>();
        map.put("appid", "你的测试公众号appID");
        map.put("secret", "你的测试公众号appsecret");
        //请求接口
        JSONObject result = restTemplate.getForObject(url, JSONObject.class,map);
        //80_Zd7nT4s07RA6gAu4F5kyM8xlpZvPijpnT4CJQr687DXdUcuVRR9SvrE4xGBtilov5sBC_2hnYQlNs34qINDSgcTLL4tdGEi1usXMEJMY-pxYS1wbLZQm7KK1s-0KFDfAFABWU
        System.out.println(result.get("access_token"));
        return result.get("access_token").toString();
    }

    //创建菜单
    @GetMapping(value = "/createMenu")
    public String createMenu(){
        //创建一级菜单
        Button button=new Button();
        List<AbstractButton> buttons=new ArrayList<>();
        //一级菜单中的第一个菜单按钮(二级菜单)
        SubButton subButton1=new SubButton("菜单1");
        List<AbstractButton> subButtons1=new ArrayList<>();
        //二级菜单菜单1的第一个按钮
        ClickButton clickButton1=new ClickButton("菜单1子级1");
        clickButton1.setKey("菜单1子级1");
        subButtons1.add(clickButton1);
        //二级菜单菜单1的第二个按钮
        ClickButton clickButton2=new ClickButton("菜单1子级2");
        clickButton2.setKey("菜单1子级2");
        subButtons1.add(clickButton2);
        subButton1.setSub_button(subButtons1);

        //一级菜单中的第二个菜单按钮(二级菜单)
        SubButton subButton2=new SubButton("菜单2");
        List<AbstractButton> subButtons2=new ArrayList<>();
        //二级菜单菜单2的第一个按钮
        ClickButton clickButton3=new ClickButton("菜单2子级1");
        clickButton3.setKey("菜单2子级1");
        subButtons2.add(clickButton3);
        //二级菜单菜单2的第二个按钮
        ClickButton clickButton4=new ClickButton("菜单2子级2");
        clickButton4.setKey("菜单2子级2");
        subButtons2.add(clickButton4);
        //二级菜单菜单2的第三个按钮
        ClickButton clickButton5=new ClickButton("菜单2子级3");
        clickButton5.setKey("菜单2子级3");
        subButtons2.add(clickButton5);
        //二级菜单菜单2的第四个按钮
        ClickButton clickButton6=new ClickButton("菜单2子级4");
        clickButton6.setKey("菜单2子级4");
        subButtons2.add(clickButton6);
        //二级菜单菜单2的第五个按钮
        ClickButton clickButton7=new ClickButton("菜单2子级5");
        clickButton7.setKey("菜单2子级5");
        subButtons2.add(clickButton7);
        subButton2.setSub_button(subButtons2);

        //一级菜单中的第三个菜单按钮(二级菜单)
        SubButton subButton3=new SubButton("菜单3");
        List<AbstractButton> subButtons3=new ArrayList<>();
        //二级菜单菜单3的第一个按钮
        ClickButton clickButton8=new ClickButton("菜单3子级1");
        clickButton8.setKey("菜单3子级1");
        subButtons3.add(clickButton8);
        //二级菜单菜单3的第二个按钮
        ClickButton clickButton9=new ClickButton("菜单3子级2");
        clickButton9.setKey("菜单3子级2");
        subButtons3.add(clickButton9);
        //二级菜单菜单3的第三个按钮
        ClickButton clickButton10=new ClickButton("菜单3子级3");
        clickButton10.setKey("菜单3子级3");
        subButtons3.add(clickButton10);
        subButton3.setSub_button(subButtons3);
        //把一级菜单中的三个按钮添加进集合
        buttons.add(subButton1);
        buttons.add(subButton2);
        buttons.add(subButton3);
        //把集合添加到一级菜单中
        button.setButton(buttons);
        System.out.println("菜单数据="+JSONObject.toJSONString(button));

        // 请求地址,这里我是先用Postman调用了getAccessToken接口获得了access_token值,在这里直接写死了供测试使用。
        String url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=80_Zd7nT4s07RA6gAu4F5kyM8xlpZvPijpnT4CJQr687DXdUcuVRR9SvrE4xGBtilov5sBC_2hnYQlNs34qINDSgcTLL4tdGEi1usXMEJMY-pxYS1wbLZQm7KK1s-0KFDfAFABWU";
        // 请求头设置,指定数据以application/json格式的数据格式的数据传递参数
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.parseMediaType("application/json;charset=UTF-8"));
        headers.add("Accept",MediaType.APPLICATION_JSON.toString());
        headers.add("Accept-Charset","UTF-8");

        // 组装请求体
        HttpEntity<Button> request = new HttpEntity<>(button, headers);

        // 发送post请求,并打印结果,以String类型接收响应结果JSON字符串
        //第1个参数:请求的url地址
        //第2个参数:请求的字段参数加数据格式
        //第3个参数:返回的结果类型,这里String.class表示返回结果是一个字符串。
        JSONObject result = restTemplate.postForObject(url, request,JSONObject.class);
        System.out.println(result);
        return result.toString();
    }
}

如果微信公众号测试号你本地配置好了,外网也可以访问了,在该项目代码里面,操作如下:

  1. 修改getAccessToken接口里面的appid值和secret值,改为你自己的。
  2. 使用Postman调用getAccessToken接口获得access_token值
  3. 将获取到的access_token写到创建菜单接口/createMenu里面的那个调用微信公众号菜单的接口里面
  4. 使用Postman调用菜单接口,然后在微信公众号接口测试号里面扫描那个测试号二维码,就能看到你创建的菜单
  5. 给你自己刚创建的测试公众号发送文本消息或者点击菜单,它都会去调用你在测试号里面配置的那个接口地址,并且是以Post形式,这里我的是Post方法/check这个方法,里面有和微信公众号交互的逻辑,根据用户发送的消息类型来进行匹配并回复相应消息。

这里没有实际效果展示,所以对于第一次学习微信公众号的人来说不好理解,不过你把上面代码全部复制到你的项目里面并进行测试,看控制台打印消息就能理解了,然后就是多看官网文档了,以上全部代码就是这些了。希望对各位小伙伴有帮助吧!

;