天天看點

微信公衆号開發 - 建立菜單微信公衆号開發文章目錄

微信公衆号開發文章目錄

1.微信公衆号開發 - 環境搭建

2.微信公衆号開發 - 配置表設計以及接入公衆号接口開發

3.微信公衆号開發 - token擷取(保證同一時間段内隻請求一次)

4.微信公衆号開發 - 菜單按鈕bean封裝

5.微信公衆号開發 - 建立菜單

6.微信公衆号開發 - 事件處理和回複消息

7.微信公衆号開發 - 發送Emoji表情

項目完整代碼請通路github:https://github.com/liaozq0426/wx.git

在上篇文章中完成了菜單、按鈕bean的封裝,現在來實作微信公衆号菜單的建立

向wx_cfg配置表中插入若幹菜單記錄
INSERT INTO `wx_cfg` (`id`, `type`, `name`, `value`, `parent_id`, `sort`, `platform`, `wx_type`, `enabled`, `desc`) VALUES ('4', 'app_url', 'appUrl', 'http://www.gavin.com', NULL, NULL, 'gavin', 'service', '1', '公衆号域名');
INSERT INTO `wx_cfg` (`id`, `type`, `name`, `value`, `parent_id`, `sort`, `platform`, `wx_type`, `enabled`, `desc`) VALUES ('5', 'menu', 'view1', '/transfer/index.html', NULL, '1', 'gavin', 'service', '1', '學習資料');
INSERT INTO `wx_cfg` (`id`, `type`, `name`, `value`, `parent_id`, `sort`, `platform`, `wx_type`, `enabled`, `desc`) VALUES ('6', 'menu', 'view2', '/transfer/index.html', NULL, '2', 'gavin', 'service', '1', '線上題庫');
INSERT INTO `wx_cfg` (`id`, `type`, `name`, `value`, `parent_id`, `sort`, `platform`, `wx_type`, `enabled`, `desc`) VALUES ('7', 'menu', 'click1', '/transfer/index.html', NULL, '3', 'gavin', 'service', '1', '關于');
INSERT INTO `wx_cfg` (`id`, `type`, `name`, `value`, `parent_id`, `sort`, `platform`, `wx_type`, `enabled`, `desc`) VALUES ('8', 'menu', 'view11', '/transfer/index.html', '5', '1', 'gavin', 'service', '1', 'JAVA');
INSERT INTO `wx_cfg` (`id`, `type`, `name`, `value`, `parent_id`, `sort`, `platform`, `wx_type`, `enabled`, `desc`) VALUES ('9', 'menu', 'view12', '/transfer/index.html', '5', '2', 'gavin', 'service', '1', 'MySQL');
           
編寫代碼

建立WxMenuService接口

package com.gavin.service;

import com.gavin.pojo.Menu;

public interface WxMenuService {
	public Menu makeMenu(String platform) throws Exception;
}
           

建立實作類WxMenuServiceImpl,代碼如下

package com.gavin.service.impl;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.gavin.cfg.WxCfgEnum;
import com.gavin.pojo.AccessToken;
import com.gavin.pojo.Button;
import com.gavin.pojo.ClickButton;
import com.gavin.pojo.ComplexButton;
import com.gavin.pojo.Menu;
import com.gavin.pojo.ViewButton;
import com.gavin.pojo.WxApiCfg;
import com.gavin.pojo.WxCfg;
import com.gavin.service.WxCfgService;
import com.gavin.service.WxMenuService;
import com.gavin.service.WxTokenService;
import com.gavin.util.EncryptionUtil;
import com.gavin.util.WxUtil;
import com.google.gson.Gson;

@Service
public class WxMenuServiceImpl implements WxMenuService{
	
	private Logger logger = Logger.getLogger(this.getClass());
	
	@Autowired
	private WxTokenService wxTokenService;
	
	@Autowired
	private WxCfgService wxCfgService;

	/**
	 * @title 根據平台建立微信公衆号菜單
	 * @author gavin
	 * @date 2019年5月23日
	 * @param platform
	 * @return
	 * @throws Exception
	 */
	@Override
	public Menu makeMenu(String platform) throws Exception {
		// 查詢一級菜單
		System.out.println(platform);
		WxCfg parentParam = new WxCfg();
		parentParam.setType(WxCfgEnum.MENU.getType());
		parentParam.setEnabled(true);
		parentParam.setPlatform(platform);
		parentParam.setOrderBy("sort asc");
		List<WxCfg> cfgList = this.wxCfgService.select(parentParam);
		if (cfgList.size() > 0) {
			Menu menu = new Menu();

			List<Button> buttons = new ArrayList<Button>();
			for (WxCfg cfg : cfgList) {
				WxCfg subParam = new WxCfg();
				subParam.setType(WxCfgEnum.MENU.getType());
				subParam.setParentId(cfg.getId());
				subParam.setEnabled(true);
				subParam.setPlatform(platform);
				// 查詢二級菜單
				List<WxCfg> subCfgList = this.wxCfgService.select(subParam);
				if (subCfgList.size() > 0) {
					// 建構多級按鈕
					List<Button> subButtons = new ArrayList<Button>();
					for (WxCfg subCfg : subCfgList) {
						Button sub = createButton(subCfg);
						subButtons.add(sub);
					}
					ComplexButton complexButton = new ComplexButton();
					complexButton.setName(cfg.getDesc());
					complexButton.setSub_button(subButtons.toArray(new Button[subButtons.size()]));
					buttons.add(complexButton);
				} else {
					Button button = createButton(cfg);
					buttons.add(button);
				}
			}
			// 擷取accessToken
			AccessToken token = this.wxTokenService.readAccessToken(AccessToken.TYPE_ACCESS_TOKEN, platform);
			menu.setButton(buttons.toArray(new Button[buttons.size()]));
			Gson gson = new Gson();
			String menuJson = gson.toJson(menu);
			System.out.println(menuJson);
			Map<String , Object> message = WxUtil.createMenu(menu, token.getAccess_token());
			logger.info(message.toString());
			if (message.get("errcode") != null 
					&& (Integer)message.get("errcode") == 0
					&& "ok".equalsIgnoreCase((String)message.get("errmsg"))) {
				logger.info("微信菜單建立成功!");
				return menu;
			}else {				
				logger.error("微信菜單建立失敗");
			}
		}
		return null;
	}
	
	/**
	 * @title 根據配置資訊建立button,這裡隻實作了最常用的click和view兩種類型的按鈕
	 * @author gavin
	 * @date 2019年5月23日
	 * @param cfg
	 * @return
	 * @throws Exception
	 */
	private Button createButton(WxCfg cfg) throws Exception {
		String btnType = cfg.getName();
		if (btnType.startsWith(Button.TYPE_CLICK)) {
			// 普通點選按鈕
			ClickButton click = new ClickButton();
			click.setName(cfg.getDesc());
			click.setType(Button.TYPE_CLICK);
			
			// key可以根據自己的需要設定,這裡我設定為[name_desc]
			click.setKey(cfg.getName() + "_" + cfg.getDesc());
			return click;
		} else if (btnType.startsWith(Button.TYPE_VIEW)) {
			// view按鈕
			ViewButton view = new ViewButton();
			view.setName(cfg.getDesc());
			view.setType(Button.TYPE_VIEW);
			// 動态生成url
			WxCfg cfgParam = new WxCfg();
			cfgParam.setPlatform(cfg.getPlatform());
			cfgParam.setType(WxCfgEnum.WX_KEY_APPID.getType());
			cfgParam.setName(WxCfgEnum.WX_KEY_APPID.getName());
			WxCfg queryCfg = this.wxCfgService.selectOne(cfgParam);
			if(queryCfg != null) {
				String appId = EncryptionUtil.base64Decode(queryCfg.getValue());
				String wxType = cfg.getWxType();
				String url = null;
				if(WxCfgEnum.WX_TYPE_SERVICE.getType().equals(wxType)) {
					// 如果是服務号,生成網頁授權的格式url
					String redirectUrl = cfg.getValue();
					if(!StringUtils.isBlank(redirectUrl)) {
						redirectUrl = redirectUrl + "?state=" + cfg.getName() + "&platform=" + cfg.getPlatform();
					}
					url = WxUtil.makeViewUrl(appId, WxApiCfg.SCOPE_BASE, redirectUrl,
							cfg.getName());
				}else if(WxCfgEnum.WX_TYPE_SUBSCRIBE.getType().equals(wxType)) {
					// 如果是訂閱号,生成普通url格式
					url = cfg.getValue();
					if(!StringUtils.isBlank(url))
						url = url + "?state=" + cfg.getName() + "&platform=" + cfg.getPlatform();
				}
				logger.info(url);
				view.setUrl(url);
				return view;				
			}
		}
		return null;
	}
}
           

上述代碼中的幾個要點

1)在查詢資料庫配置中,首先查詢了

parent_id

為空的記錄,也就是一級菜單

2)查詢出一級菜單後,周遊一級菜單集合,用一級菜單記錄的

id

作為

parent_id

參數去查詢二級菜單

3)createButton為建立按鈕對象方法,建立時會判斷name字段的值,如果name值的字首是click,則建立成ClickButton,如果name值得字首是view,則建立成ViewButton。

4)如果建立的按鈕是ViewButton,會進一步判斷wx_type字段(公衆号類型),如果是服務号,url會建立成網頁授權的格式,因為網頁授權格式才能在後續擷取openid和使用者基本資訊;如果是訂閱号,則建立成普通格式的url。

接下來在WxController中新增一個方法,調用service

@GetMapping("wx/menu")
public Menu getWxMenu(String platform) {
	try {
		return this.wxMenuService.makeMenu(platform);
	} catch (Exception e) {
		e.printStackTrace();
	}
	return null;
}
           
測試

最後,用postman測試一下wx/menu接口,調用結果如下圖所示

微信公衆号開發 - 建立菜單微信公衆号開發文章目錄

再用手機看一下公衆号

微信公衆号開發 - 建立菜單微信公衆号開發文章目錄

說明公衆号菜單建立成功!