首頁 微信小程式 微信開發 java微信開發API微信自訂個人化選單實作實例程式碼

java微信開發API微信自訂個人化選單實作實例程式碼

Mar 21, 2017 pm 03:46 PM
api java 微信開發

這篇文章主要為大家詳細介紹了java微信開發API第四步,自訂選單以及個人化選單實現,有興趣的夥伴們可以參考一下

微信如何實現自訂個性化選單,以下為大家介紹

一、全域說明
詳細說明請參考前兩篇文章。

二、本文說明
本文分為五部分:
    * 工具類別AccessTokenUtils的封裝
    * 自訂選單與個人化選單文件的閱讀解析
    * 選單JSON的分析以及建立對應bean
    * 自訂選單的實作
    * 個人化選單的實作
微信自訂選單所有類型選單都給出示範
#本文結束會給出包括本文前四篇文章的所有演示原始碼

工具類AccessTokenUtils的封裝
在上文中關於AccessToken的取得和定時保存已經詳細介紹過,此處直接給出處理過之後封裝的AccessTokenUtils,實作原理以及文件閱讀不再給。
AccessTokenUtils.java


package com.gist.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;

import javax.net.ssl.HttpsURLConnection;

import com.gist.bean.Access_token;
import com.google.gson.Gson;

/**
 * @author 高远</n> 邮箱:wgyscsf@163.com</n> 博客 http://blog.csdn.net/wgyscsf</n>
 *   编写时期 2016-4-7 下午5:44:33
 */
public class AccessTokenUtils {
 private static final long MAX_TIME = 7200 * 1000;// 微信允许最长Access_token有效时间(ms)
 private static final String TAG = "WeixinApiTest";// TAG
 private static final String APPID = "wx889b020b3666b0b8";// APPID
 private static final String SECERT = "6da7676bf394f0a9f15fbf06027856bb";// 秘钥

 /*
  * 该方法实现获取Access_token、保存并且只保存2小时Access_token。如果超过两个小时重新获取;如果没有超过两个小时,直接获取。该方法依赖
  * :public static String getAccessToken();
  * 
  * 思路:将获取到的Access_token和当前时间存储到file里,
  * 取出时判断当前时间和存储里面的记录的时间的时间差,如果大于MAX_TIME,重新获取,并且将获取到的存储到file替换原来的内容
  * ,如果小于MAX_TIME,直接获取。
  */
 // 为了调用不抛异常,这里全部捕捉异常,代码有点长
 public static String getSavedAccess_token() {
  Gson gson = new Gson();// 第三方jar,处理json和bean的转换
  String mAccess_token = null;// 需要获取的Access_token;
  FileOutputStream fos = null;// 输出流
  FileInputStream fis = null;// 输入流
  File file = new File("temp_access_token.temp");// Access_token保存的位置
  try {
   // 如果文件不存在,创建
   if (!file.exists()) {
    file.createNewFile();
   }
  } catch (Exception e1) {
   e1.printStackTrace();
  }
  // 如果文件大小等于0,说明第一次使用,存入Access_token
  if (file.length() == 0) {
   try {
    mAccess_token = getAccessToken();// 获取AccessToken
    Access_token at = new Access_token();
    at.setAccess_token(mAccess_token);
    at.setExpires_in(System.currentTimeMillis() + "");// 设置存入时间
    String json = gson.toJson(at);
    fos = new FileOutputStream(file, false);// 不允许追加
    fos.write((json).getBytes());// 将AccessToken和当前时间存入文件
    fos.close();
    return mAccess_token;
   } catch (Exception e) {
    e.printStackTrace();
   }
  } else {
   // 读取文件内容
   byte[] b = new byte[2048];
   int len = 0;
   try {
    fis = new FileInputStream(file);
    len = fis.read(b);
   } catch (IOException e1) {
    // TODO Auto-generated catch block
    e1.printStackTrace();
   }
   String mJsonAccess_token = new String(b, 0, len);// 读取到的文件内容
   Access_token access_token = gson.fromJson(mJsonAccess_token,
     new Access_token().getClass());
   if (access_token.getExpires_in() != null) {
    long saveTime = Long.parseLong(access_token.getExpires_in());
    long nowTime = System.currentTimeMillis();
    long remianTime = nowTime - saveTime;
    // System.out.println(TAG + "时间差:" + remianTime + "ms");
    if (remianTime < MAX_TIME) {
     Access_token at = gson.fromJson(mJsonAccess_token,
       new Access_token().getClass());
     mAccess_token = at.getAccess_token();
     return mAccess_token;
    } else {
     mAccess_token = getAccessToken();
     Access_token at = new Access_token();
     at.setAccess_token(mAccess_token);
     at.setExpires_in(System.currentTimeMillis() + "");
     String json = gson.toJson(at);
     try {
      fos = new FileOutputStream(file, false);// 不允许追加
      fos.write((json).getBytes());
      fos.close();
     } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
     return mAccess_token;
    }

   } else {
    return null;
   }
  }

  return mAccess_token;
 }

 /*
  * 获取微信服务器AccessToken。该部分和getAccess_token() 一致,不再加注释
  */
 public static String getAccessToken() {
  String urlString = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="
    + APPID + "&secret=" + SECERT;
  String reslut = null;
  try {
   URL reqURL = new URL(urlString);
   HttpsURLConnection httpsConn = (HttpsURLConnection) reqURL
     .openConnection();
   InputStreamReader isr = new InputStreamReader(
     httpsConn.getInputStream());
   char[] chars = new char[1024];
   reslut = "";
   int len;
   while ((len = isr.read(chars)) != -1) {
    reslut += new String(chars, 0, len);
   }
   isr.close();
  } catch (IOException e) {

   e.printStackTrace();
  }
  Gson gson = new Gson();
  Access_token access_token = gson.fromJson(reslut,
    new Access_token().getClass());
  if (access_token.getAccess_token() != null) {
   return access_token.getAccess_token();
  } else {
   return null;
  }
 }
}
登入後複製

#自訂選單和個人化選單文件的閱讀解析
##•自定義選單
◦自訂選單建立介面
 ◦自訂功能表查詢介面
 ◦自訂功能表刪除介面
 ◦自訂功能表事件推送
 ◦個人化◦介面介面
 取得公眾號的選單設定

 •文件地址:

http://mp.weixin.qq.com/wiki/10/0234e39a2025342c17a7d23595c6b40a.html## •網文件給出這樣解釋:
* 自訂選單介面可實現多種類型按鈕,如下:1、click:點選事件...;2、view:跳轉事件...;3、...(關於自訂選單)
* 介面呼叫請求說明http請求方式:POST(請使用https協定)
https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN
(關於自訂選單)* click和view的請求範例{"button":[...]}  (關於自訂選單)* 參數說明...(關於自訂選單)
* 建立個人化選單http請求方式:POST(請使用https協定)
https://api.weixin.qq.com/cgi-bin/menu/addconditional?access_token=ACCESS_TOKEN(
關於個人化選單)* 請求範例: {"button":[...],"matchrule":{...}}(關於個人化選單)* 參數說明...(關於個人化選單)
* 開發者可以透過以下條件來設定使用者看到的選單(關於個人化選單):
    1、使用者分組(開發者的業務需求可以藉助使用者分組完成)
    2、性別
    3、手機作業系統
    4、地區(使用者設定在微信客戶端的區域)
    5、語言(使用者在微信客戶端設定的語言)

 •瞭解:

◦又是熟悉的POST請求,但是,關於調用貌似說的含糊其辭,不太明白。只是知道我們需要使用「?access_token=ACCESS_TOKEN」這個參數,這個參數我們在上篇文章已經取得了。假如我們將微信文件給的那個請求地址中“ACCESS_TOKEN”換成我們獲取到的自己的ACCESS_TOKEN,訪問該網址,會看到“{“errcode”:44002,”errmsg”:”empty post data hint: [ Gdveda0984vr23]”}」。大概意思是,空的post請求資料。所以,我們要透過POST請求的形式傳遞參數給微信伺服器,在文檔下面也給了參數的格式:{“button”:[…]},所以,我們要按照該格式給微信伺服器進行傳遞參數。

 ◦關於參數說明,我們可以看到在自訂選單建立中有七個參數。在個人化選單介面中除去這七個參數之外,另外多個八個參數。簡單查看此部分文檔,我們可以了解到這個八個參數是為了個性化菜單做匹配篩選用的。
 ◦現在,我們需要按照微信文檔的要求建構json透過post的請求向微信伺服器發送這一串json數據,json裡面就包括我們創建的各種類型的按鈕事件。

選單JSON的分析以及建立對應bean
 自訂選單json分析(不包括個人化選單)。下面這段程式碼是微信文檔給的範例。
click和view的請求範例

 {
  "button":[
  { 
   "type":"click",
   "name":"今日歌曲",
   "key":"V1001_TODAY_MUSIC"
  },
  {
   "name":"菜单",
   "sub_button":[
   { 
    "type":"view",
    "name":"搜索",
    "url":"http://www.soso.com/"
   },
   {
    "type":"view",
    "name":"视频",
    "url":"http://v.qq.com/"
   },
   {
    "type":"click",
    "name":"赞一下我们",
    "key":"V1001_GOOD"
   }]
  }]
 }
登入後複製

经过分析我们可以看到这串json数据分为三层:“”button”:[{…},{…}]”、“[{…},{{“name”:菜单,”sub_button”:[{},{}]}]”、“{“type”:”view”,”name:”:”视频”,”url”:”…”},{},{}”,可能看起来比较晕。
但是,如果我们能够联想起来现实中看到的微信菜单,就会好理解一点:一级:菜单(一个菜单),下包括一到三个父按钮;二级:父按钮(1~3个父按钮),下包括一到五个子按钮;三级:子按钮(1~5个子按钮)。
现在,我们可以看到json和我们理解的“菜单”可以一一对应起来了。现在重点是如何确认每一级的“级名”,在java中也就是对应的javabean对象。
同时,因为一级菜单下会有多个父按钮,所以是一个List<父菜单>的形式。父按钮下可能有多个子菜单,也是一个 List<子菜单>;但是,父按钮也有可能也是一个单独的可以响应的按钮。是一个单独的父按钮对象。子按钮就是一个单独的子按钮对象。
查看关于自定义菜单的参数说明,我们可以看到按钮分为一级按钮(“button”)和二级按钮(“sub_button”)。还有一些公用的数据类型,例如:菜单响应类型(“type”)、菜单标题(“name”)、click类型的参数(“key”)、view类型的参数(“url”)、media_id类型和view_limited类型的参数(“media_id”)。
•数据抽象(没有写setter,getter):


//按钮基类
public class BaseButton {
 private String type;
 private String name;
 private String key;
 private String url;
 private String media_id;
} 
//子按钮
public class SonButton extends BaseButton {
 private String sub_button;
}
//父按钮
public class FatherButton extends BaseButton {
private String button;//可能直接一个父按钮做响应
@SerializedName("sub_button")//为了保证Gson解析后子按钮的名字是“sub_button”,具体用法请搜索
private List<SonButton> sonButtons;//可能有多个子按钮
}

public class Menu {
@SerializedName("button")
private List<FatherButton> fatherButtons;
}
登入後複製

以上是完整的自定义菜单的分析以及对应javabean的构建。

对于个性化菜单,如果查看该部分的文档,会发现和自定义菜单大致相同,只是多个一个“配置”的json,格式是这样的:{“button”:[…],”matchrule”:{…}}。
我们发现,“匹配”这段json和“button”是同级的,分析和实现和上面基本等同,直接给出实现的javabean。


//匹配的json对应的json
public class MatchRule {
private String group_id;
private String sex;
private String client_platform_type;
private String country;
private String province;
private String city;
private String language;
}

//修改Menu.java
public class Menu {
@SerializedName("button")
private List<FatherButton> fatherButtons;
private MatchRule matchrule;
}
登入後複製

自定义菜单的实现
任务,我们实现所有微信按钮响应类型:
任务(注释:“m-0”表示父按钮;“m-n”表示第m个父按钮,第n个子按钮(m,n≠0)):1-0:名字:click,响应点击事件:点击推事件 。2-0:名字:父按钮2。2-1:名字:view,响应事件:跳转网页;2-2:名字:scancode_push,响应事件:扫码推事件;2-3:名字:scancode_waitmsg,响应事件:扫码推事件且弹出“消息接收中”提示框;2-4:名字:pic_sysphoto,响应事件
:弹出系统拍照发图。2-5:名字:pic_photo_or_album,响应事件:弹出拍照或者相册发图。3-0:名字:父按钮3。3-1:名字
:pic_weixin,响应事件:弹出微信相册发图器;3-2:名字:location_select,响应事件:弹出地理位置选择器;3-3:名字:media_id,响应事件:下发消息(除文本消息);3-4:名字:view_limited,响应事件:跳转图文消息url。

实现源码(引用的AccessTokenUtils.java在第一部分:工具类AccessTokenUtils的封装)


 /*
  * 创建自定义菜单。
  */
 @Test
 public void createCommMenu() {
  String ACCESS_TOKEN = AccessTokenUtils.getAccessToken();// 获取AccessToken,AccessTokenUtils是封装好的类
  // 拼接api要求的httpsurl链接
  String urlString = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token="
    + ACCESS_TOKEN;
  try {
   // 创建一个url
   URL reqURL = new URL(urlString);
   // 拿取链接
   HttpsURLConnection httpsConn = (HttpsURLConnection) reqURL
     .openConnection();
   httpsConn.setDoOutput(true);
   // 取得该连接的输出流,以读取响应内容
   OutputStreamWriter osr = new OutputStreamWriter(
     httpsConn.getOutputStream());
   osr.write(getMenuJson());// 使用本类外部方法getMenuJson()
   osr.close();

   // 返回结果
   InputStreamReader isr = new InputStreamReader(
     httpsConn.getInputStream());
   // 读取服务器的响应内容并显示
   char[] chars = new char[1024];
   String reslut = "";
   int len;
   while ((len = isr.read(chars)) != -1) {
    reslut += new String(chars, 0, len);
   }
   System.out.println("返回结果:" + reslut);
   isr.close();
  } catch (IOException e) {
   e.printStackTrace();
  }
 }

 public String getMenuJson() {
  Gson gson = new Gson();// json处理工具

  Menu menu = new Menu();// 菜单类
  List<FatherButton> fatherButtons = new ArrayList<FatherButton>();// 菜单中的父按钮集合
  // -----------
  // 父按钮1
  FatherButton fb1 = new FatherButton();
  fb1.setName("click");
  fb1.setType("click");
  fb1.setKey("10");
  // -------------
  // 父按钮2
  FatherButton fb2 = new FatherButton();
  fb2.setName("父按钮2");
  List<SonButton> sonButtons2 = new ArrayList<SonButton>();// 子按钮的集合

  // 子按钮2-1
  SonButton sb21 = new SonButton();
  sb21.setName("view");
  sb21.setUrl("http://www.baidu.com");
  sb21.setType("view");
  // 子按钮2-2
  SonButton sb22 = new SonButton();
  sb22.setName("scancode_push");
  sb22.setType("scancode_push");
  sb22.setKey("22");
  // 子按钮2-3
  SonButton sb23 = new SonButton();
  sb23.setName("scancode_waitmsg");
  sb23.setType("scancode_waitmsg");
  sb23.setKey("23");
  // 子按钮2-4
  SonButton sb24 = new SonButton();
  sb24.setName("pic_sysphoto");
  sb24.setType("pic_sysphoto");
  sb24.setKey("24");
  // 子按钮2-5
  SonButton sb25 = new SonButton();
  sb25.setName("pic_photo_or_album");
  sb25.setType("pic_photo_or_album");
  sb25.setKey("25");

  // 添加子按钮到子按钮集合
  sonButtons2.add(sb21);
  sonButtons2.add(sb22);
  sonButtons2.add(sb23);
  sonButtons2.add(sb24);
  sonButtons2.add(sb25);

  // 将子按钮放到2-0父按钮集合
  fb2.setSonButtons(sonButtons2);

  // ------------------
  // 父按钮3
  FatherButton fb3 = new FatherButton();
  fb3.setName("父按钮3");
  List<SonButton> sonButtons3 = new ArrayList<SonButton>();

  // 子按钮3-1
  SonButton sb31 = new SonButton();
  sb31.setName("pic_weixin");
  sb31.setType("pic_weixin");
  sb31.setKey("31");
  // 子按钮3-2
  SonButton sb32 = new SonButton();
  sb32.setName("locatselect");
  sb32.setType("location_select");
  sb32.setKey("32");
  // // 子按钮3-3-->测试不了,因为要media_id。这需要调用素材id.
  // SonButton sb33 = new SonButton();
  // sb33.setName("media_id");
  // sb33.setType("media_id");
  // sb33.setMedia_id("???");
  // // 子按钮3-4-->测试不了,因为要media_id。这需要调用素材id.
  // SonButton sb34 = new SonButton();
  // sb34.setName("view_limited");
  // sb34.setType("view_limited");
  // sb34.setMedia_id("???");

  // 添加子按钮到子按钮队列
  sonButtons3.add(sb31);
  sonButtons3.add(sb32);
  // sonButtons3.add(sb33);
  // sonButtons3.add(sb34);

  // 将子按钮放到3-0父按钮队列
  fb3.setSonButtons(sonButtons3);
  // ---------------------

  // 将父按钮加入到父按钮集合
  fatherButtons.add(fb1);
  fatherButtons.add(fb2);
  fatherButtons.add(fb3);

  // 将父按钮队列加入到菜单栏
  menu.setFatherButtons(fatherButtons);
  String json = gson.toJson(menu);
  System.out.println(json);// 测试输出
  return json;

 }
登入後複製

个性化菜单的实现
•任务:根据性别展示不同的按钮显示(可以根据性别、地区、分组手机操作系统等)
•修改代码一,因为是不同的微信后台实现,所以接口也不一样,不过还是POST请求,代码不用改,只要替换原来urlString即可。


// 拼接api要求的httpsurl链接
String urlString = "https://api.weixin.qq.com/cgi-bin/menu/addconditional?access_token="
   + ACCESS_TOKEN;
登入後複製

•修改代码二,只要创建一个MatchRule,设置匹配规则,然后将matchrule加入到menu便可以完成匹配规则。


// -----
// 从此处开始设置个性菜单
MatchRule matchrule = new MatchRule();
matchrule.setSex("2");// 男生
menu.setMatchrule(matchrule);
// ----
登入後複製

以上是java微信開發API微信自訂個人化選單實作實例程式碼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

突破或從Java 8流返回? 突破或從Java 8流返回? Feb 07, 2025 pm 12:09 PM

Java 8引入了Stream API,提供了一種強大且表達力豐富的處理數據集合的方式。然而,使用Stream時,一個常見問題是:如何從forEach操作中中斷或返回? 傳統循環允許提前中斷或返回,但Stream的forEach方法並不直接支持這種方式。本文將解釋原因,並探討在Stream處理系統中實現提前終止的替代方法。 延伸閱讀: Java Stream API改進 理解Stream forEach forEach方法是一個終端操作,它對Stream中的每個元素執行一個操作。它的設計意圖是處

PHP:網絡開發的關鍵語言 PHP:網絡開發的關鍵語言 Apr 13, 2025 am 12:08 AM

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

PHP與Python:了解差異 PHP與Python:了解差異 Apr 11, 2025 am 12:15 AM

PHP和Python各有優勢,選擇應基於項目需求。 1.PHP適合web開發,語法簡單,執行效率高。 2.Python適用於數據科學和機器學習,語法簡潔,庫豐富。

PHP與其他語言:比較 PHP與其他語言:比較 Apr 13, 2025 am 12:19 AM

PHP適合web開發,特別是在快速開發和處理動態內容方面表現出色,但不擅長數據科學和企業級應用。與Python相比,PHP在web開發中更具優勢,但在數據科學領域不如Python;與Java相比,PHP在企業級應用中表現較差,但在web開發中更靈活;與JavaScript相比,PHP在後端開發中更簡潔,但在前端開發中不如JavaScript。

PHP與Python:核心功能 PHP與Python:核心功能 Apr 13, 2025 am 12:16 AM

PHP和Python各有優勢,適合不同場景。 1.PHP適用於web開發,提供內置web服務器和豐富函數庫。 2.Python適合數據科學和機器學習,語法簡潔且有強大標準庫。選擇時應根據項目需求決定。

Java程序查找膠囊的體積 Java程序查找膠囊的體積 Feb 07, 2025 am 11:37 AM

膠囊是一種三維幾何圖形,由一個圓柱體和兩端各一個半球體組成。膠囊的體積可以通過將圓柱體的體積和兩端半球體的體積相加來計算。本教程將討論如何使用不同的方法在Java中計算給定膠囊的體積。 膠囊體積公式 膠囊體積的公式如下: 膠囊體積 = 圓柱體體積 兩個半球體體積 其中, r: 半球體的半徑。 h: 圓柱體的高度(不包括半球體)。 例子 1 輸入 半徑 = 5 單位 高度 = 10 單位 輸出 體積 = 1570.8 立方單位 解釋 使用公式計算體積: 體積 = π × r2 × h (4

PHP:許多網站的基礎 PHP:許多網站的基礎 Apr 13, 2025 am 12:07 AM

PHP成為許多網站首選技術棧的原因包括其易用性、強大社區支持和廣泛應用。 1)易於學習和使用,適合初學者。 2)擁有龐大的開發者社區,資源豐富。 3)廣泛應用於WordPress、Drupal等平台。 4)與Web服務器緊密集成,簡化開發部署。

創造未來:零基礎的 Java 編程 創造未來:零基礎的 Java 編程 Oct 13, 2024 pm 01:32 PM

Java是熱門程式語言,適合初學者和經驗豐富的開發者學習。本教學從基礎概念出發,逐步深入解說進階主題。安裝Java開發工具包後,可透過建立簡單的「Hello,World!」程式來實踐程式設計。理解程式碼後,使用命令提示字元編譯並執行程序,控制台上將輸出「Hello,World!」。學習Java開啟了程式設計之旅,隨著掌握程度加深,可創建更複雜的應用程式。

See all articles