1. Préparation
D'innombrables personnes ont posé des questions sur le développement du modèle un, donc je l'ai publié ici pour référence uniquement. J'ai expliqué la différence entre le mode un et le mode deux plusieurs fois. Ce n'est rien de plus que le code QR du mode un pour le produit, et le code QR du mode deux est pour la commande. Je n'ai pas à parler d'autres détails spécifiques. Vous pouvez accéder au document officiel pour afficher le document par vous-même, puis choisir le mode un ou le mode deux et cela dépend de votre entreprise.
1.1. Paramètres de configuration connexes
Les quatre choses avant, App_id et App_secret se trouvent sur la plate-forme publique, tandis que MCH_ID et API_KEY se trouvent sur la plate-forme marchande, en particulier API_KEY doit être défini sur la plate-forme marchande. Cette chose est liée à l'exactitude de la vérification des paramètres, il doit donc être réglé correctement. Le modèle de paiement du code QR 1 est en fait similaire au modèle de paiement du code QR 2. En fait, il utilise uniquement App_ID, MCH_ID et API_KEY et n'utilise rien d'autre. L'adresse officielle du document du mode Mode est ici: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4
1.2. Concepts connexes
Ici, je veux d'abord corriger un concept. Au cours du développement du deuxième modèle, j'ai mentionné un concept comme "Adresse de rappel de paiement". Sa fonction est qu'après que le client a analysé et terminé le paiement, le serveur WeChat doit accéder à l'adresse fournie par nous et nous envoyer les résultats de paiement afin que nous puissions vérifier la commande de livraison. Il s'agit d'un concept et d'un nom relativement courant pour d'autres outils de paiement. Cependant, plus tard, j'ai examiné les documents sur le site officiel de WeChat et j'ai constaté que dans le premier développement du modèle, ils ont appelé cela "URL de notification asynchrone" au lieu d'une "adresse de rappel de paiement", mais cela fait essentiellement référence au même sens. Mais pourquoi est-ce que je mentionne cette chose ici? En effet, en mode premier, il y a en fait un autre soi-disant "rappel de paiement" appelé "URL de rappel de paiement du code de numérisation". Cette chose est différente de la "URL de notification asynchrone" ci-dessus. Il peut être simplement compris qu'il s'agit d'une interface sur notre serveur pour aider à terminer les commandes. Le développement du mode un nécessite la coopération des deux interfaces de "Scan le code QR pour payer l'URL de rappel" et "URL de notification asynchrone", afin que tout le monde le distingue ici.
"URL de notification asynchrone" est défini lors de l'appel d'une interface unique unifiée. Il peut être défini dynamiquement, tant que cette interface reçoit des paramètres de réponse des paramètres en fonction des règles pertinentes. Le "Scan le code QR pour payer l'URL de rappel" est relativement fixe. Il se déroule sur la plate-forme publique WeChat. Il faut environ 10 minutes pour prendre effet après le réglage. Après vous être connecté à la plate-forme publique WeChat, sélectionnez WeChat Pay et vous pouvez le trouver sous l'onglet Configuration de développement:
Ici, nous devons configurer l'adresse de notre propre serveur (et dire à nouveau l'adresse du réseau public, afin que le serveur WeChat puisse vous trouver).
1.3. Environnement de développement
J'utilise le servlet 3.0 le plus basique comme environnement d'échantillon ici. En ce qui concerne la référence des packages JAR tiers, par rapport au développement du modèle 2, en plus d'utiliser l'opération XML JDom, il existe un package de code QR Google ZXing et un package log4j. Comme indiqué dans la figure ci-dessous:
Afin de faciliter le débogage, il est recommandé de réduire d'abord le réglage de cet environnement avant de le transplanter au projet réel.
2. Développement et combat pratique
Avant de commencer, je vous suggère d'aller au document officiel pour examiner bien le tableau de synchronisation. Après avoir compris le tableau de synchronisation, l'écriture de code n'est pas une tâche difficile. Bien sûr, si vous ne pouvez pas comprendre l'image, vous pouvez également essayer de le comprendre en combinaison avec mon code suivant.
2.1. Génération de code QR
Tout d'abord, il y a un code QR. Le contenu du code QR est un lien, et le formulaire est:
weixin: // wxpay / bizpayurl? Sign = xxxxx & appid = xxxxx & mch_id = xxxxx & product_id = xxxxx & time_stamp = xxxxx & nonce_str = xxxxxxxx & nonce_str = xxxxxxxxxx
Pour plus de détails, vous pouvez vous référer au mode de document officiel pour générer des règles de code QR. Ensuite, nous devons générer un code QR pour ce lien. J'ai utilisé Google Zxing ici pour générer un code QR.
package com.wqy; Importer java.io.ioException; import java.io.outputStream; import java.util.hashmap; Importer java.util.iterator; importation java.util.map; import java.util.set; import java.util.sortedmap; import java.util.treemap; Importer javax.servlet.servletException; Importer javax.servlet.annotation.webservlet; import javax.servlet.http.httpservlet; Importer javax.servlet.http.httpservletRequest; import javax.servlet.http.httpservletResponse; import org.apache.log4j.logger; import com.google.zxing.barcodeFormat; import com.google.zxing.encodeHintType; import com.google.zxing.multiformatwriter; Importer com.google.zxing.writereXception; import com.google.zxing.client.j2se.matrixtoimagewriter; import com.google.zxing.common.bitmatrix; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; import com.wqy.util.paycommonutil; import com.wqy.util.payconfigutil; / ** * Classe d'implémentation de servlet Pay1 * / @webservlet ("/ Pay1") Classe publique Pay1 étend httpservlet {private static final long SerialVersionUID = 1l; Logger statique privé = logger.getLogger (pay1.class); public static int defaultwidthandHeight = 200; / ** * @see httpservlet # httpservlet () * / public pay1 () {super (); // Todal du constructeur généré automatiquement} / ** * @see httpservlet # doget (HttpServLetRequest, httpservletResponse * réponse) * / Protected void Doget (HttpServletRequest PayCommonutil.getNonce_str (); long time_stamp = System.currentTimemillis () / 1000; String product_id = "hd_goodsssss_10"; String key = payconfigutil.api_key; // clé tridmap <objet, objet> packageParams = new Treemap <objet, objet> (); packageParams.put ("appid", payconfigutil.app_id); packageParams.put ("mch_id", payconfigutil.mch_id); packageParams.put ("time_stamp", string.valueof (time_stamp)); packageParams.put ("nonce_str", nonce_str); packageParams.put ("product_id", product_id); String Sign = PayComMonutil.CreateSign ("UTF-8", PackageParams, Key); // MD5 Hash PackageParams.put ("Sign", signe); // générer des paramètres String str = tourlparams (packageParams); Chaîne payurl = "weixin: // wxpay / bizpayurl?" + str; Logger.info ("Payurl:" + PayUrl); // Générer le code QR Map <EncodeHintType, objet> hins = new HashMap <EncodeHintType, objet> (); // Générer le code QR Map <EncodeHintType, objet> (); // Spécifiez le niveau de correction d'erreur Hinnts.put (EncodeHintType.Error_Correction, ErrorCorrectionLevel.l); // Spécifiez le format de codage Hinnts.put (EncodeHintType.Caracter_Set, "UTF-8"); Hint.put (EncodeHintType.Margin, 1); try {bitMatrix bitMatrix = new multiformatwriter (). Encode (payurl, barcodeFormat.qr_code, defaultwidthandHeight, defaultwidthandHeight, hints); OutputStream out = réponse.getOutputStream (); Matrixtoimagewriter.writeToStream (bitmatrix, "png", out); // output qr code out.flush (); out.close (); } catch (withereXception e) {// TODO Block de capture générée automatiquement e.printStackTrace (); }} public String tourlparams (tridmap <objet, objet> packageParams) {// En fait, vous ne pouvez pas trier StringBuffer sb = new StringBuffer (); Set es = packageParams.EntrySet (); Iterator it = es.iterator (); while (it.hasnext ()) {map.entry entrée = (map.entry) it.next (); String k = (String) entry.getKey (); String v = (String) entry.getValue (); if (null! = v &&! "". equals (v)) {sb.append (k + "=" + v + "&"); }} sb.deletecharat (sb.length () - 1); // supprimer le dernier et return sb.toString (); } / ** * @see httpServlet # doPost (httpsservletRequest request, httpservletResponse * réponse) * / protected void doPost (httpServletRequest, httpservletResponse réponse) lance servletException, ioException {// todo ateroated Method Stub Doget (request, réponse); }} 2.2. Analyser l'interface URL de rappel de paiement
Lorsque le client scanne le code à deux chiffres ci-dessus avec WeChat, le serveur WeChat accédera à cette interface. Ici, nous devons terminer l'ordre unifié pour obtenir l'identifiant de session de transaction. Le principal processus de traitement est le suivant:
1) Recevoir les paramètres envoyés par le serveur WeChat et effectuer une vérification de signature des paramètres;
2) Sortez le paramètre product_id, qui est le seul paramètre qui peut être transmis via le code QR. D'autres paramètres peuvent être saisis conformément au mode de document officiel 1.1;
3) Traitez votre propre entreprise selon Product_id, telles que le calcul du montant de paiement, la génération de numéros de commande, etc.;
4) Appelez l'interface unique unifiée pour obtenir l'identifiant de session de transaction prépay_id;
4.1) Préparez les paramètres pertinents (tels que AppID, MCH_ID, le montant du paiement, le numéro de commande, la description du produit, etc.), appelez WeChat pour unifier l'interface unique (similaire à l'interface unique unifiée de l'appel du mode 2). Faites attention à «l'URL de notification asynchrone susmentionnée», qui est l'interface URL de notification asynchrone qui sera mentionnée plus loin. Pour des paramètres spécifiques, reportez-vous au document officiel pour unifier les paramètres de demande unique;
4.2) Recevez les paramètres renvoyés par l'interface unique unifiée et vérifiez les paramètres;
4.3) Sortez le paramètre prepay_id, qui est l'identifiant de session de transaction, ce qui est extrêmement important. D'autres paramètres peuvent être référés au document officiel pour retourner le résultat;
5) Préparez les paramètres pertinents (tels que AppID, MCH_ID, return_code, prepay_id, etc.) et répondez au rappel de paiement initial (si les étapes ci-dessus sont fausses, si la vérification de connexion échoue, vous pouvez retourner les paramètres d'erreur au serveur WeChat). Pour des paramètres spécifiques, veuillez vous référer au mode de document officiel 1.2 Paramètres de sortie.
package com.wqy; Importer java.io.BufferedOutputStream; Importer java.io.bufferedReader; Importer java.io.ioException; Importer java.io.inputStreamReader; Importer java.io.inputStreamReader; import java.util.sortedmap; import java.util.treemap; Importer javax.servlet.servletException; Importer javax.servlet.annotation.webservlet; import javax.servlet.http.httpservlet; Importer javax.servlet.http.httpservletRequest; import javax.servlet.http.httpservletResponse; import org.apache.log4j.logger; import com.wqy.util.httputil; import com.wqy.util.paycommonutil; import com.wqy.util.payconfigutil; / ** * Classe d'implémentation servlet Notify1 * / @webservlet ("/ notify1") classe publique Notify1 étend httpservlet {private static final long SerialVersionUID = 1l; Logger statique privé = logger.getLogger (notify1.class); / ** * @see httpServlet # httpservlet () * / public notify1 () {super (); // TOUT AUTO AUTO AUTO AUTO} / ** * @SEE HTTPSERVLET # DOGET (HttpServLetRequest Request, HttpServletResponse * Response) * / Protected Void Doget (HttpServletRequest Request, HttpservletResponse Réponse) LugetSexe InputStream; StringBuffer sb = new StringBuffer (); inputStream = request.getInputStream (); String S; BufferedReader dans = new BufferedReader (new InputStreamReader (InputStream, "UTF-8")); while ((s = in.readline ())! = null) {sb.append (s); } in.close (); inputStream.close (); TridMap <objet, objet> packageParams = PayComMonutil.xmlConvertToMap (sb.toString ()); Logger.info (packageParams); // Informations de compte Key Key = PayConfigutil.API_KEY; // key String resxml = ""; // feedback to WeChat Server // Sign-in Verification if (PayComMonutil.istenpaySign ("utf-8", packageParams, key)) {// appid openId mch_id is_subscribe nonce_str product_id Sign // Unify Single String openId = (String) packageParams.get ("openId"); String product_id = (string) packageParams.get ("product_id"); // parse product_id, calculer le prix, etc. String out_trade_no = string.valueof (System.CurrentTimemillis ()); // Numéro d'ordre String Order_price = "1"; // Prix Remarque: L'unité de prix est divisée en corde de corde = Product_id; // Le nom du produit est défini sur Product_id String attach = "xxx store"; // chaîne de données supplémentaire nonce_str0 = PayComMonutil.getNonce_str (); // Obtenez la chaîne IP d'ordinateur initiat SPBILL_CREATE_IP = PayConfigutil.create_ip; String Trade_Type = "Native"; TriMedMap <objet, objet> unifiedParams = new Treemap <objet, objet> (); UnifiedParams.put ("AppID", PayConfigutil.app_id); // UnifiedParams.put ("MCH_ID", PayConfigutil.mch_id); // UnifiedParams.put ("out_trade_no", out_trade_no); // UnifiedParams.put ("product_id", product_id); UnifiedParams.put ("corps", corps); // UnifiedParams.put ("attacher", attacher); UnifiedParams.put ("Total_Fee", Order_Price); // doit être UnifiedParams.put ("nonce_str", nonce_str0); // doit être UnifiedParams.put ("spbill_create_ip", spbill_create_ip); // doit être UnifiedParams.put ("Trade_Type", Trade_Type); // doit être UnifiedParams.put ("OpenID", OpenID); UnifiedParams.put ("notify_url", payconfigutil.notify_url); // String URL de notification asynchrone Sign0 = PayComMonutil.CreateSign ("UTF-8", UnifiedParams, Key); UnifiedParams.put ("Sign", Sign0); // Signature String requestxml = PayComMonutil.getRequestXml (UnifiedParams); logger.info (requestXml); // chaîne d'interface unique unifiée rxml = httputil.postData (payconfigutil.ufdoder_url, requestXml); // Unified Response SORDMAP <Object, Object> Reparams = PayComMonutil.xmlConvertToMap (RXML); Logger.info (réparams); // Vérifiez if (PayComMonutil.istenPaySign ("UTF-8", réparams, key)) {// Unify les paramètres renvoyés par la chaîne unique prepay_id = (string) réparams.get ("prepay_id"); // Identification de session de transaction valide dans les 2 heures String nonce_str1 = PayComMonutil.getNonce_str (); TriMedMap <objet, objet> Resparams = new Treemap <objet, objet> (); Resparams.put ("return_code", "succès"); // Resparams.put ("return_msg", "ok"); Resparams.put ("AppID", PayConfigutil.app_id); // Resparams.put ("mch_id", payconfigutil.mch_id); Resparams.put ("nonce_str", nonce_str1); // Resparams.put ("prepay_id", prepay_id); // Resparams.put ("result_code", "succès"); // doit être rageams.put ("err_code_des", "ok"); String Sign1 = PayComMonutil.CreateSign ("UTF-8", Resparams, Key); Resparams.put ("Signe", Sign1); // Signature Resxml = PayComMonutil.getRequestXml (Resparams); logger.info (resxml); } else {logger.info ("Erreur de vérification de signature"); resxml = "<xml>" + "<fettour_code> <! [cdata [fail]]> </ return_code>" + "<retour_msg> <! [CDATA [Erreur de vérification de signature]> </ return_msg>" + "</ xml>"; }} else {logger.info ("Erreur de vérification de signature"); resxml = "<xml>" + "<fettour_code> <! [cdata [fail]]> </ return_code>" + "<retour_msg> <! [CDATA [Erreur de vérification de signature]> </ return_msg>" + "</ xml>"; } // ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- out.write (resxml.getBytes ()); out.flush (); out.close (); } / ** * @see httpServlet # doPost (httpsservletRequest request, httpservletResponse * réponse) * / protected void doPost (httpServletRequest, httpservletResponse réponse) lance servletException, ioException {// todo ateroated Method Stub Doget (request, réponse); }}À ce stade, la commande WeChat de l'utilisateur affichera le montant à payer et la description du produit, puis attendez que le client termine le paiement.
2.3. Notification asynchrone de l'interface URL
Lorsque l'utilisateur termine l'opération de paiement sur WeChat, le serveur WeChat informera de manière asynchrone l'interface et nous enverra le résultat de paiement final afin que nous puissions vérifier la commande de livraison et d'autres opérations. Notez que cette interface est exactement la même que le développement du modèle 2. Le processus général est le suivant:
1) Recevoir les paramètres envoyés par le serveur WeChat et effectuer une vérification de signature des paramètres;
2) Sortez les paramètres result_code, le numéro de commande OUT_TRADE_NO, le montant de commande total_fee et d'autres paramètres liés aux entreprises. Les paramètres spécifiques peuvent être référés aux paramètres de notification de la notification générale des résultats de paiement dans le document officiel;
3) Traitement des activités, telles que la vérification du numéro de commande et du montant de la commande, de la modification de l'état de la commande, etc.;
4) Préparez les paramètres pertinents (return_code et return_msg) et répondez au serveur WeChat.
Notez que si WeChat reçoit les réponses du marchand qui ne réussissent pas ou ne sont pas chronométrées et que WeChat estime que la notification a échoué, WeChat réinitialisera régulièrement les notifications grâce à certaines stratégies pour augmenter le taux de réussite des notifications autant que possible, mais WeChat ne garantit pas que la notification réussira à la fin. (La fréquence de notification est 15/15/30/1800/1800/1800/1800/1800/1800/3600, unité: secondes)
package com.wqy; Importer java.io.BufferedOutputStream; Importer java.io.bufferedReader; Importer java.io.ioException; Importer java.io.inputStreamReader; Importer java.io.inputStreamReader; import java.util.sortedmap; Importer javax.servlet.servletException; Importer javax.servlet.annotation.webservlet; import javax.servlet.http.httpservlet; Importer javax.servlet.http.httpservletRequest; import javax.servlet.http.httpservletResponse; import org.apache.log4j.logger; import com.wqy.util.paycommonutil; import com.wqy.util.payconfigutil; / ** * Classe d'implémentation servlet re_notify * / @webservlet ("/ re_notify") classe publique re_notify étend httpservlet {private static final SerialVersionUID = 1l; Logger statique privé = logger.getLogger (re_notify.class); / ** * @see httpservlet # httpservlet () * / public re_notify () {super (); // Todal du constructeur généré par la tâche} / ** * @see httpservlet # doget (HttpServLetRequest Request, httpservletResponse * réponse) * / Protected void Doget (HttpServletRequest Request, httpservletResponse Response) Throws Netweter Entrée, IoException {// TODO Auto-genera méthode Stub //serestr InputStream; StringBuffer sb = new StringBuffer (); inputStream = request.getInputStream (); String S; BufferedReader dans = new BufferedReader (new InputStreamReader (InputStream, "UTF-8")); while ((s = in.readline ())! = null) {sb.append (s); } in.close (); inputStream.close (); TridMap <objet, objet> packageParams = PayComMonutil.xmlConvertToMap (sb.toString ()); Logger.info (packageParams); // Informations de compte Key Key = PayConfigutil.API_KEY; // string key resxml = ""; // Commentaires sur WeChat Server // Déterminez si la signature est correcte si (PayComMonutil.istenPaySign ("UTF-8", PackageParams, Key)) {// ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- out_trade_no = (string) packageParams.get ("out_trade_no"); String total_fee = (string) packageParams.get ("total_fee"); Logger.info ("mch_id:" + mch_id); Logger.info ("OpenID:" + OpenID); logger.info ("is_subscribe:" + is_subscribe); Logger.info ("out_trade_no:" + out_trade_no); logger.info ("total_fee:" + total_fee); //////////////////////////////////////// Exécuter votre propre logique commerciale //////////////// Logger.info ("Paiement réussi"); // informer WeChat. La confirmation asynchrone est réussie. Doit l'écrire. Sinon, l'arrière-plan sera informé tout le temps. Après huit fois, vous penserez que la transaction a échoué. resxml = "<xml>" + "<Auttour_code> <! [CDATA [Success]]> </ return_code>" + "<retour_msg> <! [cdata [ok]]> </ return_msg>" + "</xml>"; } else {Logger.info ("Pay Faich, Message d'erreur:" + packageParams.get ("err_code")); resxml = "<xml>" + "<Adgower_code> <! [cdata [échoué]]> </ return_code>" + "<retour_msg> <! [cdata [message est vide]]> </ return_msg>" + "</ xml>"; }} else {logger.info ("Erreur de vérification de signature"); resxml = "<xml>" + "<fettour_code> <! [cdata [fail]]> </ return_code>" + "<retour_msg> <! [CDATA [Erreur de vérification de signature]> </ return_msg>" + "</ xml>"; } // ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- BufferedOutputStream (Response.getOutputStream ()); out.write (resxml.getBytes ()); out.flush (); out.close (); } / ** * @see httpServlet # doPost (httpsservletRequest request, httpservletResponse * réponse) * / protected void doPost (httpServletRequest, httpservletResponse réponse) lance servletException, ioException {// todo ateroated Method Stub Doget (request, réponse); }} 3. Résultats des tests
3.1. Le lien de code QR de paiement généré
3.2. Paramètres reçus par l'interface URL de rappel de paiement
3.3. Lancer des paramètres de demande unique unifiés
3.4. Unifier les paramètres de retour unique
3.5. Paramètres de réponse finaux de l'interface URL de rappel de paiement
Ce qui précède est tout le contenu de cet article. J'espère que cela sera utile à l'apprentissage de tous et j'espère que tout le monde soutiendra davantage Wulin.com.