【Java】微信公眾號開發筆記

Bonstoppo發表於2019-04-06

GitHub Repository:School-Assistant

一、準備工作

1.微信公眾號的介紹

詳情請看微信公眾平臺開發概述

2.開發環境的搭建

利用ngrok進行內網穿透,測試是否聯通在本地內部如果想訪問自己的程式是很容易的,在同一個IP地址下就可以訪問同一個內網(區域網),但是如果不在該內網下的其他的使用者是無法訪問的。內網穿透顧名思義,就是打破這層“隔膜”,讓外面的使用者可以訪問。當然在這個地方的話,這個主要是還是用來測試我們的微信公眾號是不是打通了,傳到伺服器上就不必考慮這些事情了。

內網穿透的原理:傳統的開發的軟體的通訊是網址---伺服器---應用程式,ngrok的作用就是替代這個應用程式,通訊地址換成一個分配好的二級地址,可以直接進行訪問。這樣的話,我們的開發的程式和軟體就可以直接進行通訊。

ngrok如何使用以及下載的地址:Sunny_ngrok,此處不再贅述。這個地方需要注意的是,如果ngrok和tomcat兩個都沒有開的,其他人是無法訪問這個頁面的,所以無需擔心被入侵的問題。開啟之後,輸入sunny clientid xxxxx,這裡的xxxxx就是你的隧道id,當發現狀態為Tunnel Status變成online的時候,就可以了。在MyEclipse中有自帶的tomcat可以使用,把介面調成80即可。

這個地方記錄一下這個ngrok踩過的坑:因為這個地方的tomcat的埠號是8080,但是ngrok卻是一個80埠,所以需要修改一下tomcat的埠號為80埠。MyEclipse中其實自帶著一個tomcat,啟動的時候要注意不要啟動錯了,否則啟動了這個tomcat的話怎麼改都改都改不對。連結:如何去修改tomcat的埠號?

 

3.開發接入

因為安全問題,微信的諸多功能是無法針對個人使用者開發的,微信針對開發者開放了開發者賬號用來測試介面。地址如下:介面測試號申請。以下是Java程式碼的實現各個功能。

微信打通實現:WxServlet.java

開發者通過檢驗signature對請求進行校驗。若確認此次GET請求來自微信伺服器,請原樣返回echostr引數內容,則接入生效,成為開發者成功,否則接入失敗。

package servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import service.WxService;

public class WxServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		String signature = request.getParameter("signature");
		String timestamp = request.getParameter("timestamp");
		String nonce = request.getParameter("nonce");
		String echostr = request.getParameter("echostr");
		//登陸驗證:如果接入成功原樣返回一個數值//
		if(WxService.check(signature , timestamp , nonce)){
			//System.out.println("接入成功");
			PrintWriter out = response.getWriter();
			out.print(echostr);
			out.flush();
			out.close();
		}
		else{
			System.out.println("接入失敗");
		}

	}

	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("post");
	}

}

sha1檢驗演算法類:WxService.java

第一步:將token、timestamp、nonce三個引數進行字典序排序。 第二步:將三個引數字串拼接成一個字串進行sha1加密 。第三步:開發者獲得加密後的字串可與signature對比,標識該請求來源於微信。(暫時開坑sha1演算法,這個地方值得學一下。在Java中已經有了MessageDigest這個類了,所以可以直接進行使用。sha1是一個加密演算法,把數值轉換成Byte型,然後進行16位的轉換。)

package service;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

public class WxService {
	//微信服務的驗證簽名:
	private static final String TOKEN = "bonstop";//這裡的Token的數值必須和微信開發的配置方式一致//
	private static String sha1(String s){ // 加密方法//
		try{
			//獲取一個加密的物件//
			MessageDigest md = MessageDigest.getInstance("sha1");
			//加密//
			byte[] digest = md.digest(s.getBytes());
			char[] chars = {'0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'a' , 'b' , 'c' , 'd' , 'e' , 'f'};
			StringBuilder sb = new StringBuilder();
			//處理加密的結果//
			for(byte b : digest)
			{
				sb.append(chars[(b >> 4) & 15]);//取其高四位//
				sb.append(chars[b & 15]);//取其低四位//
			}
			return sb.toString();
		}
		catch(NoSuchAlgorithmException e){
			e.printStackTrace();
		}
		return null;
	}
	public static boolean check(String signature , String timestamp , String nonce){
		 //1)將token、timestamp、nonce三個引數進行字典序排序 
			String[] str = new String[] {TOKEN , timestamp , nonce};
			Arrays.sort(str);
		 //2)將三個引數字串拼接成一個字串進行sha1加密 
			String s = str[0] + str[1] + str[2];
			String mysig = sha1(s);
			System.out.println(mysig);
			System.out.println(signature);
		 //3)開發者獲得加密後的字串可與signature對比,標識該請求來源於微信
		return mysig.equalsIgnoreCase(signature);
	}
}

微信使用者發訊息樣例:test.xml

 這個是我從手機上傳送一個“”得到的結果。拉取來自一個使用者的訊息。

<xml>

	<!-- 
		ToUserName : 開發者微訊號
		FromUserName : 傳送方帳號(一個OpenID : 只是隨機放的一個資料)
		CreateTime : 訊息建立時間 (整型)單位時間為秒
		MsgType : 訊息型別,文字為text
		Content : 文字訊息內容
		MsgId : 訊息id,64位整型 
	-->

	<ToUserName><![CDATA[gh_c67e59e8f8c6]]></ToUserName>
	<FromUserName><![CDATA[oBzBC1Qwf-7-nxXs6ghXCrrxK13A]]></FromUserName>
	<CreateTime>1554984695</CreateTime>
	<MsgType><![CDATA[text]]></MsgType>
	<Content><![CDATA[浣犲ソ]]></Content><!-- 我發了一個“你好”,這個需要後序做一個解析才能使用 -->
	<MsgId>22262029333601665</MsgId>
</xml>

 

 

Day2:接入使用者訊息

接入使用者訊息:WxServlet.Java

Post可以接入從微信上發過來的訊息。

package servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import service.WxService;

public class WxServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		String signature = request.getParameter("signature");
		String timestamp = request.getParameter("timestamp");
		String nonce = request.getParameter("nonce");
		String echostr = request.getParameter("echostr");
		//登陸驗證:如果接入成功原樣返回一個數值//
		if(WxService.check(signature , timestamp , nonce)){
			//System.out.println("接入成功");
			PrintWriter out = response.getWriter();
			out.print(echostr);
			out.flush();
			out.close();
		}
		
		else{
			System.out.println("接入失敗");
		}
	}
	/*
	 * doPost用來接收訊息和事件的推送
	 * */
	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//處理訊息和事件推送
		Map<String , String> requestMap = WxService.parseRequest(request.getInputStream());
		System.out.println(requestMap);
	}

}

新增parseRequest 方法:WxService.Java

parseRequest這個功能就是讓XML資訊可以被傳回來。這裡用了dom4j.jar包進行進行解析XML。dom4j.jar放在WebROOT/Web-INF/lib下的檔案內。注意不要下載錯了jar包(dom4j-1.6.1),否則會報錯。下載地址:<dom4j>

package service;

import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletInputStream;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;


public class WxService {
	//微信服務的驗證簽名:
	private static final String TOKEN = "bonstop";//這裡的Token的數值必須和微信開發的配置方式一致//
	private static String sha1(String s){ // 加密方法//
		try{
			//獲取一個加密的物件//
			MessageDigest md = MessageDigest.getInstance("sha1");
			//加密//
			byte[] digest = md.digest(s.getBytes());
			char[] chars = {'0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'a' , 'b' , 'c' , 'd' , 'e' , 'f'};
			StringBuilder sb = new StringBuilder();
			//處理加密的結果//
			for(byte b : digest)
			{
				sb.append(chars[(b >> 4) & 15]);//取其高四位//
				sb.append(chars[b & 15]);//取其第四位//
			}
			return sb.toString();
		}
		catch(NoSuchAlgorithmException e){
			e.printStackTrace();
		}
		return null;
	}
	public static boolean check(String signature , String timestamp , String nonce){
		 //1)將token、timestamp、nonce三個引數進行字典序排序 
			String[] str = new String[] {TOKEN , timestamp , nonce};
			Arrays.sort(str);
		 //2)將三個引數字串拼接成一個字串進行sha1加密 
			String s = str[0] + str[1] + str[2];
			String mysig = sha1(s);
			System.out.println(mysig);
			System.out.println(signature);
		 //3)開發者獲得加密後的字串可與signature對比,標識該請求來源於微信
		return mysig.equalsIgnoreCase(signature);
	}
	
	public static Map<String, String> parseRequest(InputStream is) {
		Map<String , String> map = new HashMap();
		SAXReader reader = new SAXReader();
		try{
			//讀取輸入流,獲取文件物件//
			Document document = reader.read(is);
			//根據文件物件獲取根節點//
			Element root = document.getRootElement();
			//獲取根節點下的所有子節點//
			List<Element> elements = root.elements();
			for(Element e : elements){
				map.put(e.getName(), e.getStringValue());
			}
		}
		catch(DocumentException e){
			e.printStackTrace();
		}
		return map;
	}
}

 

相關文章