本系列文章是記錄本身微信公衆號的開發過程,也但願能爲感興趣的其餘人提供一些思路和幫助
歡迎轉發,轉發請在文前明顯位置,註明本文地址
項目源碼放到文末,須要自取
最終效果
html
有一個特別坑的地方,須要提早說一下 我的訂閱號 如今已經沒有接口開發自定義菜單的權限了。
java
也就是說只能經過微信帳號後臺自定義菜單,而不能經過接口開發自定義菜單。
可是接口開發和後臺自定義二者互斥
要想接口開發自定義菜單,就必須是認證公衆號,可是
spring
wt fk
雞你太美 誒,,, 雞你太美**
可是服務號申請也不難
雖然有這麼多限制,我仍是想去嘗試一下,興趣大於一切shell
申請服務號 仍是比較麻煩的 可是服務號是直接展現在好友消息列表中 而訂閱號是展現在訂閱號消息
服務器
我用的是騰訊雲。其餘外網映射工具在這裏就不說了,搜一下不少微信
進入配置頁面:基本配置 > 修改配置
app
點擊提交>肯定
以後微信會自動向你的服務器發送GET請求並驗證你的服務器,所以咱們須要完成了對GET請求的處理(後面有代碼講解,先不用點肯定)maven
開發者提交信息後,微信服務器將發送GET請求到填寫的服務器地址URL上,GET請求攜帶參數以下表所示:ide
參數 描述 signature 微信加密簽名,signature結合了開發者填寫的token參數和請求中的timestamp參數、nonce參數 timestamp 時間戳 nonce 隨機數 echostr 隨機字符串
開發者經過檢驗signature對請求進行校驗(下面有校驗方式)。若確認這次GET請求來自微信服務器,請原樣返回echostr參數內容,則> 接入生效,成爲開發者成功,不然接入失敗。
加密/校驗流程以下:
1)將token、timestamp、nonce三個參數進行字典序排序
2)將三個參數字符串拼接成一個字符串進行sha1加密
3)開發者得到加密後的字符串可與signature對比,標識該請求來源於微信spring-boot
以上是來源 微信文檔,寫的很清楚了,擼代碼。
/** * 處理微信服務器發來的get請求,進行簽名的驗證 * signature 微信端發來的簽名 * timestamp 微信端發來的時間戳 * nonce 微信端發來的隨機字符串 * echostr 微信端發來的驗證字符串 */ @GetMapping(value = "wechat") public String validate(@RequestParam(value = "signature") String signature, @RequestParam(value = "timestamp") String timestamp, @RequestParam(value = "nonce") String nonce, @RequestParam(value = "echostr") String echostr) { return WeChatUtil.checkSignature(signature, timestamp, nonce) ? echostr : null; }
public static boolean checkSignature(String signature, String timestamp, String nonce) { String[] arr = new String[] { WeChatContant.TOKEN, timestamp, nonce }; // 將token、timestamp、nonce三個參數進行字典序排序 sort(arr); StringBuilder content = new StringBuilder(); for (int i = 0; i < arr.length; i++) { content.append(arr[i]); } MessageDigest md = null; String tmpStr = null; try { md = MessageDigest.getInstance("SHA-1"); // 將三個參數字符串拼接成一個字符串進行sha1加密 byte[] digest = md.digest(content.toString().getBytes()); tmpStr = byteToStr(digest); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } content = null; // 將sha1加密後的字符串可與signature對比,標識該請求來源於微信 return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false; }
String[] arr = new String[] { WeChatContant.TOKEN, timestamp, nonce };
此處的WeChatContant.TOKEN
是個常量 public static final String TOKEN = "lhx";
必須和上文基本配置中的 此處隨便寫 保持一致
完成以後 把項目打個JAR包 扔到服務器上面(別忘安裝jdk,安裝方法百度搜一下)
此處用到的工具軟件:Xshell 6 和 Xftp 6
工具軟件放到文末,須要自取
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <executions> <execution> <configuration> <!--此處填寫boot啓動類--> <mainClass>com.lhx.wechat.WechatApplication</mainClass> </configuration> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
項目源碼中添加了maven打包插件 能夠直接maven clen package -> 可運行的jar包
項目源碼放到文末,須要自取
而後再回到 配置頁面:基本配置 > 修改配置 > 提交 >肯定 網頁頂端會顯示提交成功
當普通微信用戶向公衆帳號發消息時,微信服務器將POST消息的XML數據包到開發者填寫的URL上。
請注意:
一、關於重試的消息排重,推薦使用msgid排重。
二、微信服務器在五秒內收不到響應會斷掉鏈接,而且從新發起請求,總共重試三次。假如服務器沒法保證在五秒內處理並回復,能夠直接 回覆空串,微信服務器不會對此做任何處理,而且不會發起重試。詳情請見「發送消息-被動回覆消息」。
三、若是開發者須要對用戶消息在5秒內當即作出迴應,即便用「發送消息-被動回覆消息」接口向用戶被動回覆消息時,能夠在公衆平臺官網的開發者中心處設置消息加密。開啓加密後,用戶發來的消息和開發者回覆的消息都會被加密(但開發者經過客服接口等API調用形式向用戶發送消息,則不受影響)。關於消息加解密的詳細說明,請見「發送消息-被動回覆消息加解密說明」。各消息類型的推送XML數據包結構以下:
<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1348831860</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[this is a test]]></Content> <MsgId>1234567890123456</MsgId> </xml>
參數 描述 ToUserName 開發者微信號 FromUserName 發送方賬號(一個OpenID) CreateTime 消息建立時間 (整型) MsgType 消息類型,文本爲text Content 文本消息內容 MsgId 消息id,64位整型
文末有源碼
當用戶發送消息給公衆號時(或某些特定的用戶操做引起的事件推送時),會產生一個POST請求,開發者能夠在響應包(Get)中返回特> 定XML結構,來對該消息進行響應(現支持回覆文本、圖片、圖文、語音、視頻、音樂)。嚴格來講,發送被動響應消息其實並非一種> 接口,而是對微信服務器發過來消息的一次回覆。須要的XML數據包結構以下:
回覆文本消息
<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>12345678</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[你好]]></Content> </xml>
參數 是否必須 描述 ToUserName 是 接收方賬號(收到的OpenID) FromUserName 是 開發者微信號 CreateTime 是 消息建立時間 (整型) MsgType 是 消息類型,文本爲text Content 是 回覆的消息內容(換行:在content中可以換行,微信客戶端就支持換行顯示) 文末有源碼
完整代碼
@PostMapping(value = "wechat") public String textMessge(HttpServletRequest request) { logger.info("wechat"); return javaMessageService.textMessage(request); }
@Service public class JavaMessageServiceImpl implements JavaMessageService { private static final Logger logger = LoggerFactory.getLogger(JavaMessageServiceImpl.class); @Override public String textMessage(HttpServletRequest request) { logger.info("進來了"); // xml格式的消息數據 String respXml = null; // 默認返回的文本消息內容 String respContent; try { // 調用parseXml方法解析請求消息 Map<String,String> requestMap = WeChatUtil.parseXml(request); // 消息類型 String msgType = requestMap.get(WeChatContant.MsgType); String mes = null; // 文本消息 if (msgType.equals(WeChatContant.REQ_MESSAGE_TYPE_TEXT)) { mes =requestMap.get(WeChatContant.Content); if(mes != null){ String content = checkResources(mes); if(!StringUtils.isBlank(content)) { return WeChatUtil.sendTextMsg(requestMap, content); } } } // 圖片消息 // ...... mes = mes == null ? "在嗎" : mes; return WeChatUtil.sendTextMsg(requestMap, mes); } catch (DocumentException e) { return null; } catch (Exception e) { e.printStackTrace(); return null; } return null; } private String checkResources(String message){ String returnMessage = null; if("加油".equals(message)){ returnMessage = "你也是"; return returnMessage; } if("我愛你".equals(message)){ returnMessage = "一見面就說愛?"; return returnMessage; } return null; } }
測試能夠用postman 進行測試
項目源碼和本文用到的全部工具我已經打包好放在了微信公衆號中> "爪哇之父兄弟",
關注後,回覆"公衆號源碼",便可獲取
若是你對本文有不對的地方或者遇到難題了 歡迎評論或者掃碼進羣 一塊兒討論 免費幫助
若是本文對你有幫助,請小編喝咖啡啊
公衆號 爪哇之父兄弟 | 微信 | 支付寶 | q羣 |
---|---|---|---|
![]() |
![]() |
![]() |
![]() |