微信公眾號開發--接收與回覆訊息(Java)
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow
也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!
第一步:配置微信公眾號
進入微信公眾平臺地址
進入基本配置
這裡需要填寫的有伺服器的URL、Token兩個地方
URL
是一個公網地址,只能接收80埠的(http預設埠)
http://公網地址/專案名稱/請求路徑
Token
在校驗的時候需要用到,隨便輸入一個字串就可以了
開發者提交資訊後,微信伺服器將傳送GET請求到填寫的伺服器地址URL上,GET請求攜帶四個引數
引數 描述
signature 微信加密簽名,signature結合了開發者填寫的token引數和請求中的timestamp引數、nonce引數。
timestamp 時間戳
nonce 隨機數
echostr 隨機字串
所以需要編寫相應的Controller(採用spring MVC)
/** * 驗證微信伺服器 * * @param response * @param signature * @param timestamp * @param nonce * @param echostr */ @RequestMapping(value = "/wechat", method = RequestMethod.GET) public void wechatService(PrintWriter out, HttpServletResponse response, @RequestParam(value = "signature", required = false) String signature, @RequestParam String timestamp, @RequestParam String nonce, @RequestParam String echostr) { if (CheckUtil.checkSignature(signature, timestamp, nonce)) { out.print(echostr); } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
CheckUtil.Java
package com.wechat.utils;import java.util.Arrays;/** * * 校驗工具類 * 開發者通過檢驗signature對請求進行校驗(下面有校驗方式)。若確認此次GET請求來自微信伺服器,請原樣返回echostr引數內容,則接入生效, * 成為開發者成功,否則接入失敗。 * * @author GWCheng * */public class CheckUtil { //配置微信公眾號時填寫的Token private static final String token = "chenggaowei"; public static boolean checkSignature(String signature, String timestamp, String nonce) { // 拼接字串 String[] arr = new String[] { token, timestamp, nonce }; // 排序 Arrays.sort(arr); // 生成字串 StringBuffer content = new StringBuffer(); for (int i = 0; i < arr.length; i++) { content.append(arr[i]); } // SHA1加密 String tmp = DecriptUtil.SHA1(content.toString()); return tmp.equals(signature); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
DecriptUtil.java
import java.io.UnsupportedEncodingException;import java.security.InvalidKeyException;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import java.security.SecureRandom;import javax.crypto.BadPaddingException;import javax.crypto.Cipher;import javax.crypto.IllegalBlockSizeException;import javax.crypto.KeyGenerator;import javax.crypto.NoSuchPaddingException;import javax.crypto.SecretKey;import javax.crypto.spec.SecretKeySpec;/** * 各種加密解密 * */public class DecriptUtil { public static String SHA1(String decript) { try { MessageDigest digest = java.security.MessageDigest .getInstance("SHA-1"); digest.update(decript.getBytes()); byte messageDigest[] = digest.digest(); // Create Hex String StringBuffer hexString = new StringBuffer(); // 位元組陣列轉換為 十六進位制 數 for (int i = 0; i < messageDigest.length; i++) { String shaHex = Integer.toHexString(messageDigest[i] & 0xFF); if (shaHex.length() < 2) { hexString.append(0); } hexString.append(shaHex); } return hexString.toString(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return ""; } public static String SHA(String decript) { try { MessageDigest digest = java.security.MessageDigest .getInstance("SHA"); digest.update(decript.getBytes()); byte messageDigest[] = digest.digest(); // Create Hex String StringBuffer hexString = new StringBuffer(); // 位元組陣列轉換為 十六進位制 數 for (int i = 0; i < messageDigest.length; i++) { String shaHex = Integer.toHexString(messageDigest[i] & 0xFF); if (shaHex.length() < 2) { hexString.append(0); } hexString.append(shaHex); } return hexString.toString(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return ""; } public static String MD5(String input) { try { // 獲得MD5摘要演算法的 MessageDigest 物件 MessageDigest mdInst = MessageDigest.getInstance("MD5"); // 使用指定的位元組更新摘要 mdInst.update(input.getBytes()); // 獲得密文 byte[] md = mdInst.digest(); // 把密文轉換成十六進位制的字串形式 StringBuffer hexString = new StringBuffer(); // 位元組陣列轉換為 十六進位制 數 for (int i = 0; i < md.length; i++) { String shaHex = Integer.toHexString(md[i] & 0xFF); if (shaHex.length() < 2) { hexString.append(0); } hexString.append(shaHex); } return hexString.toString(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return ""; } /** * 加密 * * @param content * 需要加密的內容 * @param password * 加密密碼 * @return */ public static byte[] encryptAES(String content, String password) { try { KeyGenerator kgen = KeyGenerator.getInstance("AES"); kgen.init(128, new SecureRandom(password.getBytes())); SecretKey secretKey = kgen.generateKey(); byte[] enCodeFormat = secretKey.getEncoded(); SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES"); Cipher cipher = Cipher.getInstance("AES");// 建立密碼器 byte[] byteContent = content.getBytes("utf-8"); cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化 byte[] result = cipher.doFinal(byteContent); return result; // 加密 } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } return null; } /** * 解密 * * @param content * 待解密內容 * @param password * 解密金鑰 * @return */ public static byte[] decryptAES(byte[] content, String password) { try { KeyGenerator kgen = KeyGenerator.getInstance("AES"); kgen.init(128, new SecureRandom(password.getBytes())); SecretKey secretKey = kgen.generateKey(); byte[] enCodeFormat = secretKey.getEncoded(); SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES"); Cipher cipher = Cipher.getInstance("AES");// 建立密碼器 cipher.init(Cipher.DECRYPT_MODE, key);// 初始化 byte[] result = cipher.doFinal(content); return result; // 加密 } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } return null; } /** * BASE64解密 * * @param key * @return * @throws Exception */ public static String decryptBASE64(String key) { return ""; } /** * BASE64加密 * * @param key * @return * @throws Exception */ public static String encryptBASE64(String key) { return ""; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
驗證寫好了就可以點選提交了
配置成功之後會有如下的提示資訊
下面是微信發過來的四個引數,以及給微信回覆的echostr
至此開發環境已經配置好了!
第二步:接收訊息
環境配置好之後就可以開發了
微信會將發往公眾賬號的訊息發到我們配置的URL中,以POST的方式
當普通微信使用者向公眾賬號發訊息時,微信伺服器將POST訊息的XML資料包到開發者填寫的URL上。
以下是debug的資訊
微信已經將發往公眾賬號的訊息發到了我們配置的伺服器地址
xml訊息不太利於編寫程式,所以需要對xml訊息進行相應的轉換,這裡將其轉會為map
將xml轉換為map
/** * 將xml轉化為Map集合 * * @param request * @return */ public static Map<String, String> xmlToMap(HttpServletRequest request) { Map<String, String> map = new HashMap<String, String>(); SAXReader reader = new SAXReader(); InputStream ins = null; try { ins = request.getInputStream(); } catch (IOException e1) { e1.printStackTrace(); } Document doc = null; try { doc = reader.read(ins); } catch (DocumentException e1) { e1.printStackTrace(); } Element root = doc.getRootElement(); @SuppressWarnings("unchecked") List<Element> list = root.elements(); for (Element e : list) { map.put(e.getName(), e.getText()); } try { ins.close(); } catch (IOException e1) { e1.printStackTrace(); } return map; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
用到的jar包
dom4j.jar
這個方法寫好之後就可以呼叫了:
Controller如下,微信發過來的訊息用POST接收
/** * 接收來自微信發來的訊息 * * @param out * @param request * @param response */ @ResponseBody @RequestMapping(value = "/wechat", method = RequestMethod.POST) public void wechatServicePost(PrintWriter out, HttpServletRequest request, HttpServletResponse response) { String responseMessage = wechatService.processRequest(request); out.print(responseMessage); out.flush(); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
Controller呼叫Service的方法(給使用者返回訊息,也是一個xml格式的字串)
Service關鍵程式碼如下
@Servicepublic class WechatService { private static Logger log = Logger.getLogger(WechatService.class); public String processRequest(HttpServletRequest request) { Map<String, String> map = WechatMessageUtil.xmlToMap(request); log.info(map); // 傳送方帳號(一個OpenID) String fromUserName = map.get("FromUserName"); // 開發者微訊號 String toUserName = map.get("ToUserName"); // 訊息型別 String msgType = map.get("MsgType"); // 預設回覆一個"success" String responseMessage = "success"; // 對訊息進行處理 if (WechatMessageUtil.MESSAGE_TEXT.equals(msgType)) {// 文字訊息 TextMessage textMessage = new TextMessage(); textMessage.setMsgType(WechatMessageUtil.MESSAGE_TEXT); textMessage.setToUserName(fromUserName); textMessage.setFromUserName(toUserName); textMessage.setCreateTime(System.currentTimeMillis()); textMessage.setContent("我已經受到你發來的訊息了"); responseMessage = WechatMessageUtil.textMessageToXml(textMessage); } log.info(responseMessage); return responseMessage; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
Servie呼叫WechatMessageUtil將reques中的xml轉換為map
WechatMessageUtil.java如下
import java.io.IOException;import java.io.InputStream;import java.util.HashMap;import java.util.List;import java.util.Map;import javax.servlet.http.HttpServletRequest;import org.dom4j.Document;import org.dom4j.DocumentException;import org.dom4j.Element;import org.dom4j.io.SAXReader;import com.thoughtworks.xstream.XStream;import com.wechat.entity.vo.wechat.message.TextMessage;public class WechatMessageUtil { // 各種訊息型別,除了掃帶二維碼事件 /** * 文字訊息 */ public static final String MESSAGE_TEXT = "text"; /** * 圖片訊息 */ public static final String MESSAtGE_IMAGE = "image"; /** * 圖文訊息 */ public static final String MESSAGE_NEWS = "news"; /** * 語音訊息 */ public static final String MESSAGE_VOICE = "voice"; /** * 視訊訊息 */ public static final String MESSAGE_VIDEO = "video"; /** * 小視訊訊息 */ public static final String MESSAGE_SHORTVIDEO = "shortvideo"; /** * 地理位置訊息 */ public static final String MESSAGE_LOCATION = "location"; /** * 連結訊息 */ public static final String MESSAGE_LINK = "link"; /** * 事件推送訊息 */ public static final String MESSAGE_EVENT = "event"; /** * 事件推送訊息中,事件型別,subscribe(訂閱) */ public static final String MESSAGE_EVENT_SUBSCRIBE = "subscribe"; /** * 事件推送訊息中,事件型別,unsubscribe(取消訂閱) */ public static final String MESSAGE_EVENT_UNSUBSCRIBE = "unsubscribe"; /** * 事件推送訊息中,上報地理位置事件 */ public static final String MESSAGE_EVENT_LOCATION_UP = "LOCATION"; /** &nb