Ich war vor einiger Zeit beschäftigt. Ich begann, das offizielle WeChat -Konto zu entwickeln und die Dokumente von Grund auf neu zu las. Ich trat auf viele Fallstricke ein. Ich habe es durchgemacht. Ich habe kürzlich darüber nachgedacht, eine Zusammenfassung zu machen, damit ich es überprüfen kann, wenn ich es in Zukunft entwickle. Ich werde auch einen Hinweis auf Studenten geben, die an verwandten Projekten arbeiten.
1. Ideen
WeChat -Zugriff: Benutzernachrichten und Ereignisse, die von Entwicklern erforderlich sind, leiten eine Anforderung über den WeChat -Server ein und leiten an die auf der öffentliche Plattform konfigurierte Server -URL -Adresse weiter. Der WeChat -Server bringt die vier Parameter von Signature, Timestamp, Nonce und Echostr mit. Unser eigener Server spleißt das von der öffentlichen Plattform konfigurierte Token sowie der hochgeladene Zeitstempel, und Nonce wird in SHA1 verschlüsselt und stimmt mit der Signatur überein. Geben Sie die Ture zurück, um anzuzeigen, dass der Zugang erfolgreich ist.
Nachrichten Antwort: Wenn ein Benutzer eine Nachricht an das offizielle Konto sendet, fordert der WeChat -Server die Benutzernachricht an die entsprechende Schnittstelle des Servers an, das wir im XML -Format über Post konfiguriert haben. Was wir tun müssen, ist, die entsprechende logische Verarbeitung basierend auf dem Nachrichtentyp usw. durchzuführen und das endgültige Rückgabeergebnis über das XML -Format an den WeChat -Server zurückzugeben, und die WeChat -Partei übermittelt es dem Benutzer.
1. Konfiguration der öffentlichen Plattform
2.Kontroller
@Controller @RequestMapping ("/wechat") publicClass WechatController {@Value ("$ {dnbx_token}") private String dnbx_token; private static final logger logger = loggerfactory.getLogger (WechatController.class); @Resource WechatService WechatService; /** * WeChat access* @param wc * @return * @throws IOException */ @RequestMapping(value="/connect",method = {RequestMethod.GET, RequestMethod.POST}) @ResponseBody publicvoid connectWeixin(HttpServletRequest request, HttpServletResponse response) throws IOException{ // Set the encoding of the request und Antwort auf UTF-8 (verhindern chinesische verstümmelte) Anfrage. // Der WeChat-Server verwendet die UTF-8-Codierung bei Postnachrichten, und das gleiche Codieren muss beim Empfangen verwendet werden, da ansonsten chinesische verstümmelt sein wird. response.setcharactercoding ("utf-8"); // Bei der Beantwortung von Nachrichten (Antwort auf den Benutzer) ist die Codierungsmethode auch auf UTF-8 festgelegt, das Prinzip ist das gleiche wie oben. boolean isget = request.getMethod (). TolowerCase (). Equals ("get"); Printwriter out = response.getWriter (); try {if (isGet) {String Signature = Request.GetParameter ("Signature"); // WeChat -Verschlüsselungs -Signatur String String Timestamp = Request.GetParameter ("Timestamp"); // Timestamp String nonce = Anforderung.getParameter ("Nonce"); // Random Number EchoStr = GECKKE. Signatur. Wenn die Überprüfung erfolgreich ist, geben Sie Echostr so zurück, was darauf hinweist, dass der Zugang erfolgreich ist. Andernfalls schlägt der Zugriff fehl, wenn (Signutil.Checksignature (DNBX_TOKE, Signatur, Zeitstempel, Nonce)) {logger.info ("Verbinden Sie den Wixin -Server an, ist erfolgreich."); response.getWriter (). Write (echostr); } else {logger.Error ("Die Signatur nicht überprüft!"); }} else {String respMessage = "Ausnahmenachricht!"; try {respMessage = wechatService.weixinPost (Anfrage); out.write (respMessage); Logger.info ("die Anfrage erfolgreich abgeschlossen"); Logger.info ("to wixin server"+respmessage); } catch (Ausnahme E) {logger.Error ("Die Nachricht von Wixin nicht konvertieren!"); }}} catch (Exception E) {logger.Error ("Verbinden Sie den Weixin -Server ist Fehler."); } endlich {out.close (); }}}3. Signaturüberprüfungsprüfung
Aus dem obigen Controller können wir feststellen, dass ich eine Werkzeugklasse -Signutil, die als Checksignatur bezeichnet wurde, in Einkapitseln habe und in vier Werten bestanden habe, dnbx_token, Signature, Zeitstempel, Nonce. Dieser Prozess ist sehr wichtig. Tatsächlich können wir es als Verschlüsselungs- und Entschlüsselungsprozess des von WeChat übertragenen Wertes verstehen. Um die Sicherheit zu gewährleisten, haben alle Schnittstellen in vielen großen Projekten einen solchen Überprüfungsprozess. Dnbx_token Wir haben eine Token -Zeichenfolge auf der Wechat Public Platform konfiguriert, die Idee vertraulich halten! Die anderen drei sind Parameter, die vom WeChat -Server gesendet werden, um eine GET -Anforderung zu senden. Wir führen eine Schicht von SHA1 -Verschlüsselung durch:
public class Signutil { / *** Überprüfungssignatur* @param Token WeChat Server -Token, konfiguriert in der Env.Properties -Datei und im Entwicklerzentrum konfiguriert sein muss konsistent sein Signatur, String Timestamp, String nonce) {String [] arr = new String [] {Token, Timestamp, nonce}; // Sortieren Sie die Wörterbuchordnung von Token, Zeitstempel und Nonce; // Die drei Parameterzeichenfolgen in eine Zeichenfolge für die SHA1 -Verschlüsselungszeichenfolge tmpstr = sha1.encode (arr [0] + arr [1] + arr [2]); // Die String verschlüsselte SHA1 kann mit der Signatur verglichen werden und identifiziert, dass die Anfrage von WeChat Return tmpstr! = NULL stammt? tmpstr.equals (Signature.ToUpperCase ()): Falsch; }} SHA1:
/** * WeChat Public Platform (JAVA) SDK * * SHA1 Algorithm * @author helijun 2016/06/15 19:49 */ public final class SHA1 { private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'c', 'd', 'e', 'f'}; /*** Nimmt die rohen Bytes aus dem Digest und formatiert sie korrekt. * * @param Bytes die rohen Bytes aus der Digest. * @return die formatierten Bytes. */ private statische String getFormattedText (byte [] bytes) {int len = bytes.length; StringBuilder buf = new StringBuilder (len * 2); // den Chiffretext in ein hexadezimales Zeichenfolgenform für (int j = 0; j <len; j ++) {buf.Append (hex_digits [(bytes [j] >> 4) & 0x0f] konvertieren; buf.Append (hex_digits [bytes [j] & 0x0f]); } return buf.toString (); } public static String codem (string str) {if (str == null) {return null; } try {MessagedIGest MessagedIGest = MessagedIGest.getInstance ("SHA1"); MessagedIGest.Update (str.getBytes ()); return GetFormattedText (MessagedIGest.Digest ()); } catch (Ausnahme e) {neue runTimeException (e) werfen; }}}Wenn Sie es auf der öffentlichen Plattform einreichen und speichern und die grüne Eingabeaufforderung "Zugangserfolge" sehen, herzlichen Glückwunsch zum Abschluss des WeChat -Zugriffs. Dieser Prozess erfordert etwas mehr sorgfältiger und achtet auf den Fall im Verschlüsselungsalgorithmus. Wenn der Zugang nicht erfolgreich ist, sind die meisten Fälle Probleme mit dem Verschlüsselungsalgorithmus, überprüfen Sie ihn mehr.
4. Implementieren Sie den automatischen Nachrichten -Antwortdienst
/ ** * Prozessanfragen von WeChat * * @param Anfrage * @return */ public String wexinPost (httpServletRequest -Anforderung) {String respMessage = null; try {// xml request parsing map <string, string> requestmap = messageutil.xmltomap (request); // Absenderkonto (open_id) String von renername = requestmap.get ("fromUserername"); // Public Account String tousername = requestmap.get ("tousername"); // Nachrichtentyp String msgType = requestmap.get ("msgType"); // Nachrichteninhaltsstring content = requestmap.get ("content"); Logger.info ("FromuSerername ist:" + fromusername + ", tousername lautet:" + tousername + ", msgType ist:" + msgType); // Textnachricht if (msgType.equals (messageUtil.req_message_type_text)) {// Hier führen Sie die entsprechende Logik nach den Schlüsselwörtern aus, es gibt nur eine, an die Sie sich nicht vorstellen können, und es gibt keine so etwas, wie Sie nicht tun können, wenn ("Inhalt (" xxx ") {{} // automatische Antwort Textmessage Textmessage -Text = New text (). text.setContent ("Der Text ist" + Inhalt); text.settousername (fromuername); text.setfromusername (tousername); text.setCreateTime (neues Datum (). GetTime () + ""); text.setmsgType (msgType); respMessage = messageUtil.textMessAgetoxml (Text); } /*else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)) {// Event push String eventType = requestMap.get("Event");// Event type if (eventType.equals(MessageUtil.EVENT_TYPE_SUBSCRIBE)) {// Subscribe to respContent = "Welcome to follow the xxx official account! "; return messageresponse.getTextMessage (from Username, tousername, respcontent); } else if (eventType.equals (messageutil.event_type_click)) {// Benutzerdefinierte Menü klicken Sie Ereignisstring Ereigniskey = Requestmap.get ("EventKey"); // Ereignisschlüsselwert, entsprechend dem Schlüsselwert, der beim Erstellen des benutzerdefinierten Menü -logger.info ("EventKey Is:" +Ereigniskey) entspricht. return xxx; }} // WeChat-Sounderkennungstest 2015-3-30 sonst einschalten if (msgType.equals ("voice") {String RecvMessage = RequestMap.get ("Erkennung"); // respcontent = "Empfangenes Sprachanalyseergebnis:"+RecvMessage; if (recvMessage! } else {respcontent = "Was du gesagt hast, ist zu vage, kannst du es noch einmal sagen?"; } return messagerePonse.GetextMessage (from Username, tousername, respcontent); } // Fotografiefunktion else if (msgType.equals ("pic_SySthoto")) {} else {return messageresponse.GetextMessage (from Unername, tousername, "zurück zu leer zurückkehren"); }*/ // Ereignisschub sonst if (msgType.equals (messageUtil.req_message_type_event)) {String eventType = RequestMap.get ("Ereignis"); // Ereignis Typ // abonnieren if (eventType.equals (messageutil.event_type_subscribing text.setContent ("Willkommen zu folgen, xxx"); text.settousername (fromuername); text.setfromusername (tousername); text.setCreateTime (neues Datum (). GetTime () + ""); text.setmsgType (messageutil.resp_message_type_text); respMessage = messageUtil.textMessAgetoxml (Text); } // Todo Nach dem Abbestellen kann der Benutzer die vom offiziellen Konto gesendete Nachricht nicht empfangen. Daher müssen nicht auf die Nachricht antworten. RequestMap.get ("EventKey"); // Ereignisschlüsselwert entspricht dem Schlüsselwert, der beim Erstellen eines benutzerdefinierten Menüs angegeben ist, wenn (EventKey.equals ("Customer_telephone") {textMessage text = new textMessage (); text.setContent ("0755-86671980"); text.settousername (fromuername); text.setfromusername (tousername); text.setCreateTime (neues Datum (). GetTime () + ""); text.setmsgType (messageutil.resp_message_type_text); respMessage = messageUtil.textMessAgetoxml (Text); }}}} catch (Ausnahme E) {logger.Error ("Fehler ...")} return respMessage; }Der Code wird wie oben veröffentlicht. Die meisten von ihnen haben Kommentare. Wenn Sie die grundlegende Semantik einmal lesen, müssen Sie sie nicht erklären.
Es gibt einen Ort, an dem besondere Aufmerksamkeit erforderlich ist:
Die roten Färbemöglichkeiten und Tousername sind genau das Gegenteil, was auch eine der Fallstricke ist. Ich erinnere mich, dass ich es schon lange angepasst hatte, aber es war kein Problem, aber es funktionierte nicht. Schließlich habe ich die Nachricht erhalten, nachdem ich diese beiden geändert hatte! Tatsächlich ist es richtig, darüber nachzudenken. Wenn Sie zum WeChat -Server zurückkehren, ändert sich Ihre Rolle, sodass der Absender und der Empfänger definitiv das Gegenteil sind.
5. MessageUtil
public class messageutil { / *** Rückgabenachricht Typ: Text* / public static Final String resp_message_type_text = "text"; / *** Rückgabenachrichtentyp: Musik*/ public static Final String resp_message_type_music = "musik"; / *** Rückgabenachricht Typ: Grafischer Text*/ public static Final String resp_message_type_news = "news"; / *** Anforderungsnachricht Typ: Text*/ public static Final String req_message_type_text = "text"; / *** Anforderungsnachricht Typ: Image*/ public static Final String req_message_type_image = "Bild"; / *** Anforderungsnachricht Typ: Link*/ public static Final String req_message_type_link = "link"; / *** Meldungstyp anfordern: Geografischer Standort*/ public static Final String req_message_type_location = "locum"; / *** Anforderungsnachricht Typ: Audio*/ public static Final String req_message_type_voice = "voice"; / ** * Anforderungsnachricht Typ: Push */ public static Final String req_message_type_event = "event"; / ** * Ereignisart: abonnieren (abonnieren) */ public static final String event_type_subscribe = "abonnieren"; / ** * Ereignisart: Absubscribe (Absubscribe) */ public static Final String event_type_unsubScribe = "Absubscribe"; / ** * Ereignisart: Klicken Sie auf (Benutzerdefiniertes Menü klicken Sie auf Ereignis) */ public static Final String event_type_click = "klicken"; }Um die Lesbarkeit und Skalierbarkeit der Programme zu verbessern, habe ich hier einige Einkapselungen vorgenommen, mehrere Konstanten definiert und einige Parameter verkapselt, die von WeChat in Java Bean anhaltenden Objekten übergeben wurden. Der Kerncode ist wie oben. Konzentrieren Sie sich auf die Konvertierung zwischen XML und MAP
Tatsächlich wird dieses Problem mit der XML -Kommunikation WeChat zugeschrieben, und wir verwenden normalerweise JSON, sodass wir uns möglicherweise in kurzer Zeit ein wenig unwohl fühlen.
1. Schleifpaket einführen
<!-- parse xml --> <dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.6.1</version> </dependency> <dependency> <groupId>com.thoughtworks.xstream</groupId> <artifactId>xstream</artifactId> <version>1.4.9</version> </dependency>
2.xml, um das Sammlungsobjekt zu kartieren
/ ** * xml zu map * @param request * @return * @throws ioException */ @Suppresswarnings ("Unkontrolliert") public static map <String, String> xmltomap (httpServletRequest) Throws IOException {map <string> map = new HaSHmap <String, String> (); SaxReader Reader = neuer Saxreader (); InputStream INS = NULL; try {iNS = request.getInputStream (); } catch (ioException e1) {e1.printstacktrace (); } Document doc = null; try {doc = reader.read (iNS); Element root = doc.getrootelement (); Liste <Element> list = root.elements (); für (Element E: Liste) {map.put (e.getName (), e.getText ()); } Rückgabekarte; } catch (documentException e1) {e1.printstacktrace (); } endlich {Ins.close (); } return null; } 3.. Konvertieren Sie das SMS -Objekt in XML
/ ** * SMS -Objekt in xml * ** konvertieren in XML * * @param textMessage Textnachricht Objekt * @return xml */ public static String textMessAgetoxml (textMessage textMessage) {xstream xstream = new xstream (); xstream.alias ("xml", textMessage.getClass ()); return xstream.toxml (TextMessage); } Bisher wurde die Arbeiten abgeschlossen. Zu diesem Zeitpunkt können Sie versuchen, "Test" in das offizielle Konto zu senden. Sie erhalten eine WeChat -Antwort "Der Text ist Test". Dies ist auch der Antwortvorgang im obigen Code. Natürlich können Sie auch Ihre Fantasie verwenden, um alles zu tun, was Sie tun möchten, z. B. um 1 zu beantworten, ob Sie das Wetter überprüfen, 2 die Verstöße überprüfen usw.
Das obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, es wird für das Lernen aller hilfreich sein und ich hoffe, jeder wird Wulin.com mehr unterstützen.