微信公衆平臺開發好像已經火了很長一段時間,我好像有點後知後覺。但只從瞭解它後便有點不可收拾之勢,腦殼裏總想着開發一個本身的公衆號,雖然不知道具體作什麼。java
下面就說說本身這段時間對公衆號的學習。git
欲善其事,必先利其器。在開發以前先要申請一個公衆號,公衆號有三種,我的比較容易申請的是訂閱號,服務號還要審覈,稍微麻煩一點,對於我的開發我建議申請服務號,數組
由於後面會作自定義菜單的功能。再就是咱們須要有一個公網的服務器,這個能夠申請sina的sae和百度的bae,我的比較喜歡sina的一點,比較容易上手。這裏不講公衆號的申請服務器
和sae服務器的申請和配置。微信
再作完這兩件過後咱們就能夠開始公衆號的開發了。首先咱們須要瞭解微信公衆號的工做流程,對其有個總體的把握,要不從此就會換挺多簡單錯誤。在啓用開發者模式狀況下app
(下面內容都是在此模式下)當用戶經過微信客服端發送消息到微信服務後,微信服務器會將此消息轉發給咱們的公網服務器,如上面所說sae和bae(如下內容也均是在sae下完成)微信公衆平臺
。具體的業務邏輯就在sae上完成,處理完後再將結果發回微信服務器,微信服務器再發給用戶。ide
申請到公衆號後,登錄公衆品臺,能夠看到微信已經幫咱們準備好了許多功能,咱們不須要編寫任何代碼就能夠完成一個具備基本的公衆號,但這不是本文的目的,咱們是要工具
用本身的代碼實現一些功能,所以咱們要進入開發者中心去配置服務器接口。學習
下面就是本文核心內容:
試想一下讓兩個徹底不沾邊的服務器(微信服務器和sae)對接的風險,所以必須有什麼驗證機制的存在。具體的驗證過程是
一、微信服務器會以get方式調用咱們部署在sae服務器上的servlet,並傳signature、timestamp、nonce、echostr四個參數。其中signature是微信加密簽名;timestamp
是時間戳,防止即便有別有用心之人得到另外的參數而因時間戳的不一致沒法完成驗證;nonce是隨機數;echostr是隨機字符串,用於返回給微信服務器做比較。
二、servlet接收到以上數據後,會將token(在servlet中寫好且要用公衆平臺上開發者中心的token相同)timestamp、nonce按字典方式排序,再拼接成字符串進行sha1加密
將加密後的字符串與signature比較,若是相同就返回echostr。
三、微信服務器接收到返回的echostr,與發過去的echostr相比較,若是相同,就接入成功,不然失敗。
1 /** 2 * 核心請求處理類 3 * 4 */ 5 public class CrazyServlet extends HttpServlet { 6 7 private static final long serialVersionUID = 5021188348833856475L; 8 @Override 9 protected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException { 10 // 微信加密簽名 11 String signature = request.getParameter("signature"); 12 // 時間戳 13 String timestamp = request.getParameter("timestamp"); 14 // 隨機數 15 String nonce = request.getParameter("nonce"); 16 // 隨機字符串 17 String echostr = request.getParameter("echostr"); 18 PrintWriter out = response.getWriter(); 19 // 經過檢驗signature對請求進行校驗,若校驗成功則原樣返回echostr,表示接入成功,不然接入失敗 20 if (SignUtil.checkSignature(signature, timestamp, nonce)) { 21 out.print(echostr); 22 } 23 out.close(); 24 out = null; 25 }
1 /** 2 * 請求校驗工具類 3 */ 4 public class SignUtil { 5 // 與接口配置信息中的Token要一致 6 private static String token = "845C2550903CE6FA54CACDB82EAD4350"; 7 8 9 public static boolean checkSignature(String signature, String timestamp, 10 String nonce) { 11 //從請求中(也就是微信服務器傳過來的)拿到的token, timestamp, nonce 12 String[] arr = new String[] { token, timestamp, nonce }; 13 // 將token、timestamp、nonce三個參數進行字典序排序 14 sort(arr); 15 StringBuilder content = new StringBuilder(); 16 for (int i = 0; i < arr.length; i++) { 17 content.append(arr[i]); 18 } 19 MessageDigest md = null; 20 String tmpStr = null; 21 22 try { 23 md = MessageDigest.getInstance("SHA-1"); 24 // 將三個參數字符串拼接成一個字符串進行sha1加密 25 byte[] digest = md.digest(content.toString().getBytes()); 26 //將字節數組轉成字符串 27 tmpStr = byteToStr(digest); 28 } catch (NoSuchAlgorithmException e) { 29 e.printStackTrace(); 30 } 31 32 content = null; 33 // 將sha1加密後的字符串可與signature對比,標識該請求來源於微信 34 return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false; 35 } 36 37 //將加密後的字節數組變成字符串 38 private static String byteToStr(byte[] byteArray) { 39 String strDigest = ""; 40 for (int i = 0; i < byteArray.length; i++) { 41 strDigest += byteToHexStr(byteArray[i]); 42 } 43 return strDigest; 44 } 45 46 private static String byteToHexStr(byte mByte) { 47 char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 48 'B', 'C', 'D', 'E', 'F' }; 49 char[] tempArr = new char[2]; 50 tempArr[0] = Digit[(mByte >>> 4) & 0X0F]; 51 tempArr[1] = Digit[mByte & 0X0F]; 52 53 String s = new String(tempArr); 54 return s; 55 } 56 //用於字典排序 57 public static void sort(String a[]) { 58 for (int i = 0; i < a.length - 1; i++) { 59 for (int j = i + 1; j < a.length; j++) { 60 if (a[j].compareTo(a[i]) < 0) { 61 String temp = a[i]; 62 a[i] = a[j]; 63 a[j] = temp; 64 } 65 } 66 } 67 } 68 }
再sae上配置好後,點擊開發者中心,首先啓用服務器配置。填寫url和token(和java代碼中的同樣)、EncodingAESKey是隨機生成,消息加解密方式選擇明文模式。
這裏的url就是你在sae中建立應用的地址,咱們已經將寫好的java代碼上傳到這個地址。token是微信服務器和sae服務器進行對接驗證是用到的(必須保持一致),消息
加密暫時選擇明文模式,若是選擇加密模式須要編寫加密代碼,之後會再轉到加密或兼容模式,這裏先用明文模式。這樣咱們就完成了,點擊提交(記得sae服務器要打開),
若是現實成功就說明接入完成,咱們能夠接着作下面的工做了。