微信公众号的二次开发(二 自定义菜单的创建)

在上篇《微信公众号的二次开发(一)》我们介绍了微信订阅号的一些坑,
以及微信公众平台开发的一些基本配置。下面我们继续介绍如何通过用户关注等行为。获取用户的openid.

自定义微信公众号菜单

在交互行为之前,首先我们可以从后台自己生成菜单。下面直接贴代码:

import lombok.Data;

/**
 * @ClassName Button
 * @Description TODO
 * @Author Administrator
 * @Date 2019/6/11 10:59
 * @Version 1.0
 * @description: 菜单项的基类  
**/ @Data public class Button { private String name;//所有一级菜单、二级菜单都共有一个相同的属性,那就是name }
import lombok.Data;

/**
 * @ClassName CommonButton
 * @Description TODO
 * @Author Administrator
 * @Date 2019/6/11 13:33
 * @Version 1.0
 * @description: 子菜单项 :没有子菜单的菜单项,有可能是二级菜单项,也有可能是不含二级菜单的一级菜单。 
**/ @Data public class CommonButton extends Button{ private String type; private String key; private String url; }
/**
 * @ClassName ComplexButton
 * @Description TODO
 * @Author Administrator
 * @Date 2019/6/11 13:34
 * @Version 1.0
 * @description: 父菜单项 :包含有二级菜单项的一级菜单。这类菜单项包含有二个属性:name和sub_button,而sub_button以是一个子菜单项数组 
**/ @Data public class ComplexButton extends Button { private Button[] sub_button; }
/**
 * @ClassName Menu
 * @Description TODO
 * @Author Administrator
 * @Date 2019/6/11 13:35
 * @Version 1.0
 * @description:  整个菜单对象的封装 
**/ @Data public class Menu { private Button[] button; }

下面是创建菜单的main方法

import com.hbrc.hbrcpublicserver.utils.WeiXinUtils;
import com.hbrc.hbrcpublicserver.web.model.wx.AccessToken;

/**
 * @ClassName MenuManager
 * @Description TODO
 * @Author Administrator
 * @Date 2019/6/11 13:49
 * @Version 1.0*
 * @Description:菜单管理器类 
* **/ public class MenuManager { public static void main(String[] args) { // 调用接口获取access_token AccessToken at = WeiXinUtils.getAccessToken(); if (null != at) { // 调用接口创建菜单 int result = WeiXinUtils.createMenu(getMenu(), at.getToken()); // 判断菜单创建结果 if (0 == result) System.out.println("菜单创建成功!"); else System.out.println("菜单创建失败,错误码:" + result); } } /** * 组装菜单数据 * * @return */ private static Menu getMenu () { CommonButton btn11 = new CommonButton(); btn11.setName("名医访谈"); btn11.setType("click"); btn11.setKey("11"); CommonButton btn12 = new CommonButton(); btn12.setName("名医讲堂"); btn12.setType("click"); btn12.setKey("12"); CommonButton btn21 = new CommonButton(); btn21.setName("名医答疑"); btn21.setType("click"); btn21.setKey("21"); CommonButton btn22 = new CommonButton(); btn22.setName("疾病百科"); btn22.setType("view"); btn22.setUrl("http://www.mdline.cn/disease-knowledge"); CommonButton btn31 = new CommonButton(); btn31.setName("随访预告"); btn31.setType("click"); btn31.setKey("31"); CommonButton btn32 = new CommonButton(); btn32.setName("健康档案"); btn32.setType("click"); btn32.setKey("32"); /** * 微信: mainBtn1,mainBtn2,mainBtn3底部的三个一级菜单。 */ ComplexButton mainBtn1 = new ComplexButton(); mainBtn1.setName("名医风采"); //一级下有2个子菜单 mainBtn1.setSub_button(new CommonButton[]{btn11, btn12}); ComplexButton mainBtn2 = new ComplexButton(); mainBtn2.setName("疾病科普"); mainBtn2.setSub_button(new CommonButton[]{btn21, btn22}); ComplexButton mainBtn3 = new ComplexButton(); mainBtn3.setName("个人中心"); mainBtn3.setSub_button(new CommonButton[]{btn31, btn32}); /** * 封装整个菜单 */ Menu menu = new Menu(); menu.setButton(new Button[]{mainBtn1, mainBtn2, mainBtn3}); return menu; } }

上面主要用到的WeiXinUtils类也贴在下面:

import com.alibaba.fastjson.JSONObject;
import com.hbrc.hbrcpublicserver.entity.wxmenu.Menu;
import com.hbrc.hbrcpublicserver.web.model.wx.AccessToken;
import com.hbrc.hbrcpublicserver.web.model.wx.ProjectConst;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import java.io.*;
import java.net.ConnectException;
import java.net.URL;

/**
 * @ClassName WeiXinUtils
 * @Description TODO
 * @Author Administrator
 * @Date 2019/6/10 15:23
 * @Version 1.0
 **/
public class WeiXinUtils{

    /**
     * Get请求,方便到一个url接口来获取结果
     * @param url
     * @return
     */
    public static JSONObject doGetStr(String url){
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet(url);
        JSONObject jsonObject = null;
        try{
            HttpResponse response = httpClient.execute(httpGet);
            HttpEntity entity = response.getEntity();
            if(entity != null){
                String result = EntityUtils.toString(entity, "UTF-8");
                jsonObject = JSONObject.parseObject(result);
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return jsonObject;
    }


    /**
     * 获取access_token
     * @return
     */
    public static AccessToken getAccessToken(){
        AccessToken accessToken = new AccessToken();
        String url = ACCESS_TOKEN_URL.replace("APPID" ,APPID).replace("APPSECRET",APPSECRET);
        JSONObject jsonObject = doGetStr(url);
        if(jsonObject !=null){
            accessToken.setToken(jsonObject.getString("access_token"));
            accessToken.setExpireIn(jsonObject.getInteger("expires_in"));
        }
        return accessToken;
    }


    /**
     * 创建菜单
     *
     * @param menu 菜单实例
     * @param accessToken 有效的access_token
     * @return 0表示成功,其他值表示失败
     */
    public static int createMenu(Menu menu, String accessToken) {
        int result = 0;
        // 拼装创建菜单的url
        String url = menu_create_url.replace("ACCESS_TOKEN", accessToken);
        // 将菜单对象转换成json字符串
        String jsonMenu = JSONObject.toJSONString(menu);
        // 调用接口创建菜单
        JSONObject jsonObject = httpRequest(url, "POST", jsonMenu);
        if (null != jsonObject) {
            if (0 != jsonObject.getInteger("errcode")) {
                result = jsonObject.getInteger("errcode");
                System.out.println("创建菜单失败 errcode:{} errmsg:{}"+jsonObject.getInteger("errcode")+jsonObject.getString("errmsg"));
            }
        }

        return result;
    }


    /**
     * 描述:  发起https请求并获取结果
     * @param requestUrl 请求地址
     * @param requestMethod 请求方式(GET、POST)
     * @param outputStr 提交的数据
     * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
     */
    public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) {
        JSONObject jsonObject = null;
        StringBuffer buffer = new StringBuffer();
        try {
            // 创建SSLContext对象,并使用我们指定的信任管理器初始化
            TrustManager[] tm = { new MyX509TrustManager() };
            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(requestMethod);

            if ("GET".equalsIgnoreCase(requestMethod))
                httpUrlConn.connect();

            // 当有数据需要提交时
            if (null != outputStr) {
                OutputStream outputStream = httpUrlConn.getOutputStream();
                // 注意编码格式,防止中文乱码
                outputStream.write(outputStr.getBytes("UTF-8"));
                outputStream.close();
            }

            // 将返回的输入流转换成字符串
            InputStream inputStream = httpUrlConn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

            String str = null;
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }
            bufferedReader.close();
            inputStreamReader.close();
            // 释放资源
            inputStream.close();
            inputStream = null;
            httpUrlConn.disconnect();
            jsonObject = JSONObject.parseObject(buffer.toString());
        } catch (ConnectException ce) {
        } catch (Exception e) {
        }
        return jsonObject;
    }
}

因为需要请求https这里需要在添加一个信任管理器。

import javax.net.ssl.X509TrustManager;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

/**
 * @ClassName MyX509TrustManager
 * @Description TODO
 * @Author Administrator
 * @Date 2019/6/11 13:38
 * @Version 1.0
 * @description: 证书信任管理器(用于https请求)  
**/ public class MyX509TrustManager 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 null; } }

上面WeiXinUtils继承的ProjectConst类:

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;

/**
 * @ClassName ProjectConst
 * @Description TODO
 * @Author Administrator
 * @Date 2019/6/10 14:37
 * @Version 1.0
 **/
@Data
public class ProjectConst {
    /**
     * 用于获取当前与微信公众号交互的用户信息的接口(一般是用第一个接口地址)
     */
    public static final String GET_WEIXIN_USER_URL = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID";
    public final static String GetPageUsersUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";

    /**
     * 用于进行网页授权验证的接口URL,通过这个才可以得到opendID等字段信息
     */
    public final static String GET_WEBAUTH_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";

    /**
     * 用于进行当点击按钮的时候,能够在网页授权之后获取到code,再跳转到自己设定的一个URL路径上的接口,这个主要是为了获取之后于
     * 获取openId的接口相结合
     * 注意:参数:toselfURL  表示的是当授权成功后,跳转到的自己设定的页面,所以这个要根据自己的需要进行修改
     */
    public final static String Get_WEIXINPAGE_Code = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=toselfURL&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect";
    /**
     * 获取access_token的URL
     */
    public static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
    public static final String APPID=  "xxxxxxxxxxx";

    public static final String APPSECRET="xxxxxxxxxxxxx";

    // 获取access_token的接口地址(GET) 限200(次/天)
    public final static String access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";

    // 菜单创建(POST) 限100(次/天)
    public static String menu_create_url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";

}

运行MenuManager类中的main方法即可创建成功。有一点需要注意,在获取access_token时需要在微信公众号管理平台配置IP白名单.

你可能感兴趣的:(微信公众号的二次开发(二 自定义菜单的创建))