Récemment, j'ai été exposé à certaines choses sur le paiement de WeChat dans mon travail. J'ai vu que les démos que j'ai données étaient toutes des versions PHP, et je n'étais vraiment pas satisfait des documents de paiement WeChat. Après avoir vécu de nombreux pièges, j'étais inactif de faire un résumé.
1. Préparation
Pour développer WeChat, vous devez d'abord demander un compte public. Une fois la demande réussie, vous vous êtes envoyé par e-mail. Le compte public contient des documents de développement, des informations nécessaires pendant le développement et des requêtes de données pour les tests.
2. Outils
1.MD5 Classe d'outils de chiffrement
package com.pay.utils.weixin; importer java.security.Messagedigest; hexDigits [] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; essayez {byte [] btinput = s.getBytes (); // Obtenez l'objet MessagediGest de l'algorithme MD5 Digest MessagediGest mdinst = MessagediGest.getInstance ("MD5"); // Mette à jour le digest mdinst.update (btinput); // obtient l'octet de chiffre d'affaires [] md = mdinst.digest (); // Convertir le texte chiffré en une forme de chaîne hexagonale int j = md.length; char Str [] = new Char [J * 2]; int k = 0; for (int i = 0; i <j; i ++) {byte byte0 = md [i]; str [k ++] = hexDigits [byte0 >>> 4 & 0xf]; str [k ++] = hexDigits [byte0 & 0xf]; } return new String (str); } catch (exception e) {e.printStackTrace (); retourner null; }}}2. Classe d'outils Commonutil , utilisée pour remplacer le XML requis pour WeChat. Le retour suivant new String (xml.ToString (). GetBytes (), "ISO8859-1"); Modifier UTF-8 dans la classe d'outils en ISO8859-1, sinon le texte chinois de l'ordre WeChat semblera brouillé, et il peut être affiché correctement après le changement.
package com.pay.utils.weixin; importer java.io.unsupportedencodingException; import java.net.urlencoder; import java.util. *; import java.util.map.entry; public class communUtil {public static string createoncestr (int longueur) {string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; String res = ""; pour (int i = 0; i <length; i ++) {random rd = new random (); res + = Chars.Indexof (rd.nextint (Chars.Length () - 1)); } return res; } public static String createNOnCestr () {String Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; String res = ""; for (int i = 0; i <16; i ++) {random rd = new random (); res + = Chars.Charats (rd.Nextint (Chars.Length () - 1)); } return res; } public static String formatQueryParamap (hashmap <string, string> Paramètres) lève sdkruntimeException {String buff = ""; try {list <map.entry <string, string >> infoid = new ArrayList <map.entry <string, string >> (Paramètres.EntrySet ()); Collection.Sort (Infoids, nouveau comparateur <map.entry <string, string >> () {public int compare (map.entry <string, string> o1, map.entry <string, string> o2) {returnkey (o1.getKey ()). for (int i = 0; i <infoids.size (); i ++) {map.entry <string, string> item = infoids.get (i); if (item.getKey ()! = "") {buff + = item.getKey () + "=" + urlencoder.encode (item.getValue (), "utf-8") + "&"; }} if (buff.isempty () == false) {buff = buff.substring (0, buff.length () - 1); }} catch (exception e) {lancer un nouveau sdkruntimeException (e.getMessage ()); } return buff; } public static String formatBizQueryParamap (hashmap <string, string> paramap, boolean urlencode) lève sdkruntimeException {string buff = ""; try {list <map.entry <string, string >> infoid = new ArrayList <map.entry <string, string >> (paramap.entryset ()); Collection.Sort (Infoids, nouveau comparateur <map.entry <string, string >> () {public int compare (map.entry <string, string> o1, map.entry <string, string> o2) {returnkey (o1.getKey ()). for (int i = 0; i <infoids.size (); i ++) {map.entry <string, string> item = infoids.get (i); //System.out.println (item.getKey ()); if (item.getKey ()! = "") {String key = item.getKey (); String val = item.getValue (); if (urlencode) {val = urlencoder.encode (val, "utf-8"); } buff + = key.tolowercase () + "=" + val + "&"; }} if (buff.isempty () == false) {buff = buff.substring (0, buff.length () - 1); }} catch (exception e) {lancer un nouveau sdkruntimeException (e.getMessage ()); } return buff; } public static boolean isNumeric (String str) {if (str.matches ("// d *")) {return true; } else {return false; }} public static String arraytoxml (hashmap <string, string> arr) {string xml = "<xml>"; Iterator <entrée <string, string >> iter = arr.entryset (). Iterator (); while (iter.hasnext ()) {entrée <string, string> entry = iter.next (); String key = entry.getKey (); String val = entry.getValue (); if (isNumeric (val)) {xml + = "<" + key + ">" + val + "</" + key + ">"; } else xml + = "<" + key + "> <! [cdata [" + val + "]]> </" + key + ">"; } xml + = "</ xml>"; essayez {return new String (xml.toString (). getBytes (), "iso8859-1"); } catch (UnportEnCoDingException e) {// Bloc de catch généré automatiquement de TODO E.PrintStackTrace (); } retour ""; }}3.ClientCustomSSL Tool Class , utilisé pour générer des signes et créer un package de commande WeChat com.pay.utils.weixin;
Importer java.util.arraylist; import java.util.collections; import java.util.comparator; import java.util.hashmap; import java.util.list; import java.util.map; import org.springframework.util.stringutils; / ** * cet exemple démontre comment créer des connexions sécurisées avec un contexte personnalisé *. * / public class ClientCustomSSL {public static String getBizSign (hashmap <string, string> bizobj) lève sdkruntimeException {hashmap <string, string> bizparameters = new HashMap <String, String> (); List <map.entry <string, string >> infoids = new ArrayList <map.entry <string, string >> (bizobj.entryset ()); System.out.println (Infoids); CollectionS.sort (Infoids, nouveau comparateur <map.entry <string, string >> () {public int compare (map.entry <string, string> o1, map.entry <string, string> o2) {return (o1.getKey ()). ToString (). Compareto (o2.getKey ());}}); System.out.TrprintLn ("---------------); System.out.println (Infoids); for (int i = 0; i <infoids.size (); i ++) {map.entry <string, string> item = infoids.get (i); if (item.getKey ()! = "") {bizparameters.put (item.getKey (). TolowerCase (), item.getValue ()); }} //bizparameters.put("Key "," 1234567812345678123456781234567812345671 "); String bizstring = Commonutil.formatBizQueryParamap (bizparameters, false); bizstring + = "& key = 123456781234567812345671"; System.out.println ("*****************"); System.out.println (bizstring); // retourne sha1util.sha1 (bizstring); retour md5util.md5 (bizstring); } / ** * WeChat Create Order * @param noncestr * @param orderDescribe * @param orderNo * @param prix * @param timestart * @param timeExpire * @return * @throws sdkruntimexception * / public static string createActivePackage (string nonCestr, string orderDescrip SdkruntimeException {hashmap <string, string> nativeoBj = new HashMap <String, String> (); nativeoBj.put ("appid", "voir le compte public"); // ID de compte public nativeoBj.put ("MCH_ID", "Voir Email"); // Numéro de marchand nativeoBj.put ("nonce_str", noncestr); // String aléatoire nativeoBj.put ("Body", OrderDescribe); // DESCRIPTION DU PRODUIT NativeObj.put ("attacher", "Tradeno"); // Données jointes nativeoBj.put ("out_trade_no", orderNo); // Numéro de commande marchande (global unique) nativeoBj.put ("total_fee", prix); // Montant total (l'unité est cent, ne peut pas être prise avec des points décimaux) nativeoBj.put ("SPBill_create_ip", "192.168.0.144"); // terminal ip nativeoBj.put ("time_start", timestart); // Time de début de transaction nativeoBj.put ("Time_Expire", TimeExpire); // Transaction End Time NativeoBj.put ("notify_url", personnaliséPropertyPlaceHolderConfigurer.getContextProperty ("wxurl") + "/ weixin_callback / weixincallback / init.action"); // Adresse de notification de rappel nativeoBj.put ("Trade_type", "native"); // Type de transaction Sign = getBizsign (nativeObj); nativeoBj.put ("signe", signe.touppercase ()); Retour Commonutil.ArrayToxMl (nativeoBJ); } / *** weChat Order Payment Query * @param noncestr * @param orderDescribe * @param orderNo * @param prix * @param timestart * @param timeExpire * @ return * @throws sdkruntimexception * / public static string searchNativepackage (String TransactionID {Hashmap <string, string> nativeoBj = new hashmap <string, string> (); nativeoBj.put ("appid", "voir le compte public"); // Public Account IdNativeObj.put ("MCH_ID", "Voir Email"); // Numéro de marchand nativeoBj.put ("nonce_str", noncestr); // chaîne aléatoire if (! StringUtils.isempty (transactionId)) {nativeoBj.put ("transaction_id", transactionId); } if (! stringUtils.isempty (outradeno)) {nativeoBj.put ("out_trade_no", outradeno); // String aléatoire} string signe = getBizSign (nativeoBj); nativeoBj.put ("Sign", Sign.ToupperCase ()); Retour Commonutil.ArrayToxMl (nativeoBJ); / *** wechat remboursement * @param outradeno * @param outrefundno * @param totalfee * @param totalfee * @param RefundFee * @ return * @throws sdkruntimeException * / public static RefundNativePackage (String Outtradeno) SdkruntimeException {hashmap <string, string> nativeoBj = new hashmap <string, string> (); nativeoBj.put ("appid", "voir le compte public"); // le compte public idNativeObj.put ("mch_id", "voir email"); // Merchant nombre nativeoBj.put ("nonce_tr", noncistr); // Random String nativeoBj.put ("out_trade_no", outradeno); // numéro de commande marchand (global unique) nativeoBj.put ("out_refund_no", purrefundno); // Numéro de commande de remboursement du commerçant (Unique unique) nativeoBj.put ("Total_Fee", totalfee); // montant total (unité dans cents, ne peut pas prendre de décimal) RefundFee); // Montant de remboursement (unité en cents, ne peut pas prendre de décimaux) nativeoBj.put ("op_user_id", "mail"); Sign de chaîne = getBizsign (nativeObj); nativeObj.put("sign", sign.toUpperCase());return CommonUtil.ArrayToXml(nativeObj);}/*** WeChat to be paid* @param nonceStr* @param orderDescribe* @param orderNo* @param price* @param timeStart* @param timeExpire* @return* @throws SDKRuntimeException*/public static String Createjsapipackage (String noncestr, string orderDescribe, chaîne orderNo, prix de chaîne, string timestart, string timeExpire, string openId) lève sdkruntimeException {hashmap <string, string> nativeoBj = new hashmap <string, string> (); nativeoBj.put ("appid", "open compte"); // le compte public idnative idnative (",", "open compte"); // le compte public Idnative " OpenID); // Public Account IdNativeObj.put ("MCH_ID", "Voir Email") // Numéro de marchand nativeoBj.put ("NONCE_STR", NONCESTR); // Random String NativeObj.put ("Body", OrderDescribe); // Product Description OrderNo); // Numéro de commande du commerçant (Global Unique) nativeoBj.put ("Total_Fee", Price); // Montant total (unité est cent, ne peut pas prendre de décimaux) nativeoBj.put ("SPBill_create_ip", "192.168.0.144"); // Terminal Ipnativeobj.put ("Time_Start", timestart); nativeoBj.put ("Time_Expire", TimeExpire) // Transaction Fin Time NativeoBj.put ("notify_url", personnaliséPropertyPlaceHolderConfigurer.getContex Type String Sign = getBizsign (nativeObj); nativeoBj.put ("signe", signe.touppercase ()); return Commonutil.ArraytOxMl (nativeoBJ);} / *** Ordre proche sur WeChat * @param Noncestr * @param OrderDescribe * @param OrderNo * @param Price * @param timestart * @param timeExpire * @param openID * @ return * @throws sdkruntimexception * / public static String CreatecloseOr SdkruntimeException {hashmap <string, string> nativeoBj = new hashmap <string, string> (); nativeoBj.put ("appid", "voir le compte public"); // le compte public idNativeObj.put ("mch_id", "voir le courriel"); // le nombre de Merchant NativeOpt ("Out_trade_No", OutTradeNo); (globalement unique) nativeoBj.put ("nonce_str", noncestr); // String random string Sign = getBizsign (nativeObj); nativeoBj.put ("signe", signe.touppercase ()); return Commonutil.arraytoxml (nativeoBJ);}} 4. Appelez l'interface de paiement WeChat
package com.pay.controller.weixin; import java.io.file; import java.io.fileinputStream; import java.security.keystore; import java.text.simpledateFormat; import java.util.date; javax.servlet.http.httpservletRequest; import javax.servlet.http.httpservletResponse; import net.sf.json.jsonarray; import net.sf.json.jsonobject; import org.apache.http.httpentity; importation; org.apache.http.client.methods.closeablehttprossence; import org.apache.http.client.methods.httpost; import org.apache.http.conn.ssl.sslconnections bancaires; import org.apache.http.entity.stringentity; import org.apache.http.impl.client.closeablehttpclient; import org.apache.http.imp.client.httpclients; org.dom4j.documenthelper; import org.dom4j.element; import org.dom4j.io.saxreader; import org.springframework.beans.factory.annotation.autowired; import org.springframework.http. org.springframework.web.bind.annotation.requestbody; import org.springframework.web.bind.annotation.requestmapping; Import org.springframework.web.bind.annotation.requestMethod; import org.springframework.web.bind.annotation.restController; import com.pay.bo.payhistants.import com.pay.constants.payhistorypaystatus; import com.pay.constants.payhistorypaytype; import com.pay.service.weixinpaysvice; import; com.pay.utils.weixin.clientCustomssl; import com.pay.utils.weixin.closeweixorDesweutils; import com.pay.utils.weixin.customalizedpropertyplaceholderconfigurer; @ restController @ requestMapping ("/ Pay") public weixinpayController {@Autowired WeixerServer WeixinPayService; Standard standard statique privé = 1662652800000L; / ** * Renvoie l'URL qui génère le code QR * @param demande * @param réponse * @return * / @RequestMapping (value = "/ getUrl", méthode = requestMethod.post) @ResponSestatus (httpstatus.ok) public GetUrl (httpServletResponse Response, @ request String body) {Try {jsonOBOB) JsonObject.fromObject (corps); PayHist Ph = null; // list <map <string, object >> td = weixinpayservice.getTrade (OrderNo); Date dt = new Date (); SimpledateFormat sdf = new SimpledateFormat ("yyyymmddhhmmss"); String nonCestr = sdf.format (dt) .toString (); Date maintenant = new Date (); String TradePayNo = JSONO.get ("OrderNo"). TOSTRING () + String.Format ("% 10D", Standardtime - Now.getTime ()). Substring (0, 10); System.out.println ("订单标号 OrderNo ======" + JSONO.get ("OrderNo"). ToString ()); System.out.println ("10 位随机数 ======" + String.Format ("% 10d", Standardtime - Now.getTime ()). Substring (0, 10)); String price = math.round (float.valueof (jsono.get ("prix"). ToString ()) * 100) + ""; Long TimeExpirestrold = dt.getTime (); Long timew = long.parselong (personnaliséPropertyPlaceHolderConfigurer.getContextProperty ("weixin.send2finish.overtime"). ToString ()); Long TimeExpirenew = TimeExpirestrold + timewew; Date dttimeExpire = new Date (timeExpirenew); SimpledateFormat dtsdf = new SimpledateFormat ("yyyymmddhhmms"); String timeExpire = dtsdf.format (dttimeExpire) .toString (); System.out.println ("NONCESTR ==" + NONCESTR); System.out.println ("OrderNo ==" + JSONO.get ("OrderNo"). ToString ()); System.out.println ("Price ==" + Price); System.out.println ("timestart ==" + noncestr); System.out.println ("TimeExpire ==" + TimeExpire); JSONObject Result = (JSONObject) SetUrl (noncestr, "Order", TradePayNo, Price, Noncestr, TimeExpire); if (result.get ("status"). toString (). equals ("Success")) {ph = new PayHist (); Ph.SetTradePayUrl (result.getString ("WeixinPayUrl")); // Ce champ est un lien de paiement. Vous pouvez générer un code QR pour scanner le code pour payer Ph.SetPayTradeno (JSONO.get ("OrderNo"). ToString ()); Ph.SetTradePayno (TradePayNo); Ph.SetPayStatus (PayHistoryPayStatus.wechat_pay_status_wait); Ph.SetPayType (PayHistoryPayType.wechat); Ph.SetAppkey (jsono.getString ("AppKey"). ToString ()); Ph.SetPayamount (prix); result.put ("PayTradeno", Ph.getPayTradeno ()); result.put ("TradePayno", Ph.getTradePayNo ()); result.put ("Paystatus", Ph.getPayStatus ()); result.put ("PayType", Ph.GetPayType ()); } Retour Résultat; } catch (exception e) {e.printStackTrace (); JsonObject result = new JSONObject (); result.put ("statut", "erreur"); result.put ("msg", e.getMessage ()); // return result.toString (); } return null; } public Object setUrl (String nonCest, chaîne OrderDescribe, String OrderNo, String Price, String timeStart, String timeExpire) {try {keystore keystore = keystore.getInstance ("pkcs12"); FileInputStream InsideRam = new FileInputStream (nouveau fichier (chemin absolu du certificat WeChat)); essayez {keystore.load (insideam, "Merchant id" .tocharArray ()); } enfin {enterStream.close (); } // Trust Own CA et tous les certificats auto-signés sslcontext sslcontext = sslcontext.custom (). LoadKeyMaterial (Keystore, <span style = "font-Family: Arial, Helvetica, Sans-Serif;"> Merchant id </span> .toCharArray ()). Build (); // Autoriser le protocole TLSV1 uniquement SSLConnectionSocketFactory SSLSF = new SSLConnectionSocketFactory (sslContext, new String [] {"tlsv1"}, null, sslconnections bancarfactory.allow_all_all CloseableHttpClient httpClient = httpClients.Custom () .SetsSLSocketFactory (sslsf) .build (); // httpget httpget = new // httpget ("https://api.mch.weixin.qq.com/secapi/pay/refund"); Httppost httppost = new httppost ("https://api.mch.weixin.qq.com/pay/UnifiedOrder"); String xml = clientCustomSSL.CreAreAnativePackage (NONCESTR, ORDANDDESCRIME, ORDERNO, Price, TimeStart, TimeExpire); try {stritNtity se = new stringEntity (xml); httppost.SetEntity (SE); System.out.println ("Exécution de la demande" + httppost.getRequestline ()); CloseableHttpResponse Responsentry = httpClient.Execute (httppost); try {httpentity entity = réponseTry.getEntity (); System.out.println ("----------------------------------------"); System.out.println (réponsentry.getStatusline ()); if (entité! = null) {System.out.println ("Longueur du contenu de la réponse:" + entité.getContentLength ()); / * BufferedReader BufferedReader = new BufferedReader (new inputStreamReader (entity.getContent ())); Texte de chaîne; while ((text = buttereDreader.readline ()))! = null) {System.out.println ("================" + texte); } * / SaxReader saxReader = new saxReader (); Document document = saxReader.read (entity.getContent ()); Element rootElt = document.getRootelement (); System.out.println ("Node racine:" + rootElt.getName ()); System.out.println ("===" + rootElt.ElementText ("result_code")); System.out.println ("===" + rootElt.ElementText ("return_msg")); String resultCode = rootElt.ElementText ("result_code"); JsonObject result = new JSONObject (); Document documentXml = documentHelper.parseText (xml); Élément rootEltxml = documentXml.getRootelement (); if (resultCode.equals ("Success")) {System.out.println ("================ PREPAY_ID =======================================================================================================================================================================================. System.out.println ("================ Sign ===================" + RootEltxml.ElementText ("Sign")); result.put ("weixinpayurl", rootElt.ElementText ("code_url")); result.put ("prepayId", rootElt.ElementText ("prepay_id")); result.put ("statut", "succès"); result.put ("msg", "succès"); } else {result.put ("status", "false"); result.put ("msg", rootElt.ElementText ("err_code_des")); } Retour Résultat; } EntityUtils.consume (entité); } enfin {réponsentry.close (); }} enfin {httpclient.close (); } return null; } catch (exception e) {e.printStackTrace (); JsonObject result = new JSONObject (); result.put ("statut", "erreur"); result.put ("msg", e.getMessage ()); Résultat de retour; }}} Package JAR HttpClient et package JSON JAR: Adresse de téléchargement.
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.