【微信公众号开发】——自定义菜单(实现图片、链接、小程序)功能

公众号限制

公众号中如果设置了服务器配置,那么配置的菜单将无法使用,两者是互斥的,解决方案就是将菜单通过API的方式创建
微信任务你设置了服务器配置,表示你意见具备了API开发的能力,则不在提供配置菜单的功能
在这里插入图片描述

实现api自定义菜单

一、 阅读开发文档

在这里插入图片描述

二、官网示例参数

{
    "button": [
    {	
          "type":"click",
          "name":"今日歌曲",
          "key":"V1001_TODAY_MUSIC"
      },
      {
           "name":"菜单",
           "sub_button":[
           {	
               "type":"view",
               "name":"搜索",
               "url":"http://www.soso.com/"
            },
            {
                 "type":"miniprogram",
                 "name":"wxa",
                 "url":"http://mp.weixin.qq.com",
                 "appid":"wx286b93c14bbf93aa",
                 "pagepath":"pages/lunar/index"
             },
            {
               "type":"click",
               "name":"赞一下我们",
               "key":"V1001_GOOD"
            }]
       },
        {
            "name": "扫码", 
            "sub_button": [
                {
                    "type": "scancode_waitmsg", 
                    "name": "扫码带提示", 
                    "key": "rselfmenu_0_0", 
                    "sub_button": [ ]
                }, 
                {
                    "type": "scancode_push", 
                    "name": "扫码推事件", 
                    "key": "rselfmenu_0_1", 
                    "sub_button": [ ]
                }
            ]
        }, 
        {
            "name": "发图", 
            "sub_button": [
                {
                    "type": "pic_sysphoto", 
                    "name": "系统拍照发图", 
                    "key": "rselfmenu_1_0", 
                   "sub_button": [ ]
                 }, 
                {
                    "type": "pic_photo_or_album", 
                    "name": "拍照或者相册发图", 
                    "key": "rselfmenu_1_1", 
                    "sub_button": [ ]
                }, 
                {
                    "type": "pic_weixin", 
                    "name": "微信相册发图", 
                    "key": "rselfmenu_1_2", 
                    "sub_button": [ ]
                }
            ]
        }, 
        {
            "name": "发送位置", 
            "type": "location_select", 
            "key": "rselfmenu_2_0"
        },
        {
           "type": "media_id", 
           "name": "图片", 
           "media_id": "MEDIA_ID1"
        }, 
        {
           "type": "view_limited", 
           "name": "图文消息", 
           "media_id": "MEDIA_ID2"
        },
        {
            "type": "article_id",
            "name": "发布后的图文消息",
            "article_id": "ARTICLE_ID1"
        },
        {
            "type": "article_view_limited",
            "name": "发布后的图文消息",
            "article_id": "ARTICLE_ID2"
        }
    ]
}

三、接口说明

获取accessToken

1、地址信息
请求地址https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
请求方式GET
请求参数APPID APPSECRET
2、参数获取方式:

在这里插入图片描述

3、设置白名单(上述图片中所示)
4、说明

在这里插入图片描述

创建菜单

1、地址信息
请求地址https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKENT
请求方式POST
请求参数路径参数 APPSECRET
2、参数说明:

在这里插入图片描述

3、返参说明

在这里插入图片描述

4、返回码说明:

在这里插入图片描述

四、代码实现

1、返参实体类

/**
 * @project: IG
 * @author: Liyh
 * @date: 2024/12/09 14:36
 * @description: 微信菜单
 * @version: 1.0
 */
@Getter
@Setter
public class WxMenu {

    private WxButton[] button;
}
/**
 * @date: 2024/12/09 14:36
 * @description: 微信菜单按钮信息
 * @version: 1.0
 */

@Getter
@Setter
public class WxButton {

    /**
     * 按钮名称
     */
    private String name;

    /**
     * 按钮类型
     */
    private String type;

    /**
     * 按钮Key
     */
    private String key;

    /**
     * 按钮URL
     */
    private String url;

    /**
     * 小程序appId
     * @JsonPropert用于json转化
     */
    @JsonProperty("appid")
    private String appId;

    /**
     * 小程序的页面路径
     */
    @JsonProperty("pagepath")
    private String pagePath;

    /**
     * 永久素材的合法media_id
     */
    @JsonProperty("media_id")
    private String mediaId;

    /**
     * 子按钮
     */
    @JsonProperty("sub_button")
    private WxButton[] subButton;
}

2、http请求实现

/**
 * @date: 2024/12/09 15:12
 * @description: https请求信任管理器
 * @version: 1.0
 */
public class MyX509TrustManagerUtil implements X509TrustManager {
    @Override
    public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

    }

    @Override
    public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

    }

    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return new X509Certificate[0];
    }
}
public static JsonNode httpsRequest(String requestUrl, String requestType, String requestParam) {
        JsonNode jsonNode = null;
        log.info("请求url:{}, 请求类型:{}, 请求参数:{}", requestUrl, requestType, requestParam);
        try {
            // 创建SSLContext对象,并使用我们指定的信任管理器初始化
            TrustManager[] tm = {new MyX509TrustManagerUtil()};
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            sslContext.init(null, tm, new java.security.SecureRandom());
            // 从上述SSLContext对象中得到SSLSocketFactory对象
            SSLSocketFactory ssf = sslContext.getSocketFactory();
            URL url = new URL(requestUrl);
            HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
            httpUrlConn.setSSLSocketFactory(ssf);
            /*允许输出*/
            httpUrlConn.setDoOutput(true);
            /*允许输入*/
            httpUrlConn.setDoInput(true);
            /*不允许缓存*/
            httpUrlConn.setUseCaches(false);
            // 设置请求方式(GET/POST)
            httpUrlConn.setRequestMethod(requestType);
            /*如果是get请求,明文连接*/
            if (HttpMethod.GET.toString().equalsIgnoreCase(requestType)) {
                httpUrlConn.connect();
            }
            if (StringUtil.isNotBlank(requestParam)) {
                try (OutputStream outputStream = httpUrlConn.getOutputStream();) {
                    outputStream.write(requestParam.getBytes(StandardCharsets.UTF_8));
                }
            }
            try (InputStream inputStream = httpUrlConn.getInputStream()) {
                ObjectMapper objectMapper = new ObjectMapper();
                jsonNode = objectMapper.readTree(inputStream);
                log.error("https请求成功" + jsonNode);
            }
            httpUrlConn.disconnect();
        }catch (Exception e) {
            log.error("https请求失败" + e);
        }
        return jsonNode;
    }

3、构造菜单数据

public WxMenu getMenuInfo() {
        // 链接只需要设置url
        WxButton secondLevelButton1 = new WxButton();
        secondLevelButton1.setName("链接");
        secondLevelButton1.setUrl("https://www.baidu.com");
        secondLevelButton1.setType("view");
        secondLevelButton1.setSubButton(new WxButton[]{});

        // 图片需要设置永久素材的media_id
        WxButton secondLevelButton2 = new WxButton();
        secondLevelButton2.setName("图片");
        secondLevelButton2.setType("media_id");
        secondLevelButton2.setMediaId("We4arkbMLyXAc0t8E59dK26h_p*****ZVbLw4BRqVniwJuNeJk");
        secondLevelButton2.setSubButton(new WxButton[]{});


        // 小程序设置必须先关联小程序,否则报错,关联后设置appId、pagePath
        WxButton secondLevelButton6 = new WxButton();
        secondLevelButton6.setName("小程序系统");
        secondLevelButton6.setType("miniprogram");
        secondLevelButton6.setAppId("wx*************6fd8f5d");
        secondLevelButton6.setPagePath("pages/***/***");
        secondLevelButton6.setSubButton(new WxButton[]{});


        WxButton firstLevelButton1 = new WxButton();
        firstLevelButton1.setName("第一个菜单");
        firstLevelButton1.setSubButton(new WxButton[]{secondLevelButton1, secondLevelButton2};
        WxButton firstLevelButton2 = new WxButton();
        firstLevelButton2.setName("第二个菜单");
        firstLevelButton2.setUrl("https://www.baidu,com");
        firstLevelButton2.setType("view");
        WxButton firstLevelButton3 = new WxButton();
        firstLevelButton3.setName("第三个菜单");
        firstLevelButton3.setSubButton(new WxButton[]{secondLevelButton6});
        WxMenu menu = new WxMenu();
        menu.setButton(new WxButton[]{firstLevelButton1, firstLevelButton2, firstLevelButton3});
        return menu;
    }

4、请求accessToken获取token

	public String getAccessToken() {
        String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
        url = url.replace("APPID", APP_ID).replace("APPSECRET", APP_SECRET);
        JsonNode jsonNode = HttpUtils.httpsRequest(url, "GET", null);
        log.info("getAccessToken返参:" + jsonNode.asText());
        return jsonNode.get("access_token") != null ? jsonNode.get("access_token").asText() : null;
    }

5、创建菜单

public void createWxMenu() {
        String accessToken = getAccessToken();
        if (StringUtil.isBlank(accessToken)) {
            log.error("获取 Access token失败");
            return;
        }
        String url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";
        url = url.replace("ACCESS_TOKEN", accessToken);
        String requestParam = JsonUtil.toJSONString(getMenuInfo());
        JsonNode jsonNode = HttpUtils.httpsRequest(url, "POST", requestParam);

        if (jsonNode == null) {
            log.error("创建失败");
        } else {
            if ( 0 != jsonNode.get("errcode").asInt()) {
                log.error("======>>>   创建菜单失败 errcode:{} errmsg:{}", jsonNode.get("errcode"), jsonNode.get("errmsg"));
            }
        }

五、注意事项:

1、图片类型需要先上传图片到素材库中,可以通过api,我这里采用了postman调用API的方式,详细参考附一
2、如果是小程序,需要在微信后台将小程序关联,否则接口调用报错
3、如果是微信提供的测试公众号则无法关联小程序
4、未认证的微信公众号无法使用创建菜单的api(确保微信公众号已认证)

附一

如果按钮功能为发送图片,必须先将图片上传素材库之后拿到图片的media_id才可以设置,可以通过代码实现或者直接使用postman调用接口
在这里插入图片描述
在这里插入图片描述
postman调用
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值