微信公衆號開發
在進行學習微信公衆號開發時,首先我們需要做好一些必須的準備。
1.具有一個自己的公衆號平臺,方便進行學習。
2.在網上找一款內網穿透器,進行內網穿透,接入微信開發。
3.有一個已經搭建好的Web項目。
1.申請微信公衆號
進行微信公衆號申請時,在下方地址進行申請即可,我們申請時可以根據自己的不同需求進行申請,選擇訂閱號或者服務號。企業號的開發模式和微信公衆號類似,但是必須由企業才能進行申請。
https://mp.weixin.qq.com/cgi-bin/registermidpage?action=index&lang=zh_CN
這裏不對申請做過多描述,按照表單填寫即可,很簡單。
2.使用內網穿透器進行內網穿透
免費的內網穿透器有很多,博主使用過的有花生殼和Ngrok,這裏推薦使用Ngrok,花生殼速度很慢,而且自身網站也有很多BUG。Ngrok的網站地址如下:
https://www.ngrok.cc/#down-client
申請註冊完成後,選擇登錄按鈕進行登錄,在左側選擇開通隧道,進入如下界面,選擇免費的版本。
選擇後進行隧道開通,可以將表單設置爲如下信息:
前置域名可以寫一個自己喜歡的域名,端口號要與本地服務器的端口號一致。隧道名稱可以隨便起,方便自己識別。
然後我們要去下載區進行下載windows版本的客戶端。下載完成後進行解壓,可以獲得到兩個文件夾,這裏我們只保留下面一個文件夾即可。
運行該文件夾下的腳本文件 Sunny-Ngrok啓動工具.bat之後,可以看到如下界面
在這裏我們可以輸入隧道Id,隧道Id可以在穿透器的管理界面獲得,即下方的隧道Id
隨後將隧道Id填寫腳本中,如果需要啓動多個隧道,則以逗號進行分割,啓動內網穿透器,不要關閉。
3.測試項目內網穿透
在項目的隧道編輯頁面可以找到如下前置域名
該域名爲與我們平時項目運行時的域名localhost:8080相同,後跟項目路徑即可。
我的項目訪問名直接配置的/,可以獲得如下界面:
測試接口訪問成功後,我們的準備工作就已經完成了。
4.連接微信公衆號
我們可以進入開發者工具---開發者文檔 進行查看如何進行URL的接入
https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1445241432
在開始開發--接入指南 中可以看到,在進行接入時,微信公衆號會向定義好的接口URL發送get請求,參數爲
signature |
微信加密簽名,signature結合了開發者填寫的token參數和請求中的timestamp參數、nonce參數。 |
timestamp |
時間戳 |
nonce |
隨機數 |
echostr |
隨機字符串 |
根據微信開發文檔所指出,我們可以通過對所獲得的參數進行加密處理進行校驗,如果成功則返回echostr參數,表示接入成功。這裏我們將直接返回該參數,不進行驗證。
然後進入項目,進行代碼編寫,創建一個SpringMVC的Servlet接口:
@RequestMapping("check.do")
@ResponseBody
public String checkInterface(String signature, String timestamp, String nonce,
String echostr, HttpServletResponse response) throws IOException {
// 通過檢驗signature對請求進行校驗,若校驗成功則原樣返回echostr,表示接入成功,否則接入失敗
System.out.println(echostr);
return echostr;
}
接口編寫完成以後,我們可以在微信管理界面中,進行接入接口的配置。
我們登錄進入自己所申請的微信公衆號,在最下方的開發中,有一個 基本配置 按鈕,進入頁面,進行配置我們公衆號的一系列信息。
這裏爲了便於學習,採用了明文模式,即不對來往的消息進行加密處理。URL需要填寫我們進行接入微信公衆號的URL,token可以隨意填寫,識別驗證進行使用。EncodingAESKey使用隨機生成即可。
5.Access_token的獲取
Access_token是在微信開發中,常用的一個token參數,這個參數每天最多獲取2000次,且參數的有效期默認爲7200秒。我們可以通過以下接口進行獲取:
https://api.weixin.qq.com/cgi-bin/token
grant_type |
是 |
獲取access_token填寫client_credential |
appid |
是 |
第三方用戶唯一憑證 |
secret |
是 |
第三方用戶唯一憑證密鑰,即appsecret |
該接口中,具有以上三個參數,其中grant_type直接填寫client_credential即可,後兩個參數可以在開發者配置中找到,如下圖所示
開發者密碼需要進行重置以後才能看到。看完開發者密碼以後,要注意保存,否則無法再次查看。我們在進行對微信公衆平臺的訪問時,需要通過httpClient進行。在添加httpClient的jar包到項目中以後,添加一個工具類:
package com.mender.mdoa.weixin.util;
import org.apache.http.HttpEntity;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class HttpUtil {
/**
* 發送get請求到指定的URl
* @param url Url地址
* @param params 參數列表
* @return 返回的信息
*/
public String sendGet(String url, Map<String, String> params){
StringBuffer sbUrl = new StringBuffer(url);
//1.使用默認的配置的httpclient
CloseableHttpClient client = HttpClients.createDefault();
//2.使用get方法
if(params != null && params.size() != 0){
Set<String> keys = params.keySet();
sbUrl.append("?");
for(String key : keys){
sbUrl.append(key).append("=").append(params.get(key)).append("&");
}
sbUrl.substring(0,sbUrl.length() - 1);
}
System.out.println(sbUrl.toString());
HttpGet httpGet = new HttpGet(sbUrl.toString());
InputStream inputStream = null;
CloseableHttpResponse response = null;
return this.excute(httpGet);
}
/**
* 發送post請求到指定的URl
* @param url Url地址
* @param params 參數列表
* @return 返回的信息
*/
public String sendPost(String url, Map<String, String> params) throws UnsupportedEncodingException {
StringBuffer sbUrl = new StringBuffer(url);
//1.使用默認的配置的httpclient
CloseableHttpClient client = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(sbUrl.toString());
if(params != null && params.size() > 0){
List<BasicNameValuePair> paramList = new LinkedList<BasicNameValuePair>();
Set<Map.Entry<String, String>> entrySet = params.entrySet();
for(Map.Entry<String, String> entry : entrySet){
paramList.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList,"UTF-8");
httpPost.setEntity(entity);
}
return this.excute(httpPost);
}
/**
* 發送信息
* @param request
* @return
*/
private String excute(HttpUriRequest request){
InputStream inputStream = null;
CloseableHttpResponse response = null;
CloseableHttpClient httpClient = HttpClients.createDefault();
try {
response = httpClient.execute(request);
HttpEntity entity = response.getEntity();
return EntityUtils.toString(entity, "utf-8");
} catch (IOException e) {
e.printStackTrace();
return null;
}finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (response != null) {
try {
response.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
然後使用該工具類發送請求到微信的access_token獲取接口即可。
如下方代碼所示:
public static String getToken(){
String url="https://api.weixin.qq.com/cgi-bin/token";
Map<String, String> params = new HashMap<String, String>();
params.put("grant_type","client_credential");
params.put("appid","wx128a89fa44624819");
params.put("secret","a6ac12b17e8ce4b611f50c0e99571855");
HttpUtil httpUtil = new HttpUtil();
String response = httpUtil.sendGet(url, params);
System.out.println(response);
return response;
}
該方法所返回的response字符串,就是一個包含了access_token的json串,從字符串中提取即可。
在這裏可能會出現一下異常提示
{"errcode":40164,"errmsg":"invalid ip XXX.10.XXX.XXX, not in whitelist hint: [.L7cCA0682nfo1]"}
這裏是因爲我們沒有將自己的ip地址設置到公衆號的ip地址白名單中,我們只需要將報錯信息中的ip複製,然後添加到 微信管理中心---開發配置---白名單 中即可。
6.Access_token過期?
Access_token過期以後會跑出一個異常編碼,編碼的信息可以在微信開發文檔中進行查看。因爲Access_token具有有效期,因此我們需要每隔一段時間進行一次獲取,Access_token在獲取到下一個以後,前一個仍然是有效的,可以使用的,因此在這裏建議使用Spring的定時任務進行獲取,時間週期設定在小於兩小時即可。
我們也可以通過如下代碼進行有效性的測試:
public static void main(String args[]) throws UnsupportedEncodingException {
String token1 = getToken();
String token2 = getToken();
Gson gson = new Gson();
Map<String, String> map = gson.fromJson(token1, HashMap.class);
token1 = map.get("access_token");
map = gson.fromJson(token2, HashMap.class);
token2 = map.get("access_token");
String address1 = getServerAddress(token1);
String address2 = getServerAddress(token2);
System.out.println(address1);
System.out.println(address2);
}
public static String getToken(){
String url="https://api.weixin.qq.com/cgi-bin/token";
Map<String, String> params = new HashMap<String, String>();
params.put("grant_type","client_credential");
params.put("appid","wx128a89fa44624819");
params.put("secret","a6ac12b17e8ce4b611f50c0e99571855");
HttpUtil httpUtil = new HttpUtil();
String response = httpUtil.sendGet(url, params);
System.out.println(response);
return response;
}
public static String getServerAddress(String token){
String url="https://api.weixin.qq.com/cgi-bin/getcallbackip";
Map<String, String> params = new HashMap<String, String>();
params.put("access_token",token);
HttpUtil httpUtil = new HttpUtil();
String response = httpUtil.sendGet(url, params);
System.out.println(response);
return response;
}
先獲取了兩個access_token然後使用這兩個access_token來獲取微信的服務地址,最後我們就可以得到這個結果。這樣可以證明access_token是可以多次獲取,且在後一次獲取後,前一次依然有效的。