Je suis occupé avec le temps frontal depuis un certain temps. J'ai lu les documents à partir de zéro et j'ai marché sur de nombreux pièges. Je l'ai vécu récemment. J'ai envisagé de faire un résumé afin que je puisse le revoir à l'avenir lorsque je le développe. Je ferai également référence aux étudiants qui travaillent sur des projets connexes.
En fait, après l'avoir fait une fois, vous constaterez que ce n'est pas difficile. L'idée générale est: les messages utilisateur et les poussées d'événements requis par les développeurs initieront une demande via le serveur WeChat et le transfèrent à l'adresse URL du serveur que vous avez configuré sur la plate-forme publique. Le serveur WeChat apportera quatre paramètres: signature, horodatage, nonce et echostr. Notre serveur épissera le jeton configuré par la plate-forme publique et l'horodatage téléchargé. Nonce sera chiffré dans SHA1 et correspondra à la signature. Renvoyez la Ture pour indiquer que l'accès est réussi.
1. Configuration de la plate-forme publique
2.Contrôleur
@ Contrôleur @ requestmapping ("/ wechat") publicClass WeChatController {@value ("$ {dnbx_token}") String privé dnbx_token; Logger final statique privé = loggerfactory.getlogger (wechatotroller.classe); @SourcewatService WeChatService; / *ond @ return * @throws ioException * / @ requestmapping (value = "/ connect", méthode = {requestMethod.get, requestMethod.post}) @ réponsebodypublicVoid connectweixin (httpservletRequest request.SetcharAtterencoding ("UTF-8"); // Le serveur WeChat utilise le codage UTF-8 lors des messages de publication, et le même codage doit être utilisé lors de la réception, sinon le code brouillé chinois sera du code brouillé; Response.SetcharAtterencoding ("UTF-8"); // Lorsque vous répondez aux messages (en répondant à l'utilisateur), la méthode de codage est également définie sur UTF-8, le principe est le même que ci-dessus; booléen isget = request.getMethod (). tolowercase (). equals ("get"); Printwriter out = réponse.getWriter (); try {if (isget) {String Signature = request.getParameter ("Signature"); // WECHAT Signature Signature String Notce = request.getParAmètre ("NONCE"); // Nombre aléatoire String eChostr = request.getParameter ("eChostr"); // chaîne aléatoire // vérifie la demande en vérifiant la signature. Si la vérification est réussie, retournez Echostr tel quel, indiquant que l'accès est réussi. Sinon, l'accès échoue si (SignUtil.CheckSignature (dnbx_token, signature, horodat, nonce)) {logger.info ("connecter le serveur Weixin réussit."); réponse.getWriter (). WRITE (ECHOSTR); } else {Logger.Error ("n'a pas vérifié la signature!"); }}else{String respMessage = "Exception message! ";try {respMessage = wechatService.weixinPost(request);out.write(respMessage);LOGGER.info("The request completed successfully");LOGGER.info("to weixin server "+respMessage);} catch (Exception e) {LOGGER.error("Failed to convert the message from Weixin! "); }}} catch (exception e) {logger.error ("Connecter le serveur Weixin est une erreur.");} enfin {out.close ();}}}3. Signature de vérification de la signature
À partir du contrôleur ci-dessus, nous pouvons voir que je résume un signal de classe d'outils, appelé un signature de vérification, et passé en quatre valeurs, dnbx_token, signature, horodatage, nonce. Ce processus est très important. En fait, nous pouvons le comprendre comme un processus de cryptage et de décryptage de la valeur transmise par WeChat. Afin d'assurer la sécurité, toutes les interfaces dans de nombreux grands projets auront un tel processus de vérification. Dnbx_token Nous avons configuré une chaîne de jeton sur la plate-forme publique WeChat, gardez l'idée confidentielle! Les trois autres sont des paramètres envoyés par le serveur WeChat pour envoyer une demande GET. Nous effectuons une couche de cryptage SHA1:
Classe publique SignUtil {/ ** * Signature de vérification * @param token wechat Server token, configuré dans le fichier Env.properties et configuré dans le centre de développeur doit être cohérent * @param signature Le serveur WeChat envoie le SHA1 Certificat crypté Signature * @param Timestamp TimeSamp * @param nonce numéro * @retrin token, string signature, string horodatamp, string nonce) {string [] arr = new String [] {token, horodatamp, nonce}; // Trier le dictionnaire Ordre de jeton, d'horodatage et de nonce; // Splice les trois chaînes de paramètres dans une chaîne pour la chaîne de chiffrement Sha1 tmptr = sha1.encode (arr [0] + arr [1] + arr [2]); // La chaîne cryptée SHA1 peut être comparée à la signature, identifiant que la demande provient de WeChat Return Tmptr! = NULL? tmptr.equals (signature.touppercase ()): false; }}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»}; / ** * prend les octets bruts du digest et les forme correctement. * * @param octets Les octets bruts du digest. * @return les octets formatés. * / String statique privé getformattedText (byte [] bytes) {int len = bytes.length; StringBuilder buf = new StringBuilder (len * 2); // convertit le texte chiffré en une forme de chaîne hexadécimale pour (int j = 0; j <len; j ++) {buf.append (hex_digits [(bytes [j] >> 4) & 0x0f]); buf.append (hex_digits [octets [j] & 0x0f]); } return buf.toString (); } public static String Encode (String str) {if (str == null) {return null; } essayez {messagediGest MessagediGest = MessagediGest.getInstance ("sha1"); MessagediGest.update (str.getBytes ()); return getformatTtedText (MessagediGest.digest ()); } catch (exception e) {lancer une nouvelle RuntimeException (e); }}} Lorsque vous le soumettez et l'enregistrez sur la plate-forme publique et que vous voyez l'invite verte "Access Success", félicitations pour avoir terminé l'accès à WeChat. Ce processus nécessite un peu plus de prudence et fait attention à l'affaire dans l'algorithme de chiffrement. Si l'accès n'est pas réussi, la plupart des cas sont des problèmes avec l'algorithme de chiffrement, vérifiez-le davantage.
4. Implémentez le service de réponse de message automatique
/ *** Les demandes de processus de wechat * * @param request * @ return * / public String weixinPost (httpServLetRequest request) {String respsensage = null; try {// xml request analyse map <string, string> requestmap = messutil.xmltomap (request); // Sender Account (open_id) string fromUsname = requestmap.get ("FromUserName"); // public compte String Tuername = requestmap.get ("Tausername"); // Type de message String msgType = requestmap.get ("MSGTYPE"); // Message Content String Content = requestMap.get ("Content"); Logger.info ("FromUserName est:" + FromUndame + ", tousame. ", MsgType est:" + msgType); // message texte if (msgtype.equals (messageutil.req_message_type_text)) {// La logique correspondante est exécutée en fonction des mots clés. Il n'y a qu'un seul que vous ne pouvez pas imaginer. Il n'y a rien de tel que vous ne pouvez pas faire si (contenu.equals ("xxx")) {} // Réponse automatique textMessage text = new TextMessage (); text.setContent ("le texte est" + contenu); text.setTouseName (FromUserName); ""); text.setmsgType (msgType); respMessage = MessageUtil.TextMessageTOxML (Text);} / * else if (msgType.equals (MessageUtil.req_Message_Type_Event)) {// Event Push String EventType = requestMap.get ("Event"); // Type d'événement (eventType.equals (messageutil.event_type_subscribe)) {// Abonnez-vous à rescontent = "Bienvenue à suivre le compte officiel xxx!"; return messageResponse.getTextMessage (FromUserName, Tuername, rescontent);} else if (eventType.equals (menutSey.event_type_click) {//Souled menu ClueTeUtil.event_type_click) {//Souled menu ClueTeUtil.event_type_click) {//Souled menu ClueTeUtil.event_type_click) {//Souled menu Clueype.event_type_click) {//seumpals click.event_type; eventKey = requestmap.get ("EventKey"); // Valeur de clé d'événement, correspondant à la valeur clé spécifiée lors de la création du menu personnalisé Logger.info ("EventKey est:" + EventKey); return xxx;}} // Activer WECHAT Sound Recognition Test 2015-3-30ELSE requestmap.get ("reconnaissance"); // respontent = "Résultat de l'analyse de la parole reçue:" + recvMessage; if (recvMessage! = null) {respacent = tulingapiprocess.gettulingResult (recvMessage);} else {respact = "ce que vous avez dit est trop vague, pouvez-vous le dire à nouveau?";} return messageResponse.getTextMessage (à partir du nom de toussert, respect); } // Fonction de photographie else if (msgType.equals ("pic_sysphoto")) {} else {return messageResponse.getTextMessage (FromUserName, Tausername, "return vide"); } * // Événement push else if (msgtype.equals (messageutil.req_message_type_event)) {String EventType = requestMap.get ("Event"); // Type d'événement // abonne Suivre, xxx "); text.setTousername (FromUserName); text.setFromUsername (Tausername); text.setCreateTime (new Date (). GetTime () +" "); text.setmsgtype (messageutil.resp_message_type_text); respsessage = MessageUtil. Désubscribe, l'utilisateur ne peut pas recevoir le message envoyé par le compte officiel, il n'est donc pas nécessaire de répondre au message else if (eventType.equals (messageutil.event_type_unsubscribe)) {// dissubscribe} // Menu personnalisé cliquez sur l'événement if (EventType.equals (MessageUtil.event_type_click)) Valeur de clé de l'événement, correspondant à la valeur clé spécifiée lors de la création du menu personnalisé if (eventKey.equals ("customer_telephone")) {textMessage text = new TextMessage (); text.setSontent ("0755-86671980"); Text.SetTountame (FromUserAmE); NewSet.SetFromename (tousename); Date (). GetTime () + ""); text.setmsGtype (messageutil.resp_message_type_text); respsensage = messageUtil.textMessageToxMl (text);}}}}} catch (exception e) {logger.error ("Erreur ...")} retour respect;}Le code est affiché comme ci-dessus. La plupart d'entre eux ont des commentaires. Si vous lisez la sémantique de base une fois, vous n'avez pas besoin de les expliquer.
Brève idée: Lorsqu'un utilisateur envoie un message au compte officiel, le serveur WeChat demandera le message de l'utilisateur par Post sur l'interface correspondante du serveur que nous avons configuré au format XML. Ce que nous devons faire est d'effectuer un traitement logique correspondant en fonction du type de message, etc., et de renvoyer le résultat de retour final au serveur WeChat via le format XML, puis de le transmettre à l'utilisateur.
Il y a un endroit qui nécessite une attention particulière:
Le Rouge de couleur FromUnName et Tousername sont exactement le contraire, qui est également l'un des pièges. Je me souviens que je l'avais ajusté pendant longtemps, mais ce n'était pas un problème, mais cela ne fonctionnait pas. Enfin, j'ai reçu le message après avoir changé ces deux! En fait, il est correct d'y penser. Lorsque vous revenez au serveur WeChat, votre rôle va changer, donc l'expéditeur et le récepteur sont certainement le contraire.
5.MessageUtil
classe publique MessageUtil {/ ** * Retour Type de message: texte * / public static final string resp_message_type_text = "text"; / ** * RETOUR TYPE DE MESSAGES: MUSIQUE * / PUBLIC STATIQUE FINAL STRING REP_MESSAGE_TYPE_MUSIC = "MUSIQUE"; / ** * Type de message de retour: texte graphique * / public statique final statique resp_message_type_news = "news"; / ** * Type de message de demande: texte * / public static final String req_message_type_text = "text"; / ** * Type de message de demande: image * / public static final String req_message_type_image = "image"; / ** * Type de message de demande: lien * / public static final String req_message_type_link = "link"; / ** * Type de message de demande: Emplacement géographique * / Public Static Final String req_Message_Type_Location = "Location"; / ** * Type de message de demande: Audio * / public static final String req_message_type_voice = "Voice"; / ** * Type de message de demande: push * / public static final String req_message_type_event = "Event"; / ** * Type d'événement: abonnez-vous (abonnez-vous) * / public static final String event_type_subscribe = "abonnez-vous"; / ** * Type d'événement: Désubscribe (Unbscribe) * / public static final String event_type_unsubscribe = "Désubscribe"; / ** * Type d'événement: cliquez sur (Menu personnalisé Click Event) * / public static final String Event_Type_Click = "Click"; }Ici, afin d'améliorer la lisibilité et de l'évolutivité du programme, j'ai fait de l'encapsulation, défini plusieurs constantes et encapsulé certains paramètres passés de WeChat dans des objets persistants Java Bean. Le code central est comme ci-dessus. Concentrez-vous sur la conversion entre XML et MAP
En fait, ce problème est attribué à WeChat en utilisant la communication XML, et nous utilisons généralement JSON, nous pouvons donc nous sentir un peu inconfortables dans un court laps de temps.
1. introduce paquet
<! - Parse XML -> <Dedency> <GroupId> Dom4j </proupId> <ArtifActid> Dom4j </ Artifactid> <De version> 1.6.1 </ Version> </ Dependency> <Dedency> <ProupID> com.thoughtworks.xstream </proupId> </ version> </Dedirenty>
2.xml à cartographier l'objet de collecte
/ *** xml converti en map * @param request * @ return * @throws ioexception * / @ suppresswarnings ("Unchecked") public static map <string, string> xmltomap (httpservletRequest request) lance ioException {map <string, string> map = new hashmap <string> (); saxReader leader = new saxread (); string> (); saxReader leader = leader = nouveau saxread (); ins = null; try {ins = request.getInputStream ();} catch (ioException e1) {e1.printStackTrace ();} document doc = null; try {doc = reader.read (ins); element root = doc.getrootelement (); list> list = root.elements (); for (élément e: list) {map.put (. e.getText ());} retour de la carte;} catch (documentException e1) {e1.printStackTrace ();} enfin {ins.close ();} return null;}3. Convertir l'objet de message texte en XML
/ ** * Convertir un objet de message texte à XML * * @param TextMessage Message Object * @return xml * / public static String TextMessageToxMl (TextMessage TextMessage) {xstream xstream = new Xstream (); xstream.alias (xml ", textMessage);Ce qui précède est l'introduction de l'éditeur à Java pour implémenter l'accès SpringMVC WeChat et implémenter une fonction de réponse automatique simple. J'espère que ce sera utile à tout le monde. Si vous avez des questions, veuillez me laisser un message et l'éditeur répondra à tout le monde à temps. Merci beaucoup pour votre soutien au site Web Wulin.com!