微信公众号开发02----自定义菜单及菜单功能实现

创建自定义菜单

公众平台的自定义菜单主要分三种:

  • view类型:点菜单跳转到一个新界面
  • click类型:获取菜单的点击事件,点击后要做什么你决定
  • miniprogram类型:小程序类型

官网的开发文档中,对自定义菜单的一些基本概念和特点都讲的很详细了,这里不再赘述,直接进入正题。

下面代码片段都是接上一篇,代码均是写在WeixinGZHService.java类

1. 程序生成自定义菜单

   	@Value("${weixinGZH.appid}")
    private String WEIXIN_GZH_APPID;
    @Value("${weixinGZH.secret}")
    private String WEIXIN_GZH_SECRET;
    public static final String WEIXIN_ACCESS_TOKEN_KEY = "weixin_access_token";
    public static final String KEY_I_HAVE_TIME = "V1001_I_have_time";
/**
     * 生成菜单列表
     */
    public void createMenuList() throws IOException, ParseException {
        httpClient = new HttpClient(get_create_menu_list(getAcessToken()));
        httpClient.setHttps(true);
        //定义自定义菜单集合
        List<WeixinMenu> weixinMenus = new ArrayList<>();
        //一级菜单
        WeixinMenu menu1 = new WeixinMenu();
        menu1.setName("我有空");
        menu1.setType(ButtonType.click);
        menu1.setKey(KEY_I_HAVE_TIME);
        weixinMenus.add(menu1);

        WeixinMenu menu2 = new WeixinMenu();
        menu2.setName("任务中心");
        menu2.setType(ButtonType.view);
        menu2.setUrl(SERVER_ROOT_URL + "/redirect/redirecttogoingorder");
        weixinMenus.add(menu2);

        WeixinMenu menu3 = new WeixinMenu();
        menu3.setName("我的帐户");
        menu3.setSub_button(new ArrayList<>());
        menu3.setType(null);

        WeixinMenu subMenu3_0 = new WeixinMenu();
        subMenu3_0.setName("查看余额");
        subMenu3_0.setType(ButtonType.view);
        subMenu3_0.setUrl(SERVER_ROOT_URL + "/redirect/redirecttocashout");
        menu3.getSub_button().add(subMenu3_1);

        WeixinMenu subMenu3_1 = new WeixinMenu();
        subMenu3_1.setName("本月战绩");
        subMenu3_1.setType(ButtonType.view);
        subMenu3_1.setUrl(SERVER_ROOT_URL + "/redirect/redirecttomonthscore");
        menu3.getSub_button().add(subMenu3_1);
        weixinMenus.add(menu3);

        WeixinMenu subMenu3_2 = new WeixinMenu();
        subMenu3_2.setName("注册视频教程");
        subMenu3_2.setType(ButtonType.view);
        subMenu3_2.setUrl("http://www.baidu.com");
        menu3.getSub_button().add(subMenu3_2);

        Map map = new HashMap();
        map.put("button", weixinMenus);
        System.out.println("菜单转json对象:" + JSONObject.toJSONString(map));
        httpClient.setXmlParam(JSONObject.toJSONString(map));
        httpClient.post();
        System.out.println("======创建菜单:" + httpClient.getContent());
    }
    /**
     * 获取创建菜单的url
     *
     * @return
     */
    public String get_create_menu_list(String accessToken) {
        return "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=" + accessToken;
    }
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 获取access_token。
     * access_token之所以采用缓存到redis,是因为这个token在微信官方中指明只有2个小时时效,超过2小时,要重新获取
     * 所以在这里,将直接借助Redis来设置生成的token时效110分钟,这样目的是既可以防止频繁调用公众号获取token接口又能保存程序自动获取token
     */
    public String getAcessToken() {
        Object accessToken = redisTemplate.opsForValue().get(WEIXIN_ACCESS_TOKEN_KEY);
        if (accessToken == null) {
            //重新调用接口查询access_token
            httpClient = new HttpClient(get_access_token(WEIXIN_GZH_APPID, WEIXIN_GZH_SECRET));
            try {
                httpClient.get();
                String content = httpClient.getContent();
                JSONObject jsonObject = JSONObject.parseObject(content);
                accessToken = jsonObject.get("access_token");
                if (accessToken != null) {
                    redisTemplate.opsForValue().set(WEIXIN_ACCESS_TOKEN_KEY, accessToken.toString(), 110, TimeUnit.MINUTES);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return accessToken == null ? null : accessToken.toString();

    }

2.实现每个菜单跳转业务代码

上面的代码示例,我用到了3种菜单跳转类型:
click:在点击菜单时,处理业务逻辑
view:
跳转界面,不需要获取当前微信用户信息
跳转界面,需要获取当前点击菜单的微信用户信息

2.1 click菜单业务代码

在程序中,实现click点击,那就需要在我上一篇中讲联调公众平台时写的那个WechatCallbackApi.java类中完成

  • 示例代码如下(代码写在WechatCallbackApi.java)
//在doGet()方法中,通过下面的方法来进行判断
/发送模板消息时,也会向公众号返回一条消息,但此消息的数据类型与 click事件的返回类型不同。需要判断eventKey的值
            if (weixinResult != null && StringUtils.isNotBlank(weixinResult.getEventKey())) {
                switch (weixinResult.getEventKey()) {
					case KEY_I_HAVE_TIME:
					//这里处理点这个【我有空】菜单时的业务逻辑代码
					//当然,这里的业务代码没必要写在这个类中,你可以再写一个component,然后通过@Autowired注入后调用封装后的方法
					break;
                }
            }

2.2 view跳转并获取微信用户的信息

界面跳转并认证流程

用户点公众号菜单
调用view类型中配置的url
在服务器方法中调用微信的oauth认证并获取token
再根据token来获取微信用户的openid及其他信息

官方的这个流程听起来就很晕了,如果你是个新手,可能你已经完全没勇气往下走了,因为这里如果出现什么异常,其实是很难定位的。
所以接下直接上代码,按照代码的编写过程边复制代码边理解,这样就算中间出现什么问题,你也能有解决问题的方向。

2.2.1 编写创建view菜单时的跳转URL代码
  • 代码回顾
        WeixinMenu subMenu3_0 = new WeixinMenu();
        subMenu3_0.setName("查看余额");
        subMenu3_0.setType(ButtonType.view);
        subMenu3_0.setUrl(SERVER_ROOT_URL + "/redirect/redirecttocashout");

配置的URL是:SERVER_ROOT_URL + “/redirect/redirecttocashout”。
SERVER_ROOT_URL :这是访问你服务器根路径的变量

  • 上面的配置,意思是当你点【查看余额】菜单时,就会向你指定的服务器中,由微信平台发起一个 /redirect/redirecttocashout 请求。
现在问题来了,微信后台如何能知道我们服务器的根URL是多少呢?
所以在这里,你需要再到微信公众后台配置一个访问你服务器的根路径信息

2.2.2 配置网页授权

在这里插入图片描述点击【修改】,进行访问根URL配置
在这里插入图片描述
将图片中第3步的文件下载来,放到你的后台工程中 /resources/static 目录下。
域名1:配置外网访问你服务器的域名或是外网IP

如何确定文件放对了位置:访问工程URL+第3步中的文件名。如果可以成功访问,则说明成功。
如果你在访问时,报401之类错误,则说明被你的权限框架拦截了,配置文件URL放行即可。

2.2.3 编写跳转的control逻辑

关于公众号view界面跳转带授权的逻辑将都会写在WeixinRedirectController.java类中

  • 处理/redirect/redirecttocashoutURL逻辑
//公众号view跳转并获取openid的跳转操作
@Controller
@RequestMapping("/redirect")
public class WeixinRedirectController {
    @Value("${weixinGZH.appid}")
    private String WEIXIN_GZH_APPID;
    @Value("${weixinGZH.secret}")
    private String WEIXIN_GZH_SECRET;
    @Value("${SERVER_ROOT_URL}")
    private String SERVER_ROOT_URL;

    /**
     * 重定向到【我的余额】
     *
     * @param
     * @return java.lang.String
     * @author caiwen
     */
    @RequestMapping("/redirecttocashout")
    public String redirectToCashout() {
        return "redirect:https://open.weixin.qq.com/connect/oauth2/authorize?appid="
                + WEIXIN_GZH_APPID + "&redirect_uri=" + SERVER_ROOT_URL
                + "/redirect/weixinoauth&response_type=code&scope=snsapi_base&state=" + STATE_CASHOUT + "#wechat_redirect";
    }
}

关键参数state,这个值是用于区分后面oauth认证成功后,到底是点的哪个菜单。

  • 跳转到微信公众平台的oauth认证的统一方法
@RequestMapping("/weixinoauth")
    public String weixinOauth(String code, String state) {
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="
                + WEIXIN_GZH_APPID + "&secret=" + WEIXIN_GZH_SECRET + "&code=" + code + "&grant_type=authorization_code";
        HttpClient httpClient = new HttpClient(url);
        String content = "";
        try {
            httpClient.get();
            content = httpClient.getContent();
        } catch (Exception e) {
            e.printStackTrace();
        }
        String openid = JSONObject.parseObject(content).getString("openid");
        LoggerFactory.getLogger(getClass()).error("================content=" + content + ",openid=" + openid);
        String redirect = "";
        if (StringUtils.isBlank(openid)) {
            return null;
        }
        //根据state的值,决定在拿到了用户openid的情况下往哪里跳
        switch (state) {
            case STATE_CASHOUT:
                redirect = "真正要跳转到你自己页面的URL,可以是一个后台请求URL也可以直接是一个界面地址。"
                break;
        }
        return "redirect:" + redirect;
    }

到此,通过自定义菜单跳转个人界面,同时获取当前点击按钮的微信用户的信息(openid)

下一篇将会介绍 微信支付 充值功能实现

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章