كنت مشغولاً لفترة من الوقت. بدأت في تطوير حساب WeChat الرسمي وقراءة المستندات من نقطة الصفر. صعدت على الكثير من المزالق. لقد مررت به. لقد فكرت مؤخرًا في إجراء بعض الملخصات حتى أتمكن من مراجعته عندما أقوم بتطويره في المستقبل. سأشير أيضًا إلى الطلاب الذين يعملون في المشاريع ذات الصلة.
1. الأفكار
WeChat Access: ستبدأ رسائل المستخدم ودفع الأحداث المطلوبة من قبل المطورين طلبًا من خلال خادم WeChat وإعادة توجيهه إلى عنوان عنوان URL للخادم الذي قمت بتكوينه على النظام الأساسي العام. سيحضر خادم WeChat المعلمات الأربعة للتوقيع ، الطابع الزمني ، nonce ، و echosttr. يربط الخادم الخاص بنا الرمز المميز الذي تم تكوينه بواسطة النظام الأساسي العام ، وكذلك الطابع الزمني الذي تم تحميله ، ويتم تشفير NONCE في SHA1 ويتطابق مع التوقيع. أعد ture للإشارة إلى أن الوصول ناجح.
رد الرسالة: عندما يرسل المستخدم رسالة إلى الحساب الرسمي ، سيطلب خادم WeChat رسالة المستخدم إلى الواجهة المقابلة للخادم الذي قمنا بتكوينه بتنسيق XML من خلال Post. ما يتعين علينا القيام به هو إجراء المعالجة المنطقية المقابلة بناءً على نوع الرسالة ، وما إلى ذلك ، وإرجاع نتيجة الإرجاع النهائية إلى خادم WeChat من خلال تنسيق XML ، وسوف ينقلها حزب WeChat إلى المستخدم.
1. تكوين النظام الأساسي العام
2.controller
@controller @requestMapping ("/wechat") publicClass WeChatController {Value ("$ {dnbx_token}") سلسلة خاصة dnbx_token ؛ private Static Final Logger Logger = loggerFactory.getLogger (WeChatController.class) ؛ Resource WeChatservice WeChatservice ؛ /** * Wechat Access * param wc * regurn * throws ioException */requestmapping (value = "/connect" ، method = {requestMethod.get ، requestMethod.post}) responseBonseBonderboun إلى utf-8 (منع التشويش الصيني) request.setcharacterencoding ("UTF-8") ؛ // يستخدم خادم WeChat ترميز UTF-8 عند نشر الرسائل ، ويجب استخدام نفس الترميز عند الاستلام ، وإلا سيكون المشوهة الصينية ؛ استجابة. setcharacterencoding ("UTF-8") ؛ // عند الرد على الرسائل (الرد على المستخدم) ، يتم أيضًا تعيين طريقة الترميز على UTF-8 ، والمبدأ هو نفسه كما هو مذكور أعلاه ؛ منطقية isget = request.getMethod (). printWriter out = response.getWriter () ؛ حاول {if (isget) {string signature = request.getParameter ("Signature") ؛ // WeChat Encryption String Timestamp = request.getParameter ("timestamp") ؛ // timestamp string nonce = request.getParameter ("nonce") ؛ إذا كان التحقق ناجحًا ، فاحصل على Echosttr كما هو ، مما يشير إلى أن الوصول ناجح. خلاف ذلك ، يفشل الوصول إذا (signutil.checksignature (dnbx_token ، التوقيع ، الطابع الزمني ، nonce)) {logger.info ("توصيل خادم Weixin ناجح.") ؛ استجابة. } آخر {logger.error ("فشل في التحقق من التوقيع!") ؛ }} else {string represmessage = "استثناء رسالة!" ؛ حاول {respmessage = weChatservice.weixinpost (request) ؛ out.write (respmessage) ؛ logger.info ("الانتهاء من الطلب بنجاح") ؛ logger.info ("إلى Weixin Server"+respmessage) ؛ } catch (استثناء e) {logger.error ("فشل في تحويل الرسالة من Weixin!") ؛ }}} catch (استثناء e) {logger.error ("قم بتوصيل خادم weixin هو خطأ.") ؛ } أخيرًا {out.close () ؛ }}}3. التحقق من التحقق من التوقيع
من وحدة التحكم أعلاه ، يمكننا أن نرى أنني أغلف علامة فئة الأدوات ، تسمى checksiscishature ، وتم تمريرها في أربع قيم ، DNBX_TOKEN ، التوقيع ، الطابع الزمني ، nonce. هذه العملية مهمة جدا. في الواقع ، يمكننا أن نفهمها على أنها عملية تشفير وفك تشفير القيمة التي يتم نقلها بواسطة WeChat. من أجل ضمان الأمن ، سيكون لجميع الواجهات في العديد من المشاريع الكبيرة عملية التحقق هذه. dnbx_token قمنا بتكوين سلسلة رمزية على منصة WeChat العامة ، حافظ على سرية الفكرة! الثلاثة الأخرى هي المعلمات التي يتم إرسالها بواسطة خادم WeChat لإرسال طلب الحصول على. نؤدي طبقة من تشفير SHA1:
الفئة العامة signutil { / *** توقيع التحقق* param token wechat server token ، يجب أن يكون تكوينه في ملف env.properties وتكوينه في مركز المطورين ثابتًا* signature server wechat يرسل رقم sha1 string string string (string tokenature* string timestamp* timestamp timestamp* publaram boolen to string to string tok. التوقيع ، سلسلة الطابع الزمني ، سلسلة nonce) {string [] arr = new string [] {token ، timestamp ، nonce} ؛ // فرز ترتيب القاموس من الرمز المميز ، الطابع الزمني ، و nonce ؛ // لصق سلاسل المعلمة الثلاثة في سلسلة لسلسلة تشفير SHA1 TMPSTR = sha1.encode (arr [0] + arr [1] + arr [2]) ؛ // يمكن مقارنة السلسلة المشفرة SHA1 بالتوقيع ، مع تحديد أن الطلب يأتي من WeChat Return TMPSTR! = NULL؟ TMPSTR.Equals (Signature.ToupperCase ()): خطأ ؛ }} SHA1:
/** * منصة WeChat العامة (Java) SDK * * SHA1 خوارزمية * Author Helijun 2016/06/15 19:49/Public Final Class Sha1 {Private Static Final Char [] "،" ، "،" ، "،" ، "،" ، "،" ، "،" ، "،" ، "،" ، "،" ، "،" ، "،" ، "،" ، "،" ، "،" ، "،" ، "،" ، "،" ، "،" ، "،" ، "،" ، "،" ، "،" ، "،" ، "،" ، "،" ، "،" ، "،" ، "،" ، "،" ، "،" ، "،" ، "،" ، "، 'b' ، 'c' ، 'd' ، 'e' ، 'f'} ؛ /*** يأخذ البايتات الخام من Digest وتنسيقها بشكل صحيح. * * param بايت بايت الخام من الهضم. * @العودة البايتات المنسقة. */ private Static String getFormattedText (byte [] bytes) {int len = bytes.length ؛ StringBuilder buf = new StringBuilder (len * 2) ؛ // قم بتحويل النص المشفر إلى نموذج سلسلة سداسي عشر لـ (int j = 0 ؛ j <len ؛ j ++) {buf.append (hex_digits [(bytes [j] >> 4) & 0x0f]) ؛ buf.append (hex_digits [bytes [j] & 0x0f]) ؛ } return buf.toString () ؛ } تشفير السلسلة الثابتة العامة (String str) {if (str == null) {return null ؛ } جرب {messagedigest messagedigest = messagedigest.getInstance ("sha1") ؛ messagedigest.update (str.getBytes ()) ؛ return getFormattedText (messagedigest.digest ()) ؛ } catch (استثناء e) {رمي new runTimeException (e) ؛ }}}عند إرسالها وحفظها على المنصة العامة ورؤية المطالبة الخضراء "نجاح الوصول" ، تهانينا على إكمال وصول WeChat. تتطلب هذه العملية المزيد من العناية والانتباه إلى الحالة في خوارزمية التشفير. إذا لم يكن الوصول ناجحًا ، فإن معظم الحالات هي مشاكل في خوارزمية التشفير ، تحقق من ذلك أكثر.
4. تنفيذ خدمة رد الرسائل التلقائية
/ ** * طلبات العملية من WeChat * * param request * return */ public string weixinpost (httpservletrequest request) {string respmessage = null ؛ جرب {// xml طلب التحليل خريطة <string ، string> requestMap = messageutil.xmltomap (request) ؛ // Sender Account (Open_id) String fromuserName = requestMap.get ("fromuserName") ؛ // سلسلة الحساب العامة touserName = requestMap.get ("touserName") ؛ // نوع الرسالة سلسلة msgtype = requestMap.get ("msgtype") ؛ // message content string content = requestMap.get ("content") ؛ logger.info ("fromuserName هو:" + fromuserName + "، touserName هو:" + touserName + "، msgtype هو:" + msgtype) ؛ // رسالة نصية if (msgtype.equals (messageUtil.req_message_type_text)) {// هنا تقوم بتنفيذ المنطق المقابل وفقًا للكلمات الرئيسية ، لا يوجد سوى واحد لا يمكنك التفكير فيه ، ولا يوجد نصي textmess () text.setContent ("النص هو" + محتوى) ؛ text.SettouserName (fromusername) ؛ text.setFromuserName (touserName) ؛ text.setCreateTime (date new (). getTime () + "") ؛ text.setmsgtype (msgtype) ؛ respmessage = messageutil.textMessageToxMl (text) ؛ }/*else if (msgtype.equals (messageutil.req_message_type_event)) {// push string eventtype = requestMap.get ("event") ؛ // type type if (eventtype.equals (messageutiL.event_type_subscribe) return messageresponse.getTextMessage (fromusername ، touserName ، respcontent) ؛ } if if (eventType.equals (messageutil.event_type_click)) {// menu custom انقر فوق event string eventkey = requestMap.get ("eventkey") إرجاع xxx ؛ }} // قم بتشغيل اختبار التعرف على صوت WeChat 2015-3-30 if (msgtype.equals ("voice")) {string recvmessage = requestMap.get ("التعرف") ؛ // respcontent = "استلام تحليل الكلام:"+recvmessage ؛ if (recvmessage! = null) {respcontent = tulingapiprocess.getTulingResult (recvmessage) ؛ } آخر {respcontent = "ما قلته غامض للغاية ، هل يمكنك قول ذلك مرة أخرى؟" ؛ } return messageresponse.getTextMessage (fromuserName ، touserName ، respcontent) ؛ } // وظيفة التصوير الفوتوغرافي آخر إذا (msgtype.equals ("pic_sysphoto")) {} آخر {return messageresponse.getTextMessage (fromusername ، touserName ، "العودة إلى فارغة") ؛ }*/// event push else if (msgtype.equals (messageutil.req_message_type_event)) {string eventType = requestMap.get ("event") ؛ // type type // recscribe if (eventtype.equals (messageutil.event_type_subscribe)) text.setContent ("مرحبًا بك في متابعة ، xxx") ؛ text.SettouserName (fromusername) ؛ text.setFromuserName (touserName) ؛ text.setCreateTime (date new (). getTime () + "") ؛ text.setmsgtype (messageutil.resp_message_type_text) ؛ respmessage = messageutil.textMessageToxMl (text) ؛ } // todo بعد إلغاء الاشتراك ، لا يمكن للمستخدم استلام الرسالة المرسلة بواسطة الحساب الرسمي ، لذلك ليست هناك حاجة للرد على رسالة أخرى إذا (eventType.equals (messageutil.event_type_unsubscribe)) {// unsubscribe} // custom menual انقر فوق حدث آخر إذا (eventtype.equals. requestMap.get ("eventKey") ؛ // قيمة مفتاح الحدث تتوافق مع قيمة المفتاح المحددة عند إنشاء قائمة مخصصة if (eventKey.equals ("customer_telephone")) {textMessage text = new textMessage () ؛ text.setContent ("0755-86671980") ؛ text.SettouserName (fromusername) ؛ text.setFromuserName (touserName) ؛ text.setCreateTime (date new (). getTime () + "") ؛ text.setmsgtype (messageutil.resp_message_type_text) ؛ respmessage = messageutil.textMessageToxMl (text) ؛ }}}} catch (استثناء e) {logger.error ("error ...")} return respmessage ؛ }تم نشر الرمز على النحو الوارد أعلاه. معظمهم لديهم تعليقات. إذا قرأت الدلالات الأساسية مرة واحدة ، فلن تحتاج إلى شرحها.
هناك مكان واحد يحتاج إلى عناية خاصة:
إن اسم FromuserName و tousername الأحمر هو عكس ذلك تمامًا ، وهو أيضًا أحد المزالق. أتذكر أنني قمت بتعديله لفترة طويلة ، لكنها لم تكن مشكلة ، لكنها لم تكن تعمل. أخيرًا ، تلقيت الرسالة بعد تغيير هذين! في الواقع ، من الصحيح التفكير في الأمر. عندما تعود إلى خادم WeChat ، سيتغير دورك ، وبالتالي فإن المرسل والمستقبل هو بالتأكيد عكس ذلك.
5.Messageutil
فئة عامة messageutil { / *** نوع الرسالة الإرجاع: Text* / public static Final String Resp_Message_Type_text = "text" ؛ / *** نوع الرسالة الإرجاع: Music*/ public Static Final String resp_message_type_music = "music" ؛ / *** نوع الرسالة الإرجاع: نص الرسوم*/ السلسلة النهائية الثابتة العامة resp_message_type_news = "الأخبار" ؛ / *** نوع رسالة الطلب: Text*/ Public Static Final String req_message_type_text = "text" ؛ / *** نوع الرسالة نوع الرسالة: الصورة*/ السلسلة النهائية الثابتة العامة req_message_type_image = "Image" ؛ / *** نوع الطلب نوع الرسالة: الرابط*/ السلسلة النهائية الثابتة العامة req_message_type_link = "link" ؛ / *** نوع رسالة الطلب: الموقع الجغرافي*/ السلسلة النهائية الثابتة العامة req_message_type_location = "الموقع" ؛ / *** نوع رسالة الطلب: الصوت*/ السلسلة النهائية الثابتة العامة req_message_type_voice = "Voice" ؛ / ** * نوع رسالة الطلب: Push */ public Static Final String req_message_type_event = "event" ؛ / ** * نوع الحدث: اشتراك (اشترك) */ static Static Final String event_type_subscribe = "اشتراك" ؛ / ** * نوع الحدث: إلغاء الاشتراك (إلغاء الاشتراك) */ السلسلة النهائية الثابتة العامة event_type_unsubscribe = "unbscribe" ؛ / ** * نوع الحدث: انقر فوق (قائمة مخصصة انقر فوق الحدث) */ السلسلة النهائية الثابتة العامة event_type_click = "انقر فوق" ؛ }هنا ، من أجل جعل البرنامج قابلية للقراءة وقابلية التوسع أفضل ، قمت بإجراء بعض التغليف ، وحددت العديد من الثوابت ، وتغليف بعض المعلمات التي تم تمريرها من WeChat إلى كائنات Java Bean الثابتة. الرمز الأساسي كما هو مذكور أعلاه. ركز على التحويل بين XML والخريطة
في الواقع ، تعزى هذه المشكلة إلى WeChat باستخدام اتصال XML ، وعادة ما نستخدم JSON ، لذلك قد نشعر بعدم الارتياح قليلاً في فترة زمنية قصيرة.
1. حزمة جرة
<!-parse xml-> <redency> <roupid> dom4j </rougiD> <artifactId> dom4j </stifactid> <الإصدار> 1.6.1 </version> </dependency> <redency> <roucid> com.theaughworks.xstream </roughid>
2.xml على كائن جمع الخريطة
/ ** * xml to map * param request * regurn * throws ioException */ suppressWarnings ("unchected") خريطة ثابتة عامة <string ، string> xmltomap (httpservletrequest طلب) ioException} قارئ SaxReader = New SaxReader () ؛ inputStream ins = null ؛ حاول {ins = request.getInputStream () ؛ } catch (ioException e1) {e1.printStackTrace () ؛ } مستند المستند = فارغ ؛ حاول {doc = reader.read (ins) ؛ العنصر جذر = doc.getRootElement () ؛ قائمة <Element> list = root.elements () ؛ لـ (element e: list) {map.put (e.getName () ، e.getText ()) ؛ } خريطة الإرجاع ؛ } catch (documentException e1) {e1.printStackTrace () ؛ } أخيرًا {ins.close () ؛ } إرجاع فارغ ؛ } 3. تحويل كائن الرسالة النصية إلى XML
/ ** * تحويل كائن الرسالة النصية إلى XML * * param textMessage رسالة نصية النص * @RETURN XML */ public Static String TextMessageToxMl (TextMessage textMessage) {xstream xstream = new xstream () ؛ xstream.alias ("XML" ، textMessage.getClass ()) ؛ إرجاع xstream.toxml (textMessage) ؛ } حتى الآن ، تم الانتهاء من العمل. في هذا الوقت ، يمكنك محاولة إرسال "اختبار" في الحساب الرسمي. ستتلقى رد WeChat "النص هو اختبار". هذه هي أيضًا عملية الرد التي تم إجراؤها في الرمز أعلاه. بالطبع ، يمكنك أيضًا استخدام خيالك للقيام بكل ما تريد القيام به ، مثل الرد على 1 تحقق من الطقس ، والتحقق من الانتهاكات ، وما إلى ذلك ....
ما سبق هو كل محتوى هذه المقالة. آمل أن يكون ذلك مفيدًا لتعلم الجميع وآمل أن يدعم الجميع wulin.com أكثر.