微信公衆號開發 (3) 菜單處理

1、前言

  1. 微信公衆號開發 (1) 微信接入認證成爲開發者
  2. 微信公衆號開發 (2) 消息處理
本文將實現
  1. 根據AppIDAppSecret獲取access_token
  2. 自定義菜單(建立菜單查詢菜單刪除菜單
微信文檔中提示的一些注意點:
  1. access_token的存儲至少要保留512字符空間。
  2. access_token的有效期2小時,需定時刷新,重複獲取將致使上次獲取的access_token失效
  3. 自定義菜單最多3個一級菜單,每一級菜單最多5個二級菜單
  4. 一級菜單最多4個漢字二級菜單最多7個漢字
  5. 菜單刷新策略:5分鐘以後更新菜單。測試時能夠嘗試取消關注公衆帳號後再次關注,則能夠看到建立後的效果

2、RestTemplate配置 (用於遠程調用微信http接口方法)

RestTemplate是Spring提供的用於訪問Rest服務的客戶端,RestTemplate提供了多種便捷訪問遠程Http服務的方法,可以大大提升客戶端的編寫效率。html

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();
        // 解決post請求中文亂碼問題
        restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
        return restTemplate;
    }

}

3、微信接口調用說明

  1. 獲取access_token接口 : 【GET請求】 https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
  2. 查詢菜單接口 : 【GET請求】 https://api.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN
  3. 刪除菜單接口 : 【GET請求】 https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN
  4. 建立菜單接口 : 【POST請求】 https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN
封裝微信接口所需變量
public class Constants {
    /**
     * TODO 填寫本身的 `appID` 和 `appsecret`
     */
    public static final String APP_ID = "xxx";
    public static final String APP_SECRET = "xxx";

    /**
     * 經過 `GET請求方式` 獲取 `access_token`
     */
    public static final String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
    /**
     * TODO 只作臨時方便測試使用
     */
    public static final String ACCESS_TOKEN = "xxx";

    /**
     * 查詢菜單接口 - GET請求
     */
    public static final String GET_MENU_URL = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN";
    /**
     * 刪除菜單接口 - GET請求 (注意,在個性化菜單時,調用此接口會刪除默認菜單及所有個性化菜單)
     */
    public static final String DELETE_MENU_URL = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN";
    /**
     * 建立菜單接口 - POST請求
     */
    public static final String CREATE_MENU_URL = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";

}

4、根據AppIDAppSecret獲取access_token

access_token是公衆號的全局惟一接口調用憑據,公衆號調用各接口(下面的建立菜單查詢菜單刪除菜單等)時都需使用access_token!java

這裏可查看微信文檔獲取access_token方式git

① 封裝響應結果AccessTokenVO
@Data
@ApiModel(description = "access_token: 公衆號的全局惟一接口調用憑據")
public class AccessTokenVO {

    @ApiModelProperty(value = "獲取到的憑證")
    private String access_token;

    @ApiModelProperty(value = "憑證有效時間,單位:秒(微信目前暫7200秒,即2小時,過時後需再次獲取)")
    private int expires_in;

}
② 服務類
public interface IWeixinService {

    /**
     * 根據AppID和AppSecret獲取access_token
     *
     * @param appId:
     * @param appSecret:
     * @return: com.zhengqing.demo.modules.weixin.model.AccessTokenVO
     */
    AccessTokenVO getAccessToken(String appId, String appSecret);

}
③ 服務實現類
@Slf4j
@Service
public class WeixinServiceImpl implements IWeixinService {

    @Autowired
    private RestTemplate restTemplate;

    @Override
    public AccessTokenVO getAccessToken(String appId, String appSecret) {
        AccessTokenVO accessTokenVO = restTemplate.getForObject(Constants.GET_ACCESS_TOKEN_URL.replace("APPID", appId).replace("APPSECRET", appSecret), AccessTokenVO.class);
        return accessTokenVO;
    }

}

5、自定義菜單處理

clickview請求示例

{
     "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"
            }]
       }]
 }

一、封裝菜單數據

舒適小提示:這裏封裝數據建議多看下微信文檔中給出的數據,否則可能會對最後組裝菜單樹數據建立菜單的時候感到迷惑 ~github

在這裏插入圖片描述

① 菜單類型枚舉類
public enum MenuType {
    // 點擊式菜單
    CLICK("click"),
    // 連接式菜單
    VIEW("view");
}
② 菜單 - 基類
@Data
@ApiModel(description = "菜單 - 基類")
public class Button {

    @ApiModelProperty(value = "菜單標題,不超過16個字節,子菜單不超過60個字節")
    private String name;

}
③ 點擊式菜單
@Data
@ApiModel(description = "用戶點擊菜單可接收消息推送")
public class ClickButton extends Button {

    @ApiModelProperty(value = "菜單的響應動做類型,view表示網頁類型,click表示點擊類型,miniprogram表示小程序類型")
    private String type = MenuType.CLICK.getType();

    @ApiModelProperty(value = "菜單KEY值,用於消息接口推送,不超過128字節")
    private String key;

}
④ 連接式菜單
@Data
@ApiModel(description = "用戶點擊菜單可打開連接")
public class ViewButton extends Button {

    @ApiModelProperty(value = "菜單的響應動做類型,view表示網頁類型,click表示點擊類型,miniprogram表示小程序類型")
    private String type = MenuType.VIEW.getType();

    @ApiModelProperty(value = "(view、miniprogram類型必須) 網頁 連接,用戶點擊菜單可打開連接,不超過1024字節。 type爲miniprogram時,不支持小程序的老版本客戶端將打開本url")
    private String url;

}
⑤ 含二級菜單的一級菜單
@Data
@ApiModel(description = "含二級菜單的一級菜單")
public class ComplexButton extends Button {

    @ApiModelProperty(value = "二級菜單數組,個數應爲1~5個")
    private Button[] sub_button;

}
⑥ 最外層的菜單樹
@Data
@ApiModel(description = "菜單樹")
public class Menu {

    @ApiModelProperty(value = "一級菜單數組,個數應爲1~3個")
    private Button[] button;

}

二、服務類

public interface IMenuService {

    /**
     * 查詢菜單
     *
     * @param accessToken:訪問憑據
     * @return: java.lang.Object
     */
    Object getMenu(String accessToken);

    /**
     * 刪除菜單
     *
     * @param accessToken:訪問憑據
     * @return: com.zhengqing.demo.modules.weixin.model.WeixinResponseResult
     */
    WeixinResponseResult deleteMenu(String accessToken);

    /**
     * 建立菜單
     *
     * @param menu        : 建立的菜單數據
     * @param accessToken : 訪問憑據
     * @return: com.zhengqing.demo.modules.weixin.model.WeixinResponseResult
     */
    WeixinResponseResult createMenu(Menu menu, String accessToken);

}

三、服務實現類

@Slf4j
@Service
public class MenuServiceImpl implements IMenuService {

    @Autowired
    private RestTemplate restTemplate;


    @Override
    public Object getMenu(String accessToken) {
        Object menu = restTemplate.getForObject(Constants.GET_MENU_URL.replace("ACCESS_TOKEN", accessToken), Object.class);
        return menu;
    }

    @Override
    public WeixinResponseResult deleteMenu(String accessToken) {
        WeixinResponseResult result = restTemplate.getForObject(Constants.DELETE_MENU_URL.replace("ACCESS_TOKEN", accessToken), WeixinResponseResult.class);
        return result;
    }

    @Override
    public WeixinResponseResult createMenu(Menu menu, String accessToken) {
        // 將菜單對象轉換成json字符串
        String jsonMenu = JSON.toJSONString(menu);
        WeixinResponseResult result = restTemplate.postForObject(Constants.CREATE_MENU_URL.replace("ACCESS_TOKEN", accessToken), jsonMenu, WeixinResponseResult.class);
        return result;
    }

}

6、測試

一、獲取access_token
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = DemoApplication.class)
public class WeixinTest {

    @Autowired
    private IWeixinService weixinService;

    @Test // 獲取 `access_token`
    public void getAccessToken() throws Exception {
        AccessTokenVO accessTokenVO = weixinService.getAccessToken(Constants.APP_ID, Constants.APP_SECRET);
        log.info("======================================== \n" + accessTokenVO.getAccess_token());
    }

}
二、建立自定義菜單查詢菜單刪除菜單

注:這裏小編將獲取到的access_token 寫死到常量 Constants.ACCESS_TOKEN 中作測試,實際項目中可將access_token保存到緩存中,每隔快到2個小時的時候去從新獲取一次刷新緩存數據 ~json

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = DemoApplication.class)
public class MenuTest {

    @Autowired
    private IMenuService menuService;

    @Test // 查詢菜單
    public void getMenu() {
        Object menu = menuService.getMenu(Constants.ACCESS_TOKEN);
        log.info("======================================== \n" + JSON.toJSONString(menu));
    }

    @Test // 刪除菜單
    public void deleteMenu() {
        WeixinResponseResult result = menuService.deleteMenu(Constants.ACCESS_TOKEN);
        log.info("======================================== \n" + result);
    }

    @Test // 建立菜單
    public void createMenu() {
        WeixinResponseResult result = menuService.createMenu(createMenuTree(), Constants.ACCESS_TOKEN);
        log.info("======================================== \n" + result);
    }

    /**
     * 菜單數據
     */
     private Menu createMenuTree() {
        // 連接式菜單
        ViewButton btn11 = new ViewButton();
        btn11.setName("CSDN");
        btn11.setUrl("https://zhengqing.blog.csdn.net/");

        ViewButton btn12 = new ViewButton();
        btn12.setName("我的博客");
        btn12.setUrl("http://zhengqingya.gitee.io/blog/");

        // 點擊式菜單
        ClickButton mainBtn2 = new ClickButton();
        mainBtn2.setName("點我吖");
        mainBtn2.setKey("hello");

        ViewButton btn31 = new ViewButton();
        btn31.setName("碼雲");
        btn31.setUrl("https://gitee.com/zhengqingya/projects");

        ViewButton btn32 = new ViewButton();
        btn32.setName("GitHub");
        btn32.setUrl("https://github.com/zhengqingya?tab=repositories");

        // 含二級菜單的一級菜單
        ComplexButton mainBtn1 = new ComplexButton();
        mainBtn1.setName("博客");
        mainBtn1.setSub_button(new ViewButton[]{btn11, btn12});

        ComplexButton mainBtn3 = new ComplexButton();
        mainBtn3.setName("倉庫");
        mainBtn3.setSub_button(new ViewButton[]{btn31, btn32});

        Menu menu = new Menu();
        menu.setButton(new Button[]{mainBtn1, mainBtn2, mainBtn3});

        return menu;
    }

}

最終自定義的菜單小程序

在這裏插入圖片描述

本文案例demo源碼

https://gitee.com/zhengqingya/java-workspaceapi

相關文章
相關標籤/搜索