1. Vorbereitung
Lassen Sie uns zunächst über die Zahlung von Wechat beschweren. Es gibt mehrere Zahlungsmodelle, die es unterstützt, aber die offiziellen Dokumente sind besonders verstreut, und es gibt nicht einmal einige anständige Java-bezogene Demos. Ich habe noch nie eine WeChat -Zahlung geleistet. Ich war am Anfang wirklich fassungslos. Ich habe es endlich für zwei Tage durchgesetzt. Ich habe es hier unten geschrieben, um die zukünftigen Generationen zu genießen!
In Bezug auf die Vorbereitungsarbeiten finden Sie die offizielle Dokumentenadresse von "WeChat Scan QR -Code -Zahlungsmodell 2" hier https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_1 Sie können sich zuerst ansehen. In der Tat gibt es die folgenden Dinge, die Sie vorbereiten müssen:
Unter ihnen finden sich App_ID und app_secret auf der öffentlichen Plattform, während MCH_ID und API_KEY auf der Händlerplattform gefunden werden. Insbesondere muss API_Key auf der Händlerplattform eingestellt werden. Für "WeChat Scan -Code -Zahlungsmodus 2" (Zahlung und Rückruf) werden nur App_ID, mch_id und api_key verwendet, und es wird nichts anderes verwendet.
Ich werde nicht über die Entwicklungsumgebung sprechen. Egal, ob Sie SpringMVC, Struts2 oder Direct Serverlet sind, es ist fast gleich. Solange Sie sicherstellen können, dass die entsprechende Methode aufgerufen werden kann. In Bezug auf die Zitat von Jar-Paketen von Drittanbietern habe ich nur eine JDOM verwendet, die XML hier betreibt. Denken Sie daran, dass es die 1.* Version ist, nicht die neueste 2.* auf der offiziellen Website, und die beiden sind unvereinbar. Insbesondere ist es jdom-1.1.3.jar, das Abhängigkeitspaket jaxen-1.1.6.jar. Für diese beiden Pakete habe ich den in einigen Beispielen verwendeten HTTPClient nicht verwendet. Es fühlt sich unnötig an und das Abhängigkeitspaket ist sehr kompliziert. Natürlich bist du Maven, als ich es nicht gesagt habe.
2. Entwicklung und praktischer Kampf
1. Stellen Sie zunächst eine Verbindung zur WeChat -Schnittstelle her und erhalten Sie den QR -Code von WeChat Zahlung.
public String weixin_pay () löst Ausnahme aus {// Kontoinformationsstring appid = payconfigutil.app_id; // appid // String appsecret = payConfigutil.app_secret; // AppSecret String mch_id = payConfigutil.mch_id; // Business Number String key = payconfigutil.api_key; // KEY STRING CURTRIMTE = PAYCOMMONUTIL.getCurrime (); String sttrot = currtime.substring (8, currtime.length ()); String strrandom = paycommonutil.buildrandom (4) + ""; String nonce_str = sttime + strrandom; String order_price = 1; // Preis Hinweis: Die Preiseinheit ist in String body = "Goodssssss" unterteilt; // Produktname String out_trade_no = "11338"; // Bestellnummer // Erhalten Sie den initiierenden Computer -IP -String SPBILL_CREATE_IP = PAYCONFIGUTIL.CREATE_IP; // Callback Interface String notify_url = payconfigutil.notify_url; String Trade_type = "nativ"; SortEdMap <Objekt, Objekt> packageParams = new Treemap <Objekt, Objekt> (); packageParks.put ("Appid", Appid); packageParks.put ("mch_id", mch_id); packageParams.put ("nonce_str", nonce_str); packageParks.put ("Körper", Körper); packageParams.put ("out_trade_no", out_trade_no); packageParams.put ("Total_fee", order_price); packageParams.put ("SPBILL_CREATE_IP", SPBILL_CREATE_IP); packageParams.put ("benachrichtigen_url", notify_url); packageParams.put ("Trade_type", Trade_Type); String Sign = payCommonUtil.CreateSign ("UTF-8", PackageParams, Key); packageParks.put ("Zeichen", Zeichen); String RequestXML = PayCommonUtil.getRequestXML (PackageParams); System.out.println (RequestXML); String resxml = httputil.postData (payconfigutil.ufdoder_url, requestXml); Map map = xmlutil.doxmlParse (ResxML); // String return_code = (string) map.get ("return_code"); // String prepay_id = (String) map.get ("prepay_id"); String urlCode = (String) map.get ("code_url"); UrlCode zurückgeben; }Wenn nichts Unerwartetes passiert, erhalten wir eine Zahlungs -URL vom WeChat -Server, die wie Weixin: // WXPAY/BizPayurl? Pr = pixxxxx aussieht. Danach müssen wir einen QR -Code für diese URL generieren, und dann können wir mit unserem Mobiltelefon -WeChat den Code zum Zahlen scannen. Es gibt viele Möglichkeiten, QR -Codes zu generieren. Bitte nehmen Sie Ihre eigenen Bedürfnisse an. Ich biete hier eine Schnittstelle zur Erzeugung von Google QR -Code:
public static String qrfromgoogle (String Chl) löst Ausnahme aus {int widhtheight = 300; String ec_level = "l"; int margin = 0; Chl = Urlencode (Chl); String qrfromgoogle = "http://chart.apis.google.com/chart?chs=" + widhtheight + "x" + widhtheight + "& cht = qr & chld =" + ec_level + "|" + margin + "& chl =" + Chl; kehren qrfromgoogle zurück; } // Spezielle Charakterverarbeitung öffentliche statische String-Urlencode (String SRC) löst nicht supportedenCodingException aus {return urlencoder.encode (SRC, "UTF-8"). Ersetzen ("+", "%20"); } Der obige Code umfasst mehrere Werkzeugklassen: PayConfigilil, PayCommonutil, Httputil und XMLUTIL. Unter ihnen setzt PayConfigutil einige oben erwähnte Konfigurationen und Pfade. PayCommonutil beinhaltet verschiedene Methoden, um das aktuelle Ereignis zu erhalten, zufällige Zeichenfolgen zu erzeugen, Parametersignaturen zu erhalten und XML zu spleißen. Der Code ist wie folgt:
Paycommonutil im öffentlichen Klassen { /*** Ob die Signatur korrekt ist, ist die Regel: Sortieren nach Parametername AZ und Parameter, die auf leere Werte begegnen, beteiligen sich nicht an der Signatur. * @return boolean */ public static boolean istenpaysign (String charakteritätszerod, sortEdMap <Objekt, Objekt> PackageParams, String api_key) {StringBuffer SB = new StringBuffer (); Set ES = packageParams.EntrySet (); Iterator it = es.Iderator (); while (it.hasNext ()) {map.Entry -Eintrag = (Map.Entry) it.next (); String k = (String) Eintrag.getKey (); String v = (String) Eintrag.getValue (); if (! "sign" .equals (k) && null! = v &&! ". }} sb.append ("key =" + api_key); // Dateien Sie die summarische Zeichenfolge mySign = md5util.md5enCode (sb.toString (), charakteritätsgerichtet) .ToLowerCase (); String Tenpaysign = ((String) packageParams.get ("Zeichen")). TolowerCase (); //System.out.println(tenpaysign + "" + mySign); kehren Sie Tenpaysign.equals (mySign) zurück; } / ** * @Author * @date 2016-4-22 * @Description: Sign Signatur * @param CharakterCodierung * Codierungsformat * @param Parameter * Anforderungsparameter * @return * / public static String erstellen (String charakteritätszeichen, sortedMap <Objekt, Objekt> packagePaket, String api_key) {StringBufer SB = New StringBere (New String (); Set ES = packageParams.EntrySet (); Iterator it = es.Iderator (); while (it.hasNext ()) {map.Entry -Eintrag = (Map.Entry) it.next (); String k = (String) Eintrag.getKey (); String v = (String) Eintrag.getValue (); if (null! = v &&! ". }} sb.append ("key =" + api_key); String Sign = md5util.md5Encode (sb.toString (), charakteritätszündig) .toUppercase (); Rückgabezeichen; } / ** * @Author * @date 2016-4-22 * @Description: Die Anforderungsparameter in XML-Format-String konvertieren * @param Parameter * Anforderungsparameter * @return * / public static String getRequestXML (sortedMap <Objekt, Objekt> Parameter) {StringBufer sber sb = new Stringbuffer (); sb.Append ("<xml>"); Set ES = parameter.EntrySet (); Iterator it = es.Iderator (); while (it.hasNext ()) {map.Entry -Eintrag = (Map.Entry) it.next (); String k = (String) Eintrag.getKey (); String v = (String) Eintrag.getValue (); if ("atort" .EqualSignoreCase (k) || "Körper" .EqualSignoreCase (k) || "Zeichen" .EqualSignoreCase (k)) {sb.append ("<" + k + ">" + "<! [CDATA [" + V + "]> </" + k + ">"); } else {sb.append ("<" + k + ">" + v + "</" + k + ">"); }}} sb.append ("</xml>"); return sb.tostring (); } /*** Nehmen Sie eine zufällige positive Ganzzahl der angegebenen Längegröße heraus. * * @Param Länge * int die Länge der abgerufenen Zufallszahl einstellen. Länge weniger als 11 * @Return Int gibt die generierte Zufallszahl zurück. */ public static int buildrandom (int länge) {int num = 1; double random = math.random (); if (random <0,1) {random = random + 0,1; } für (int i = 0; i <länge; i ++) {num = num * 10; } return (int) ((zufällig * num)); } / ** * Die aktuelle Zeit yyyyymmddhhmms * * @return String * / public static String getCurrime () {Datum jetzt = new Date (); SimpleDateFormat Outformat = new SimpledateFormat ("yyyymmddhhmms"); String S = outformat.format (jetzt); Rückkehr s; }}Httputil und xmlutil sind wie folgt:
public class httputil {private static final log logger = logs.get (); private endgültige statische int Connect_timeout = 5000; // in Millionenseconds private endgültige statische String default_encoding = "utf-8"; public static String postdata (String urlstr, String -Daten) {Postdata zurückgeben (urlstr, data, null); } public static String postdata (String urlstr, String -Daten, String contentType) {bufferedReader reader = null; Versuchen Sie {url url = new url (urlstr); UrlConnection conn = url.openconnection (); conn.setDooutput (true); conn.setConnectTimeout (Connect_timeout); Conn.SetReadTimeout (Connect_timeout); if (contentType! = null) conn.setRequestProperty ("Content-Typ", ContentType); OutputStreamwriter writer = new OutputStreamWriter (Conn.GetOutputStream (), default_encoding); if (data == null) data = ""; writer.write (Daten); writer.flush (); writer.close (); Reader = New BufferedReader (neuer InputStreamReader (Conn.GetInputStream (), default_encoding)); StringBuilder sb = new StringBuilder (); String line = null; while ((line = reader.readline ())! = null) {sb.append (line); sb.Append ("/r/n"); } return sb.toString (); } catch (ioException e) {logger.Error ("Fehler mit" + urlstr + ":" + e.getMessage ()); } endlich {try {if (reader! = null) reader.close (); } catch (ioException e) {}} return null; }} public class xmlutil { /*** analysieren Sie XML und geben Sie das Element-Schlüsselwertpaar der ersten Ebene zurück. Wenn das Element der ersten Ebene Kinder hat, sind der Wert dieses Knotens die XML-Daten des untergeordneten Knotens. * @param strxml * @return * @throws jdomexception * @throws ioException */public static map doxmlParse (String Strxml) wirft jdomexception, ioException {strxml = strxml.replacefirst ("coding =/", "", "", "", "", "", "", "", ",", ",", ",", ",", ",", ",", ",", ",", ",", "/"/"/" ") aus. if (null == strxml || "" .Equals (strxml)) {return null; } Map m = new HashMap (); InputStream in = new BytearrayInputStream (strxml.getBytes ("utf-8")); Saxbuilder Builder = neuer Saxbuilder (); Document doc = builder.build (in); Element root = doc.getrootelement (); Listlist = root.getChildren (); Iterator it = list.Iterator (); while (it.hasnext ()) {Element e = (Element) it.Next (); String k = e.getName (); Zeichenfolge v = ""; List childhes = e.getChildren (); if (Kinder.Isempty ()) {v = e.getTextNormalize (); } else {v = xmlutil.getChildrentext (Kinder); } M.put (k, v); } // den Stream in.close () schließen; Rückkehr M; } / ** * Holen Sie sich den XML des untergeordneten Knotens * @param childhes * @return String * / public static String getChildrentext (Liste Kinder) {StringBuffer sb = new StringBuffer (); if (! Kinder.Isempty ()) {iterator it = children.iterator (); while (it.hasnext ()) {Element e = (Element) it.Next (); String name = e.getName (); String value = e.getTextNormalize (); Listlist = e.getChildren (); sb.append ("<" + name + ">"); if (! list.isempty ()) {sb.append (xmlutil.getChildrentext (list)); } SB.Append (Wert); sb.append ("</" + name + ">"); }} return sb.toString (); }} Natürlich gibt es auch eine MD5 Computing Tool -Klasse
public class md5util {private statische String bytearraytohexString (Byte B []) {StringBuffer resultsb = new StringBuffer (); für (int i = 0; i <B.Length; i ++) resultb.Append (bytetohexstring (b [i])); return resultesb.toString (); } private statische String -BytetohexString (Byte b) {int n = b; if (n <0) n += 256; int d1 = n / 16; int d2 = n % 16; HEXDIGITS [D1] + HexDigits [D2] zurückgeben; } public static String md5Code (String -Ursprung, String charSetName) {String resultStRing = null; try {resultStRing = new String (Ursprung); MessagedIGest MD = MessagedIGest.getInstance ("md5"); if (charSetName == null || "" .Eequals (charSetName)) resultString = bytearraytohexstring (md.Digest (resultStRing .getBytes ())); sonst resultString = bytearraytohexString (md.Digest (resultStRing .getBytes (charSetName))); } catch (Ausnahme) {} return resultString; } private statische endgültige Zeichenfolge hexDigits [] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"}; } 2. Zahlungsrückruf
Nach Abschluss der Zahlung sendet WeChat die entsprechenden Zahlungsergebnisse und Benutzerinformationen an die oben angegebene Rückrufadresse. Wir müssen die Verarbeitung erhalten und die Antwort zurückgeben. Wenn WeChat mit Hintergrundbenachrichtigungen die Antwort eines Händlers ohne Erfolg oder Zeitüberschreitung erhält und WeChat der Ansicht ist, dass die Benachrichtigung gescheitert ist, wird WeChat regelmäßig Benachrichtigungen durch bestimmte Strategien wieder initiieren, um die Erfolgsrate von Benachrichtigungen so weit wie möglich zu erhöhen, aber WeChat garantiert nicht, dass die Benachrichtigung im Ende erfolgreich sein wird. (Die Benachrichtigungsfrequenz ist 15/15/30/1800/1800/1800/1800/1800/1800/3600, Einheit: Sekunden)
In Bezug auf die Zahlungsrückrufschnittstelle müssen wir zunächst den Inhalt der Zahlungsergebnisbenachrichtigung unterschreiben und überprüfen und dann den entsprechenden Verarbeitungsvorgang basierend auf dem Zahlungsergebnis durchführen.
public void weixin_notify (httpServletRequest -Anforderung, httpServletResponse -Antwort) löst Ausnahme aus {// Lesen Sie die Parameter InputStream InputStream; StringBuffer sb = new StringBuffer (); inputStream = request.getInputStream (); String S; BufferedReader in = neuer BufferedReader (neuer InputStreamReader (InputStream, "UTF-8")); while ((s = in.readline ())! = null) {sb.Append (s); } in.close (); inputStream.close (); // XML in Map Map <String, String> m = New HashMap <String, String> () analysieren; m = xmlutil.doxmlParse (sb.toString ()); // Leere Einstellungen TREEMAP SortEdMap <Objekt, Objekt> packageParams = new Treemap <Objekt, Objekt> (); Iterator it = m.Keyset (). Iterator (); while (it.hasNext ()) {String parameter = (string) it.next (); String parameterervalue = M.Get (Parameter); Zeichenfolge v = ""; if (null! } packageParams.put (Parameter, v); } // Kontoinformationsstring Key = payConfigUtil.api_key; // Schlüssel logger.info (packageParams); // Bestimmen Sie, ob die Signatur korrekt ist, wenn (paycommonutil.istenpaysign ("utf-8", packageParams, Schlüssel) { // ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Startet // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- (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); /////////// 执行自己的业务逻辑 /////////////////// Logger.info ("Zahlung erfolgreich"); // WeChat benachrichtigen. Asynchrone Bestätigung ist erfolgreich. Muss es schreiben. Andernfalls wird der Hintergrund ständig benachrichtigt. Nach acht Mal wird berücksichtigt, dass die Transaktion fehlgeschlagen ist. resxml = "<xml>" + "<return_code> <! [CDATA [Erfolg]]> </return_code>" + "<return_msg> <! [CDATA [OK]]> </return_msg>" + "</xml>"; } else {logger.info ("Zahlung fehlgeschlagen, Fehlermeldung:" + packageParams.get ("err_code")); resxml = "<xml>" + "<return_code> <! [cdata [fail]]> </return_code>" + "<return_msg> <! [cdata [meldung ist leer]]> </return_msg>" + "</xml>"; } //---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- logger.info ("Benachrichtigungssignaturüberprüfung fehlgeschlagen"); }} Der Signaturüberprüfungsalgorithmus ähnelt dem Signaturergenerierungsalgorithmus und wird in der oben genannten PayKommonutil -Werkzeugklasse bereitgestellt.
3. später Geschichten
Ich bin der Meinung, dass die Zahlungserfahrung des Wechat -Scans ziemlich gut ist. Der einzige Nachteil ist, dass die entsprechenden Dokumente verstreut sind. Die offizielle Demo ist nicht in Java geschrieben. Ich hoffe, dass der offizielle WeChat -Beamte es in Zukunft nach und nach verbessern kann!
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.