爱听音乐的狗

有趣,古怪,奇异

士不可以不弘毅,任重而道远


微信公众号获取Access_token与自定义菜单创建

获取access_token

获取access_token微信公众号官方文档

1、access_token简单说明

access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token,获取到access_token之后应将值进行保存,而不是每次都调用接口进行获取;服务器会返回expire_in(有效时间,单位秒),当expire_in过期之后再调用接口刷新access_token的值。

在调用接口获取access_token,需要参数AppID与AppSecret,AppID和AppSecret可在“微信公众平台-开发-基本配置”页中获得(需要已经成为开发者,且帐号没有异常状态)

接口调用请求说明:

https请求方式: GET
/**
*  grant_type     获取access_token填写client_credential
*  appid    第三方用户唯一凭证
*  secret    第三方用户唯一凭证密钥,即appsecret
*/
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

2、获取access_token 示例

在类WxService中,将appid、appsecret以及获取access_token的URL设置为静态常量;提供一个私有类方法用于调用微信接口获取access_token以及expires_in,并将值进行保存;再提供一个公共类方法,用于获取保存的值,如果保存的值为空或者时间已过期,就调用所提供的私有类方法获取值。

Java示例代码

//获取ACCESS_TOKEN的URL
private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
//appID
private static final String APPID = "wx503297a5bc732744";
//appsecret
private static final String APPSECRET = "ab7c6be47ffe47ef4b44d13502afc60a";

示例方法

/**
 * 获取AccessToken
 */
private static void getCurrentAccessToken() {
    String url = ACCESS_TOKEN_URL.replace("APPID", APPID).replace("APPSECRET",APPSECRET);
    try {
        //调用GET方法获取数据
        String jsonStr = NetManagerUtil.net(url,null,"GET");
        //将json字符串转为对象
        JSONObject jsonObject = JSON.parseObject(jsonStr);
        AccessToken accessToken = new AccessToken(jsonObject.getString("access_token"), jsonObject.getString("expires_in"));
        cuttentAccessToken = accessToken;
    } catch (Exception e) {
        e.printStackTrace();
    }

}

public static String getAccessToken() {
    //如果token不存在或者token过期就去获取token
    if (cuttentAccessToken == null || cuttentAccessToken.isExpires()) {
        getCurrentAccessToken();
    }
    return cuttentAccessToken.getToken();
}

在”getCurrentAccessToken”方法中用到了”NetManagerUtil”类中的”net”方法进行网络请求
“JSONObject”需要导入”fastjson”的jar包
AccessToken是新建的pojo类用于存放access_token与过期时间
“cuttentAccessToken”是类型为”AccessToken”的静态私有变量

(1) 编写”NetManagerUtil”类中的”net”方法进行网络请求

“NetManagerUtil”类中静态常量

public static final String DEF_CHATSET = "UTF-8";
public static final int DEF_CONN_TIMEOUT = 30000;
public static final int DEF_READ_TIMEOUT = 30000;

网络请求方法

/**
 *
 * @param strUrl 请求地址
 * @param params 请求参数
 * @param method 请求方法
 * @return  网络请求字符串
 * @throws Exception
 */
public static String net(String strUrl, Map params,String method) throws Exception {
    HttpURLConnection conn = null;
    BufferedReader reader = null;
    String rs = null;
    try {
        StringBuffer sb = new StringBuffer();
        //GET方法链接设置
        if(method==null || method.equals("GET")){
            if (params!= null) {
                strUrl = strUrl+"?"+urlencode(params);
            }
        }
        URL url = new URL(strUrl);
        //开连接
        conn = (HttpURLConnection) url.openConnection();
        //设置请求方式
        if(method==null || method.equals("GET")){
            conn.setRequestMethod("GET");
        }else{
            conn.setRequestMethod("POST");
            conn.setDoOutput(true);
        }
        //是否缓存
        conn.setUseCaches(false);
        //过期时间
        conn.setConnectTimeout(DEF_CONN_TIMEOUT);
        conn.setReadTimeout(DEF_READ_TIMEOUT);
        //是否重定向
        conn.setInstanceFollowRedirects(false);
        //连接
        conn.connect();
        //POST方法设置
        if (params!= null && method.equals("POST")) {
            try {
                //输出流
                DataOutputStream out = new DataOutputStream(conn.getOutputStream());
                out.writeBytes(urlencode(params));
            } catch (Exception e) {
                // TODO: handle exception
            }
        }
        //读取输入流
        InputStream is = conn.getInputStream();
        reader = new BufferedReader(new InputStreamReader(is, DEF_CHATSET));
        String strRead = null;
        while ((strRead = reader.readLine()) != null) {
            sb.append(strRead);
        }
        System.out.println(sb.toString());
        rs = sb.toString();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (reader != null) {
            reader.close();
        }
        if (conn != null) {
            conn.disconnect();
        }
    }
    return rs;
}

//将map型转为请求参数型
public static String urlencode(Map<String,Object>data) {
    StringBuilder sb = new StringBuilder();
    for (Map.Entry i : data.entrySet()) {
        try {
            sb.append(i.getKey()).append("=").append(URLEncoder.encode(i.getValue()+"","UTF-8")).append("&");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }
    return sb.toString();
}

(2) 在pom.xml中导入”fastjson”的jar包

<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>fastjson</artifactId>
  <version>1.1.41</version>
  <scope>compile</scope>
</dependency>

(3) 新建名为 AccessToken 的pojo类,并添加变量以及构造方法以及判断token是否过期的方法

/**
 * 成功的token
 */
private String token;
/**
 * 过期时间
 */
private String expiresTimeout;

public String getToken() {
    return token;
}

public void setToken(String token) {
    this.token = token;
}

public String getExpiresTimeout() {
    return expiresTimeout;
}

public void setExpiresTimeout(String expiresTimeout) {
    this.expiresTimeout = expiresTimeout;
}

/**
 * 构造方法
 * @param token     token
 * @param expiresIn 获取到的时间
 */
public AccessToken(String token, String expiresIn) {
    this.token = token;
    this.expiresTimeout = System.currentTimeMillis() + Integer.parseInt(expiresIn) * 1000 +"";
}

/**
 * 是否过期
 * @return
 */
public boolean isExpires() {
    return System.currentTimeMillis() > Long.parseLong(this.expiresTimeout);
}

(4) 在WxService类中添加静态私有变量

private static AccessToken cuttentAccessToken;

3 、获取access_token测试

新建名为WxTest的测试类,编写获取access_token的测试方法进行测试

/**
 * 获取token
 */
@Test
public void getToken() {
    System.out.println(WxService.getAccessToken());
    System.out.println(WxService.getAccessToken());
}

自定义菜单的创建

自定义菜单创建微信公众号官方文档

1、自定义菜单简单说明

自定义菜单最多包括3个一级菜单,每个一级菜单最多包含5个二级菜单;一级菜单最多4个汉字,二级菜单最多7个汉字;测试时可以尝试取消关注公众账号后再次关注,则可以看到创建后的效果

自定义菜单的按钮类型有很多,比如click、view、scancode_push、scancode_waitmsg等;菜单的创建以click、view两种进行示例,其他按钮方式所传入的json数据格式参考自定义菜单创建微信公众号官方文档

接口调用请求说明:

http请求方式:POST(请使用https协议)
[https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN](https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN)

2、json字符串所对应的对象封装

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

通过这段示例可以看出创建按钮需传入一段json字符串,而且一个button键对应按钮所形成的数组(一级菜单),在按钮数组中还存在sub_button键所对应的子按钮数组(二级菜单);所以最外层可以创建为WxButton类,在类中只有一个属性,属性名为button,类型为List。观察发现每个按钮都有name字段,所以创建一个BaseButton抽象类,再类中只提供一个属性,属性名为name,类型为String。每个不同类型的按钮都继承自BaseButton类去构建不同类型的pojo类;如果菜单中包含二级菜单,就创建类继承自BaseButton并提供一个名为sub_button的List类型的属性,来代表一级菜单并包含子菜单这种情形。

创建抽象类”BaseButton”

/**
 * 菜单名字
 */
private String name;

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public BaseButton(String name) {
    this.name = name;
}

创建类型为Click的ClickButton类,并继承自BaseButton

/**
 * 菜单类型
 */
private String type = "click";
/**
 * 唯一键
 */
private String key;

public String getType() {
    return type;
}

public void setType(String type) {
    this.type = type;
}

public String getKey() {
    return key;
}

public void setKey(String key) {
    this.key = key;
}

public ClickButton(String name, String key) {
    super(name);
    this.key = key;
}

创建按钮类型为View的ViewButton类,并继承自BaseButton

/**
 * 菜单类型
 */
private String type = "view";
/**
 * 跳转地址
 */
private String url;

public String getType() {
    return type;
}

public void setType(String type) {
    this.type = type;
}

public String getUrl() {
    return url;
}

public void setUrl(String url) {
    this.url = url;
}

public ViewButton(String name, String url) {
    super(name);
    this.url = url;
}

创建有子菜单的菜单,类名为SubButton,继承自BaseButton

private List<BaseButton> sub_button = new ArrayList<>();

public List<BaseButton> getSub_button() {
    return sub_button;
}

public void setSub_button(List<BaseButton> sub_button) {
    this.sub_button = sub_button;
}

public SubButton(String name) {
    super(name);
}

创建名为WxButton的类用于生成最终json字符串的类

private List<BaseButton> button = new ArrayList<>();

public List<BaseButton> getButton() {
    return button;
}

public void setButton(List<BaseButton> button) {
    this.button = button;
}

3、利用封装的pojo创建自定义菜单

常见名为”CreatButtonUtil”的类,在main方法中调用creatWxButton私有类方法进行菜单的创建

(1) 将所需要用到的文字定义为静态常量

private static final String CREAT_MENU_URL = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";

private static final String ONE_MENU_TITLE = "查找路线";
public static final String ONE_MENU_TITLEKEY = "查找路线KEY";

private static final String TWO_MENU_TITLE = "产品服务";
private static final String TWO_MENU_SUBTITLE_ONE = "服务范围";
private static final String TWO_MENU_SUBTITLE_ONEURL = "http://www.epochyoosure.com/fangan/";
private static final String TWO_MENU_SUBOTITLE_TWO = "服务项目";
private static final String TWO_MENU_SUBTITLE_TWOURL = "http://www.epochyoosure.com/a/youxuechanpin/";
private static final String TWO_MENU_SUBTITLE_THREE = "新闻资讯";
private static final String TWO_MENU_SUBTITLE_THREEURL = "http://www.epochyoosure.com/zixun/";

private static final String THREE_MENU_TITLE = "艾派格";
private static final String THREE_SUBTITLE_ONE = "私人订制";
private static final String THREE_SUBTITLE_ONEKEY = "私人订制KEY";
private static final String THREE_SUBTITLE_TWO = "关于我们";
private static final String THREE_MENU_SUBTITLE_THREEURL = "http://www.epochyoosure.com/index.html";

(2) 创建”creatWxButton”私有类方法,在方法中创建菜单对象,并将对象转为json字符串, 调用”NetManagerUtil”所提供的post方法请求网络,传入所需要的参数,创建菜单

private static void creatWxButton() {
    //第一个菜单
    ClickButton oneButton = new ClickButton(ONE_MENU_TITLE,ONE_MENU_TITLEKEY);
    //第二个菜单
    SubButton twoButton = new SubButton(TWO_MENU_TITLE);
    //第二个菜单的子菜单
    ViewButton oneSubButton = new ViewButton(TWO_MENU_SUBTITLE_ONE,TWO_MENU_SUBTITLE_ONEURL);
    ViewButton twoSubButton = new ViewButton(TWO_MENU_SUBOTITLE_TWO,TWO_MENU_SUBTITLE_TWOURL);
    ViewButton threeSubButton = new ViewButton(TWO_MENU_SUBTITLE_THREE,TWO_MENU_SUBTITLE_THREEURL);
    twoButton.getSub_button().add(threeSubButton);
    twoButton.getSub_button().add(twoSubButton);
    twoButton.getSub_button().add(oneSubButton);
    //第三个菜单
    SubButton threeButton = new SubButton(THREE_MENU_TITLE);
    //第三个菜单的子菜单
    ClickButton subButtonOne = new ClickButton(THREE_SUBTITLE_ONE,THREE_SUBTITLE_ONEKEY);
    ViewButton subButtonTwo = new ViewButton(THREE_SUBTITLE_TWO,THREE_MENU_SUBTITLE_THREEURL);
    threeButton.getSub_button().add(subButtonOne);
    threeButton.getSub_button().add(subButtonTwo);
    //添加到button对象中
    WxButton wxButton = new WxButton();
    wxButton.getButton().add(oneButton);
    wxButton.getButton().add(twoButton);
    wxButton.getButton().add(threeButton);
    //转json
    String jsonStr = JSONObject.toJSONString(wxButton);
    //替换token
    String url = CREAT_MENU_URL.replace("ACCESS_TOKEN", WxService.getAccessToken());
    //调用网络请求
    NetManagerUtil.post(url,jsonStr);
}

(3) 类”NetManagerUtil”类中添加post方法

/**
 * pust 请求
 * @param url  请求的url
 * @param data 请求的data
 * @return 返回json字符串
 */
public static String post(String url,String data){
    try {
        URL urlObj = new URL(url);
        //开链接
        URLConnection connection = urlObj.openConnection();
        //要发送数据出去,需要设置为可发送数据状态
        connection.setDoOutput(true);
        //是否缓存
        connection.setUseCaches(false);
        //过期时间
        connection.setConnectTimeout(DEF_CONN_TIMEOUT);
        connection.setReadTimeout(DEF_READ_TIMEOUT);
        //获取输出流
        OutputStream outputStream = connection.getOutputStream();
        //写出数据
        if (data != null) {
            outputStream.write(data.getBytes());
        }
        outputStream.close();
        //获取输入流
        InputStream is = connection.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(is, DEF_CHATSET));
        String strRead = null;
        StringBuffer sb = new StringBuffer();

        while ((strRead = reader.readLine()) != null) {
            sb.append(strRead);
        }
        System.out.println(sb.toString());
        return sb.toString();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

(4) 在此类的main方法中调用”creatWxButton”方法

public static void main(String[] args) {
    creatWxButton();
}

(5) 运行main方法

控制台打印”{“errcode”:0,”errmsg”:”ok”}”,就创建成功

提醒
在公众号中点击自定义菜单会收到自定义菜单事件,部分按钮类型需要对事件进行处理以对用户的操作进行响应,后续将持续更新消息事件的接收与回复

最近的文章

微信公众号的开发环境搭建与接入

开发环境的搭建1、进入Ngrok官网,下载客户端 2、选择需要下载的版本并解压 3、注册ngrok账号并登陆,在隧道管理页进行隧道的开通 4、 填写隧道信息 5、隧道连接 在开通隧道之后会产生一个隧道id,可以在终端中根据隧道id进行连接,当终端出现在线时,代表连接成功,这时其他人就可以通过 …

公众号开发 继续阅读
更早的文章

Maven创建Web工程以及SSM框架目录结构的搭建

创建Web工程1、选择”File”—&gt;”New”—&gt;”Project”,如图所示: 2、在弹出的视图左侧选择”Maven”,右侧选择SDK,并勾选上”Create from archetype”选择框,选择”org.apache.maven.archetypes:maven-arche …

Java 继续阅读