AppID
和AppSecret
獲取access_token
建立菜單
、查詢菜單
、刪除菜單
)存儲
至少要保留512
個字符
空間。有效期
爲2小時
,需定時刷新,重複獲取將致使上次獲取的access_token失效3個一級菜單
,每一級菜單最多5個二級菜單
一級菜單最多4個漢字
,二級菜單最多7個漢字
菜單刷新策略:
5分鐘以後更新菜單。測試時能夠嘗試取消關注公衆帳號後再次關注,則能夠看到建立後的效果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; } }
【GET請求】
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
【GET請求】
https://api.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN
【GET請求】
https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN
【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"; }
AppID
和AppSecret
獲取access_token
access_token是公衆號的全局惟一接口調用憑據,公衆號調用各接口(下面的建立菜單
、查詢菜單
、刪除菜單
等)時都需使用access_token!java
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; } }
click
和view
請求示例{ "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; } }
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; } }
最終自定義的菜單小程序