ฉันยุ่งกับเวลาส่วนหน้ามาระยะหนึ่งแล้ว ฉันได้อ่านเอกสารตั้งแต่เริ่มต้นและได้ก้าวไปสู่ข้อผิดพลาดมากมาย ฉันเคยผ่านมันไปแล้ว ฉันได้พิจารณาสรุปบางอย่างเพื่อที่ฉันจะได้ตรวจสอบในอนาคตเมื่อฉันพัฒนามัน ฉันจะให้การอ้างอิงถึงนักเรียนที่ทำงานในโครงการที่เกี่ยวข้อง
ในความเป็นจริงหลังจากทำครั้งเดียวคุณจะพบว่ามันไม่ยาก แนวคิดทั่วไปคือ: ข้อความผู้ใช้และเหตุการณ์ที่ผู้พัฒนาต้องการจะเริ่มการร้องขอผ่านเซิร์ฟเวอร์ WeChat และส่งต่อไปยังที่อยู่ URL ของเซิร์ฟเวอร์ที่คุณกำหนดค่าบนแพลตฟอร์มสาธารณะ เซิร์ฟเวอร์ WeChat จะนำพารามิเตอร์สี่ตัว ได้แก่ ลายเซ็น, การประทับเวลา, nonce และ echostr เซิร์ฟเวอร์ของเราจะประกบโทเค็นที่กำหนดค่าโดยแพลตฟอร์มสาธารณะและอัปโหลดเวลาประทับ Nonce จะถูกเข้ารหัสใน SHA1 และตรงกับลายเซ็น ส่งคืน ture เพื่อระบุว่าการเข้าถึงสำเร็จ
1. การกำหนดค่าแพลตฟอร์มสาธารณะ
2. เครื่องควบคุม
@controller@requestmapping ("/weChat") publicclass wechatcontroller {@value ("$ {dnbx_token}") สตริงส่วนตัว dnbx_token; logger logger สุดท้าย @throws ioexception */@requestmapping (value = "/connect", method = {requestmethod.get, requestmethod.post})@responsebodypublicvoid connectwoixin (httpservletrequest Request request.Setcharacterencoding ("UTF-8"); // เซิร์ฟเวอร์ WeChat ใช้การเข้ารหัส UTF-8 เมื่อข้อความโพสต์และการเข้ารหัสเดียวกันจะต้องใช้เมื่อได้รับมิฉะนั้นรหัสภาษาจีนที่อ่านไม่ออกจะเป็นรหัสที่อ่านไม่ออก Response.Setcharacterencoding ("UTF-8"); // เมื่อตอบกลับข้อความ (ตอบกลับผู้ใช้) วิธีการเข้ารหัสจะถูกตั้งค่าเป็น UTF-8 หลักการเหมือนกับข้างต้น บูลีน isget = request.getMethod (). toLowerCase (). เท่ากับ ("รับ"); printWriter out = response.getWriter (); ลอง {ถ้า (isget) {String Signature = request.getParameter ("ลายเซ็น"); // weChat การเข้ารหัสลายเซ็นสตริง timestamp = request.getParameter ("timestamp"); request.getParameter ("echosttr"); // สุ่มสตริง // ตรวจสอบคำขอโดยตรวจสอบลายเซ็น หากการตรวจสอบประสบความสำเร็จให้ส่งคืน echosttr ตามที่เป็นอยู่แสดงว่าการเข้าถึงประสบความสำเร็จ มิฉะนั้นการเข้าถึงจะล้มเหลวหาก (signutil.checksignature (dnbx_token, ลายเซ็น, timestamp, nonce)) {logger.info ("เชื่อมต่อเซิร์ฟเวอร์ Weixin สำเร็จ"); Response.getWriter (). เขียน (echostr); } else {logger.error ("ไม่สามารถตรวจสอบลายเซ็น!"); }} else {string respmessage = "ข้อความยกเว้น!"; ลอง {respmessage = wechatservice.weixinpost (คำขอ); out.write (respmessage); logger.info ("คำขอเสร็จสมบูรณ์"); logger.info Weixin! "); }}} catch (exception e) {logger.error ("เชื่อมต่อเซิร์ฟเวอร์ weixin เป็นข้อผิดพลาด");} ในที่สุด {out.close ();}}}3. การตรวจสอบการตรวจสอบลายเซ็น
จากคอนโทรลเลอร์ด้านบนเราจะเห็นว่าฉันห่อหุ้มตัวบ่งชี้คลาสเครื่องมือที่เรียกว่าการตรวจสอบและส่งผ่านในสี่ค่า DNBX_Token, ลายเซ็น, การประทับเวลา, nonce กระบวนการนี้สำคัญมาก ในความเป็นจริงเราสามารถเข้าใจได้ว่าเป็นกระบวนการเข้ารหัสและถอดรหัสของค่าที่ส่งโดย WeChat เพื่อให้มั่นใจว่าการรักษาความปลอดภัยอินเทอร์เฟซทั้งหมดในโครงการขนาดใหญ่จำนวนมากจะมีกระบวนการตรวจสอบดังกล่าว dnbx_token เราได้กำหนดค่าสตริงโทเค็นบนแพลตฟอร์มสาธารณะ WeChat ทำให้ความคิดเป็นความลับ! อีกสามตัวคือพารามิเตอร์ที่ส่งโดย WeChat Server เพื่อส่งคำขอ GET เราทำการเข้ารหัส SHA1:
Signutil คลาสสาธารณะ { / *** ลายเซ็นการตรวจสอบ* @param โทเค็นโทเค็นเซิร์ฟเวอร์ Wechat เซิร์ฟเวอร์ที่กำหนดค่าในไฟล์ env.properties และกำหนดค่าในศูนย์นักพัฒนาซอฟต์แวร์จะต้องสอดคล้อง* @param ลายเซ็นเซิร์ฟเวอร์ weChat ส่ง sha1 @sha1 โทเค็น, ลายเซ็นสตริง, สตริง timestamp, สตริง nonce) {string [] arr = สตริงใหม่ [] {โทเค็น, timestamp, nonce}; // เรียงลำดับพจนานุกรมของโทเค็น, การประทับเวลาและ nonce; // splice สตริงพารามิเตอร์สามตัวลงในสตริงสำหรับ SHA1 การเข้ารหัสสตริง tmpstr = sha1.encode (arr [0] + arr [1] + arr [2]); // สตริงที่เข้ารหัส sha1 สามารถเปรียบเทียบกับลายเซ็นระบุว่าคำขอมาจาก weChat return tmpstr! = null? tmpstr.equals (signature.touppercase ()): false; -sha1:
/** * แพลตฟอร์มสาธารณะ WeChat (java) SDK * * sha1 อัลกอริทึม * @author Helijun 2016/06/15 19: 49 */คลาสสุดท้ายของสาธารณะ sha1 {ส่วนตัวคงที่ถ่านสุดท้าย [] hex_digits = {'0', '1', '2', '3' 'b', 'c', 'd', 'e', 'f'}; /*** ใช้ไบต์ดิบจากการย่อยและจัดรูปแบบให้ถูกต้อง * * @param ไบต์ไบต์ดิบจาก digest * @return ไบต์ที่จัดรูปแบบ */ สตริงคงที่ส่วนตัว getFormattedText (byte [] bytes) {int len = bytes.length; StringBuilder buf = new StringBuilder (len * 2); // แปลง ciphertext เป็นรูปแบบสตริง hexadecimal สำหรับ (int j = 0; j <len; j ++) {buf.append (hex_digits [(ไบต์ [j] >> 4) & 0x0f]); buf.append (hex_digits [bytes [j] & 0x0f]); } return buf.toString (); } String String สาธารณะเข้ารหัส (String str) {if (str == null) {return null; } ลอง {messageGeSest messageGeStest = messageGeSt.getInstance ("sha1"); messageGeSt.update (str.getBytes ()); กลับ getFormattedText (messageGeSt.digest ()); } catch (exception e) {โยน runtimeException ใหม่ (e); - เมื่อคุณส่งและบันทึกไว้บนแพลตฟอร์มสาธารณะและดู "ความสำเร็จในการเข้าถึง" Green Prompt "ขอแสดงความยินดีกับการเข้าถึง WeChat กระบวนการนี้ต้องใช้ความระมัดระวังมากขึ้นและให้ความสนใจกับคดีในอัลกอริทึมการเข้ารหัส หากการเข้าถึงไม่สำเร็จกรณีส่วนใหญ่เป็นปัญหาเกี่ยวกับอัลกอริทึมการเข้ารหัสให้ตรวจสอบเพิ่มเติม
4. ใช้บริการตอบกลับข้อความอัตโนมัติ
/*** คำขอกระบวนการจาก weChat** @param Request* @return*/สตริงสาธารณะ weixInpost (คำขอ httpservletRequest) {สตริง respmessage = null; ลอง {// xml คำขอแยกวิเคราะห์ <String, requestmap = messageUtil.xmlTomap (คำขอ) requestmap.get ("fromusername"); // สตริงบัญชีสาธารณะ tousername = requestmap.get ("tousername"); // ประเภทข้อความสตริงสตริง msgtype = requestmap.get ("msgtype"); // เนื้อหาสตริงของข้อความ ", msgtype คือ:" + msgtype); // ข้อความถ้า (msgtype.equals (MessageUtil.req_message_type_text)) {// ตรรกะที่สอดคล้องกันถูกดำเนินการตามคำสำคัญ มีเพียงหนึ่งเดียวที่คุณจินตนาการไม่ได้ ไม่มีสิ่งใดที่คุณไม่สามารถทำได้ถ้า (content.equals ("xxx")) {} // การตอบกลับข้อความอัตโนมัติข้อความข้อความ = textMessage ใหม่ (); text.setContent ("ข้อความคือ" + เนื้อหา); text.settousername ""); text.setMsgType (msgType); respMessage = messageUtil.TextMessagetOxml (ข้อความ);}/*อื่น ๆ ถ้า (msgtype.equals (messageUtil.req_message_type_event) {// เหตุการณ์พุช (EventType.equals (MessageUtil.Event_Type_Subscribe)) {// สมัครสมาชิก respcontent = "ยินดีต้อนรับสู่การติดตามบัญชี XXX อย่างเป็นทางการ!"; ส่งคืน messageresponse.getTextMessage (fromusername, tousername, respcontent); = requestmap.get ("EventKey"); // ค่าคีย์เหตุการณ์, สอดคล้องกับค่าคีย์ที่ระบุเมื่อสร้างเมนู menu logger.info ("EventKey คือ:" +EventKey); return xxx;}} // เปิดการทดสอบการจดจำเสียง WeChat 2015-3-30Else ถ้า requestmap.get ("การรับรู้"); // respcontent = "ผลการวิเคราะห์คำพูดที่ได้รับ:"+recvMessage; if (recvMessage! = null) {respcontent = tulingapiprocess.getTulingResult (recvMessage);} else {respcontent = "สิ่งที่คุณพูดนั้นคลุมเครือเกินไป } // ฟังก์ชั่นการถ่ายภาพอื่น ๆ ถ้า (msgtype.equals ("pic_sysphoto")) {} else {return messageresponse.getTextMessage (Fromusername, tousername, "return empty"); }*// เหตุการณ์พุชอื่นถ้า (msgtype.equals (MessageUtil.req_message_type_event)) {String eventtype = requestmap.get ("เหตุการณ์"); // ประเภทเหตุการณ์ // สมัครสมาชิกถ้า (eventtype.equals ติดตาม, xxx "); text.settousername (fromusername); text.setFromusername (tousername); text.setCreateTime (วันที่ใหม่ (). getTime () +" "); text.setMsgType (MessageUtil.Resp_Message_Type_Text); ยกเลิกการสมัครผู้ใช้ไม่สามารถรับข้อความที่ส่งโดยบัญชีอย่างเป็นทางการดังนั้นจึงไม่จำเป็นต้องตอบกลับข้อความอื่น ๆ ถ้า (EventType.equals (MessageUtil.event_Type_unsubsribe)) {// ยกเลิกการสมัคร} // เมนูที่กำหนดเอง ค่าคีย์เหตุการณ์ที่สอดคล้องกับค่าคีย์ที่ระบุเมื่อสร้างเมนูที่กำหนดเองถ้า (eventkey.equals ("customer_telephone")) {textMessage text = textMessage ใหม่ (); text.setContent ("0755-86671980"); text.settousername วันที่ (). getTime () + ""); text.setMsgType (MessageUtil.resp_message_type_text); respmessage = messageUtil.TextMessagetOxml (ข้อความ);}}}}} catch (ยกเว้น e) {logger.error ("ข้อผิดพลาด ... ")รหัสถูกโพสต์ดังกล่าวข้างต้น ส่วนใหญ่มีความคิดเห็น หากคุณอ่านความหมายพื้นฐานหนึ่งครั้งคุณไม่จำเป็นต้องอธิบาย
แนวคิดสั้น ๆ : เมื่อผู้ใช้ส่งข้อความไปยังบัญชีอย่างเป็นทางการเซิร์ฟเวอร์ WeChat จะขอข้อความผู้ใช้ผ่านโพสต์ไปยังอินเทอร์เฟซที่เกี่ยวข้องของเซิร์ฟเวอร์ที่เรากำหนดค่าในรูปแบบ XML สิ่งที่เราต้องทำคือการประมวลผลเชิงตรรกะที่สอดคล้องกันตามประเภทข้อความ ฯลฯ และส่งคืนผลลัพธ์การส่งคืนสุดท้ายไปยังเซิร์ฟเวอร์ WeChat ผ่านรูปแบบ XML จากนั้นถ่ายทอดให้ผู้ใช้
มีสถานที่แห่งหนึ่งที่ต้องการความสนใจเป็นพิเศษ:
สีแดงจากชื่อชื่อและ tousername เป็นสิ่งที่ตรงกันข้ามซึ่งเป็นหนึ่งในข้อผิดพลาด ฉันจำได้ว่าฉันได้ปรับมันมาเป็นเวลานาน แต่มันก็ไม่ใช่ปัญหา แต่มันไม่ทำงาน ในที่สุดฉันก็ได้รับข้อความหลังจากเปลี่ยนสองสิ่งนี้! ในความเป็นจริงมันถูกต้องที่จะคิดเกี่ยวกับมัน เมื่อคุณกลับไปที่ WeChat Server บทบาทของคุณจะเปลี่ยนไปดังนั้นผู้ส่งและตัวรับสัญญาณจึงตรงกันข้ามอย่างแน่นอน
5. MessageUtil
Public Class MessageUtil {/ *** ส่งคืนประเภทข้อความ: ข้อความ*/ สตริงสุดท้ายคงที่สาธารณะ resp_message_type_text = "text"; / *** ส่งคืนประเภทข้อความ: เพลง*/ สตริงสุดท้ายคงที่ resp_message_type_music = "เพลง"; / *** ส่งคืนประเภทข้อความ: ข้อความกราฟิก*/ สตริงสุดท้ายคงที่สาธารณะ resp_message_type_news = "ข่าว"; / *** คำขอประเภทข้อความ: ข้อความ*/ สาธารณะคงที่สตริงสุดท้าย req_message_type_text = "text"; / *** ประเภทข้อความร้องขอ: ภาพ*/ สตริงสุดท้ายคงที่ req_message_type_image = "image"; / *** ประเภทข้อความร้องขอ: ลิงก์*/ สตริงสุดท้ายคงที่ req_message_type_link = "ลิงก์"; / *** ประเภทข้อความร้องขอ: ตำแหน่งทางภูมิศาสตร์*/ สตริงสุดท้ายคงที่ req_message_type_location = "ตำแหน่ง"; / *** ประเภทข้อความร้องขอ: เสียง*/ สตริงสุดท้ายคงที่ req_message_type_voice = "เสียง"; / ** * ประเภทข้อความร้องขอ: พุช */ สตริงสุดท้ายคงที่ req_message_type_event = "เหตุการณ์"; / ** * ประเภทเหตุการณ์: สมัครสมาชิก (สมัครสมาชิก) */ สตริงสุดท้ายคงที่ event_type_subscribe = "สมัครสมาชิก"; / ** * ประเภทเหตุการณ์: ยกเลิกการสมัคร (ยกเลิกการสมัคร) */ สตริงสุดท้ายคงที่สาธารณะ event_type_unsubscribe = "ยกเลิกการสมัคร"; / ** * ประเภทเหตุการณ์: คลิก (เมนูที่กำหนดเองคลิกเหตุการณ์) */ สตริงสุดท้ายคงที่ event_type_click = "คลิก"; -ที่นี่เพื่อให้โปรแกรมการอ่านและความยืดหยุ่นดีขึ้นฉันได้ทำการห่อหุ้มบางอย่างกำหนดค่าคงที่หลายค่าและห่อหุ้มพารามิเตอร์บางอย่างที่ส่งผ่านจาก WeChat ไปยังวัตถุถาวร Java Bean รหัสหลักอยู่ข้างบน มุ่งเน้นไปที่การแปลงระหว่าง XML และ MAP
ในความเป็นจริงปัญหานี้เกิดจาก WeChat โดยใช้การสื่อสาร XML และเรามักจะใช้ JSON ดังนั้นเราอาจรู้สึกอึดอัดเล็กน้อยในช่วงเวลาสั้น ๆ
1. Introduce Jar Package
<!-Parse XML-> <predency> <sdeperency> <sdeperency> <roupId> dom4j </groupId> <ratifactId> dom4j </artifactid> <cersion> 1.6.1 </version> </การพึ่งพา> <การพึ่งพา> <roupid> com.thoughtworks.xstream </groupid>
2.xml ถึงแผนที่วัตถุคอลเลกชัน
/*** XML แปลงเป็นแผนที่* @param Request* @return* @throws ioexception*/ @suppresswarnings ("unchecked") แผนที่สาธารณะคงที่ <สตริง, สตริง> xmltomap (httpservletrequest คำขอ) null; ลอง {ins = request.getInputStream ();} catch (ioexception e1) {e1.printStackTrace ();} เอกสารเอกสาร = null; ลอง {doc = reader.read (ins); element root = doc.getRootelement () รายการ e.getText ());} return map;} catch (documentException e1) {e1.printStackTrace ();} ในที่สุด {ins.close ();} return null;}3. แปลงวัตถุข้อความเป็น XML
/ ** * แปลงวัตถุข้อความเป็น xml * * @param textMessage ข้อความข้อความ * @return xml */ สตริงคงที่ public String textMessagetOxml (textMessage textMessage) {xstream xstream = ใหม่ xstream (); xstream.alias ("xml"ด้านบนเป็นบทนำของบรรณาธิการเกี่ยวกับ Java ในการใช้งาน SpringMVC WeChat Access และใช้ฟังก์ชั่นการตอบกลับอัตโนมัติอย่างง่าย ฉันหวังว่ามันจะเป็นประโยชน์กับทุกคน หากคุณมีคำถามใด ๆ โปรดฝากข้อความถึงฉันและบรรณาธิการจะตอบกลับทุกคนในเวลา ขอบคุณมากสำหรับการสนับสนุนเว็บไซต์ Wulin.com!