Vor kurzem war ich in meiner Arbeit einigen Dingen über WeChat -Zahlungen ausgesetzt. Ich sah, dass die Demos, die ich gab, alle PHP -Versionen waren, und ich war wirklich nicht mit den WeChat -Zahlungsdokumenten zufrieden. Nachdem ich viele Fallstricke erlebt hatte, war ich untätig, um eine Zusammenfassung zu machen.
1. Vorbereitung
Um WeChat zu entwickeln, müssen Sie zunächst ein öffentliches Konto beantragen. Nachdem die Bewerbung erfolgreich ist, werden Sie per E -Mail an Sie gesendet. Das öffentliche Konto enthält Entwicklungsdokumente, notwendige Informationen während der Entwicklung und Datenabfrage zum Testen.
2. Werkzeuge
1. MD5 Verschlüsselungstoolklasse
Paket com.pay.utils.weixin; Import Java.Security.Messagedigest; öffentliche Klasse Md5util {öffentliche endgültige statische String MD5 (String S) {char hexDigits [] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', '}; try {byte [] btinput = s.getBytes (); // Erhalten Sie das MessagedIGest -Objekt des M -MessagedIGest -MessagedIGest -MessagedIGestS -Algorithmus -MessagedIGEST.getInstance ("Md5"); // Aktualisieren Sie die Digest mdinst.update (btinput); // den CipheText byte [] md = mdinst.Digest () erhalten; // den Chiffretext in eine HEX -String -Form int j = md.length konvertieren; char str [] = new char [j * 2]; int k = 0; für (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 (Ausnahme e) {e.printstacktrace (); null zurückkehren; }}}2. CommonUtil -Werkzeugklasse , zum Ersetzen des für WeChat erforderlichen XML. Die folgende Rückgabe neuer String (xml.toString (). GetBytes (), "ISO8859-1"); Ändern Sie UTF-8 in der Werkzeugklasse in ISO8859-1, andernfalls erscheint der chinesische Text in der WeChat-Order verstümmelt und kann nach der Änderung korrekt angezeigt werden.
Paket com.pay.utils.weixin; importieren java.io.unsupportedenCodingException; import Java.net.urlencoder; Import Java.util. "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456789"; String res = ""; für (int i = 0; i <länge; i ++) {random rd = new random (); res += chars.indexof (rd.nextint (chars.length () - 1)); } return res; } public static String createNonCestern () {String chars = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456789"; String res = ""; für (int i = 0; i <16; i ++) {random rd = new random (); res += chars.charat (rd.nextint (chars.length () - 1)); } return res; } public static String formatqueryparamap (HashMap <String, String> Parameter) löscht sdKruntimeException {String buff = ""; try {list <map.Entry <String, String >> Infoids = new ArrayList <map.Entry <String, String >> (parameter.EntrySet ()); Collectionss.sort (Infoids, neuer Komparator <map.Entry <String, String >> () {public int compare (map.Entry <String, String> O1, map.Entry <String, String> O2) {return (o1.getkey ()). ToString (). Vergleicheto (O2.GeteKey ();}}); für (int i = 0; i <infoids.SIZE (); i ++) {map.entry <String, String> item = infoids.get (i); if (item.getkey ()! }} if (buff.isempy () == false) {buff = buff.substring (0, buff.length () - 1); }} catch (Ausnahme E) {neue sdkruntimeexception (e.getMessage ()); } return buff; } public static String formatbizQueryparamap (HashMap <String, String> Paramap, boolean urlencode) sdkruntimeexception {String buff = ""; try {list <map.Entry <String, String >> Infoids = New ArrayList <map.Entry <String, String >> (paramap.EntrySet ()); Collectionss.sort (Infoids, neuer Komparator <map.Entry <String, String >> () {public int compare (map.Entry <String, String> O1, map.Entry <String, String> O2) {return (o1.getkey ()). ToString (). Vergleicheto (O2.GeteKey ();}}); für (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.isempy () == false) {buff = buff.substring (0, buff.length () - 1); }} catch (Ausnahme E) {neue 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 <Eintrag <String, String >> iter = arr.EntrySet (). Iterator (); while (iter.hasnext ()) {Eintrag <String, String> Eintrag = iter.next (); String key = Eintrag.getKey (); String val = Eintrag.getValue (); if (isnumeric (val)) {xml + = "<" + taste + ">" + val + "</" + taste + ">"; } else xml + = "<" + taste + "> <! [cdata [" + val + "]]> </" + taste + ">"; } xml += "</xml>"; try {return New String (xml.toString (). getBytes (), "ISO8859-1"); } catch (unportedenCodingException e) {// todo automatisch generierter Catch-Block e.printstacktrace (); } zurückkehren ""; }}3.ClientCustomSL -Werkzeugklasse , verwendet, um Zeichen zu generieren und WeChat -Bestellpaket com.pay.utils.weixin zu erstellen;
Java.util.ArrayList; import Java.util.Collections; import Java.util.comParator; import Java.util.hashMap; import Java.util.list; Import Java.util.map; */public class ClientCustomSL {public static String getBizSign (HashMap <String, String> bizobj) löst SdkruntimeException {HashMap <String, String> bizParameters = new Hashmap <String> () aus; Liste <map.Entry <String, String >> Infoids = new ArrayList <map.Entry <String, String >> (bizobj.entryset ()); System.out.println (Infoiden); Collectionss.sort (Infoids, neuer Komparator <map.Entry <String, String >> () {public int compare (map.Entry <String, String> o1, map.Entry <String, String> o2) {return (o1.getkey ()). ToString (). Vergleiche (O2.GeteKey ();}}); System.out.println (Infoiden); für (int i = 0; i <infoids.SIZE (); i ++) {map.entry <String, String> item = infoids.get (i); if (item.getkey ()! }} //bizparameters.put("Key "," 1234567812345678123456781234567812345671 "); String bizString = CommonUtil.Formatbizqueryparamap (BizParameters, False); BizString += "& Key = 123456781234567812345671"; System.out.println ("***************"); System.out.println (BizString); // return Sha1util.sha1 (BizString); return md5util.md5 (bizstring); } /** * WeChat create order* @param nonceStr * @param orderDescribe * @param orderNo * @param price * @param timeStart * @param timeExpire * @return * @throws SDKRuntimeException */ public static String CreateNativePackage(String nonceStr,String orderDescribe,String orderNo,String price,String timeStart,String timeExpire) throws SDKruntimeException {HashMap <String, String> natricObj = new HashMap <String, String> (); NativeObj.put ("Appid", "siehe öffentliches Konto"); // Public Account ID NativeObj.put ("mch_id", "siehe E -Mail"); // Händlernummer nativeObj.put ("nonce_str", noncestre); // zufällige Zeichenfolge natobj.put ("Körper", orderDescribe); // Produktbeschreibung nativem natives ("Attach", "TradeNo"); // Angehängte Daten nativesObj.put ("out_trade_no", orderno); // Händlerauftragsnummer (global eindeutig) native native owpj.put ("Total_fee", Preis); // Gesamtbetrag (Einheit ist Cent, kann nicht mit Dezimalpunkten eingenommen werden) NativeObj.put ("spbill_create_ip", "192.168.0.144"); // terminal ip nativObj.put ("time_start", timestart); // Transaktionsstartzeit nativesObj.put ("time_expire", timeExpire); // Transaktion Endzeit nativoBj.put ("benachrichtigen_url", CustomizedPropertyPlaPlaDaMpleConFigur. // Rückrufbenachrichtigungsadresse NativeObj.put ("Trade_Type", "Native"); // Transaktionstyp String Sign = getBizSign (nativ (nativ (nativ); NativeObj.put ("Sign", Sign.ToUpperCase ()); return CommonUtil.Arraytoxml (nativoBJ); } /*** WeChat order payment query* @param nonceStr* @param orderDescribe* @param orderNo* @param price* @param timeStart* @param timeExpire* @return* @throws SDKRuntimeException*/public static String SearchNativePackage(String transactionId,String outTradeNo,String nonceStr) throws SDKRuntimeException Oder // Public Account idnativeObj.put ("mch_id", "siehe E -Mail"); // Händlernummer nativeObj.put ("nonce_str", noncestre); // zufällige Zeichenfolge if (! Stringutils.isempty (transactionId)) {natrumObj.put ("transaction_id", transactionID); } if (! Stringutils.isempty (Outtradeno)) {nativObj.put ("out_trade_no", Outtradeno); // zufällige String} String sign = getBizSign (nativ (nativesObj); nativoBj.put ("Sign", sign.toUppercase ()); return CommonUtil.Arraytoxml (nativoBJ); /*** WeChat refund* @param outTradeNo* @param outRefundNo * @param totalFee* @param totalFee* @param refundFee* @return* @throws SDKRuntimeException*/public static String RefundNativePackage(String outTradeNo,String outRefundNo,String totalFee,String refundFee,String nonceStr) throws Sdkruntimeexception {HashMap <String, String> NOMISEBJ = NEW HashMap <String> (); NativeObj.put ("appid", "siehe public account"); // öffentliches Konto idnativeobj.put ("MCH_ID", "siehe E -Mail"); // Händler natrantobj.put ("nonce_strieren", noncestr); NativeObj.put ("out_trade_no", Outtradeno); // Händlerbestellnummer (global eindeutig) native ordnungsgemäß ("out_refund_no", OutfundNo); // Händlerrückerstattungsnummer (global eindeutig) NativeObj.put ("Total_fee", TotalFee, Total. Rückerstattung); // Rückerstattungsbetrag (Einheit in Cent, Dezimalpunkte nicht) nativ ("op_user_id", "mail"); String Sign = getBizSign (nativ (nativoBJ); NativeObj.put ("Sign", Sign.ToUpperCase ()); return CommonUtil.arrayToxml (nativeObj);}/*** WeChat, um bezahlt zu werden CreateJSAPIPACKAGE (String noncestern, String orderDescribe, String orderNo, String -Preis, String Timestart, String TimeExpire, String OpenID) löst sdkruntimeexception {HashMap <String> natives natives natobj = new Hashmap <String> (); NativeObj. OpenID); // öffentliches Konto idnativobj.put ("mch_id", "siehe E -Mail") // Händlernummer natives NativeObj.put ("nonce_str", noncester); // zufällige String nativ nativeobj.put ("body", orderDescribe); // Produktbeschreibung natives nativ ("Attade", "TradoNo"//////////////////// -Data naturedatheroBj. orderno); // Händlerauftragsnummer (global eindeutig) native NativeObj.put ("Total_fee", Preis); // Gesamtbetrag (Einheit ist Cent, Dezimalpunkte) NativeObj.put ("SPBILL_CREATE_IP", "192.168.0.144"); NativeObj.put ("time_expire", timeExpire) // Transaktion Endzeit nativesObj.put ("Notify_url", CustomizedPropertyPlaPleholderConFigurer.getContextProperty ("WXURL")+"/weixin_callback/wixincallback/initation/initaction"). "JSAPI"); // Transaktionstyp String sign = getBizSign (nativ (nativoBJ); nativoBj.put ("Zeichen", Sign.ToUpperCase ()); return CommonUtil.ArrayToXml(nativeObj);}/*** Close order on WeChat* @param nonceStr* @param orderDescribe* @param orderNo* @param price* @param timeStart* @param timeExpire* @param openId* @return* @throws SDKRuntimeException*/public static String CreateCloseOrder(String outTradeNo,String nonceStr) throws Sdkruntimeexception {HashMap <String, String> natives HashMap <String> (); nativeObj.put ("appid", "siehe das öffentliche Konto"); // public account idnativeobj.put ("mch_id", siehe die E -Mail "); // MerchanchanchantoBj.put (" Outtrader_No. (global eindeutig) NativeObj.put ("nonce_str", noncestern); // zufällige String String sign = getBizSign (nativ (nativ (nativ); nativoBj.put ("sign", sign.touppercase ()); return CommonUtil.Arraytoxml (nativeObj);}} 4. Rufen Sie die WeChat -Zahlungsschnittstelle an
Paket com.pay.controller.weixin; import java.io.file; import Java.io.fileinputStream; import Java.security.KeyStore Java.text.SimpledateFormat; Import Java.util.date; Import; javax.servlet.http.httpServletRequest; importieren javax.servlet.http.httpservletResponse; import net.sf.json.jsonArray; import net.sf.json.jsonObject; import org.apache.http.httpentity; org.apache.http.client.methods.cloSeableHttPesponse; import org.apache.http.client.methods.httppost; org.apache.http.entity.StringEntity; import org.apache.http.impl.client.cloSeableHttpclient; import org.apache.http.impl.client.httpclients; import org.apache.http.util.util.Utils; org.dom4j.documentHelper; import org.dom4j.element; import org.dom4j.io.saxreader; import org.springframework.beans.factory.annotation org.springframework.web.bind.annotation.Requestbody; Import org.springframework.web.bind.annotation.requestmapping; org.springframework.web.bind.annotation.restcontroller; import com.pay.bo.payhistants com.pay.utils.wexin.clientcustomSl; import com.pay.utils.weixin.closeweixinorderutils; import com.pay.utils.weixin.CustomizedPropertyPlaPlyolderConConFigurer; wixinpayservice; private statische Langzeitstandzeit = 1662652800000L; /** * Gibt die URL zurück, die den QR -Code generiert. JsonObject.fromObject (Körper); Payhist ph = null; // list <map <String, Objekt >> td = wixinpayService.getTrade (orderNo); Datum dt = neues Datum (); SimpleDateFormat SDF = new SimpledateFormat ("yyyymmddhhmms"); String noncest = sdf.format (dt) .ToString (); Datum jetzt = neues Datum (); 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 ("preis"). ToString ())*100)+""; Long timeExpirestrold = dt.getTime (); Long timenew = long.parselong (CustomizedPropertyPlaPleholderConFigurer.getContextProperty ("wixin.send2Finish.Overtime"). Tostring ()); Langzeitexpirew = timeExpirestrold+timenew; Datum dtimeexpire = neues Datum (TimeExpireNew); SimpleDateFormat dtsdf = new SimpledateFormat ("yyyymmddhhmms"); String timeExpire = dtsdf.format (dtTimeExpire) .ToString (); System.out.println ("noncest =="+noncestre); System.out.println ("orderno =="+jsono.get ("orderno"). ToString ()); System.out.println ("preis =="+preis); System.out.println ("Timestart =="+noncester); System.out.println ("TimeExpire =="+TimeExpire); JsonObject Ergebnis = (jsonObject) seturl (noncest, "order", treadpayno, preis, noncestern, timeExpire); if (result.get ("Status"). toString (). Equals ("Erfolg") {ph = new payhist (); Ph.SetTradepayurl (result.getString ("wixinpayurl"); // Dieses Feld ist ein Zahlungslink. Sie können einen QR -Code generieren, um den Code so zu scannen, um Ph.SetPaytradeno (jsono.get ("orderno") zu bezahlen. ToString ()); Ph.SetTradepayno (Tradepayno); Ph.SetPayStatus (payhistoryPayStatus.wechat_pay_status_wait); Ph.SetPayType (payhistoryPaytype.wechat); Ph.SetAppkey (jsono.getString ("appey"). toString ()); Ph.SetPayAmount (Preis); result.put ("paytradeno", ph.getPaytradeno ()); result.put ("Tradepayno", Ph.Gettradepayno ()); result.put ("payStatus", Ph.getPayStatus ()); result.put ("payType", ph.getPaytype ()); } Rückgabeergebnis; } catch (Ausnahme e) {e.printstacktrace (); JsonObject Ergebnis = new JSONObject (); result.put ("Status", "Fehler"); result.put ("msg", e.getMessage ()); // return result.toString (); } return null; } public Object seturl (String noncest, String orderDeCring, String orderNo, String -Preis, String timestart, String timeExpire) {try {keystore keystore = keystore.getInstance ("pkcs12"); FileInputStream Instream = new FileInputStream (neue Datei (Absolute Pfad des WeChat -Zertifikats)); try {keystore.load (instrenm, "Merchant id" .toCharArray ()); } endlich {Enterstream.close (); } // vertrauen Sie eigene CA und alle selbstsignierten Zertifikate sslcontext sslcontext = sslcontexts.custom (). Loadkeymaterial (Keystore, <span style = "font-family: arial, helvetica, sans-serif; // TLSV1 -Protokoll nur sslConnectionsOCKETFACTORY SSLSF = NEU SSLCONNEctionsOCKETFACTORY (SSLCONTEXT, NEW STRING [] {"TLSV1"}, NULL, SSLCONNECTIONSOCKETFACTORY.All_Hostname_verifier); 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.qqq.com/pay/unifiedorder"); String xml = clientCustomSL.CreateNativePackage (Noncest, OrderDescribe, Orderno, Preis, Zeitstart, TimeExpire); try {strackentity se = new strietentity (xml); httppost.setentity (SE); System.out.println ("Ausführung von Anforderungen" + httppost.getRequestline ()); CloseableHttPresponse ResponseEntry = httpclient.execute (httppost); try {httpentity entity = reactionEntry.getEntity (); System.out.println ("------------------------------------"); System.out.println (responseEntry.getStatusline ()); if (entity! /* BufferedReader bufferedReader = new bufferedReader (neuer InputStreamReader (entity.getContent ()); Stringtext; while ((text = bufferedReader.readline ())! = null) {System.out.println ("================"+text); }*/ SAXReader Saxreader = new Saxreader (); Document document = saxreader.read (entity.getContent ()); Element rootelt = document.getrootelement (); System.out.println ("Root -Knoten:" + rootelt.getName ()); System.out.println ("==="+rootelt.elementText ("result_code")); System.out.println ("==="+rootelt.elementText ("return_msg")); String resultcode = rootelt.elementText ("result_code"); JsonObject Ergebnis = new JSONObject (); Document documentXml = documentHelper.ParsetExt (xml); Element rooteltxml = documentXml.getrootelement (); if (resultcode.equals ("Erfolg")) {System.out.println ("==================================================="+ Rootelt.elementtext ("prepay_id"); System.out.println ("================= Sign ==================="+ rooteltxml.elementText ("Sign")); result.put ("wixinpayurl", rootelt.elementText ("code_url")); result.put ("prepayid", rootelt.elementText ("prepay_id")); result.put ("Status", "Erfolg"); result.put ("msg", "Erfolg"); } else {result.put ("Status", "false"); result.put ("msg", rootelt.elementText ("err_code_des")); } Rückgabeergebnis; } EntityUtils.consume (Entity); } endlich {reaktionEntry.close (); }} schließlich {httpclient.close (); } return null; } catch (Ausnahme e) {e.printstacktrace (); JsonObject Ergebnis = new JSONObject (); result.put ("Status", "Fehler"); result.put ("msg", e.getMessage ()); Rückgabeergebnis; }}} Httpclient JAR -Paket und JSON JAR -Paket: Download -Adresse.
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.