เมื่อเร็ว ๆ นี้ฉันได้สัมผัสกับบางสิ่งเกี่ยวกับการชำระเงิน WeChat ในงานของฉัน ฉันเห็นว่าการสาธิตที่ฉันให้นั้นเป็นรุ่น PHP ทั้งหมดและฉันก็ไม่พอใจกับเอกสารการชำระเงิน WeChat หลังจากประสบข้อผิดพลาดมากมายฉันก็ไม่ได้ใช้งานเพื่อสรุป
1. การเตรียม
ในการพัฒนา WeChat คุณต้องสมัครบัญชีสาธารณะก่อน หลังจากที่แอปพลิเคชันสำเร็จคุณจะถูกส่งถึงคุณทางอีเมล บัญชีสาธารณะมีเอกสารการพัฒนาข้อมูลที่จำเป็นในระหว่างการพัฒนาและแบบสอบถามข้อมูลสำหรับการทดสอบ
2. เครื่องมือ
1. MD5 คลาสเครื่องมือเข้ารหัส
แพ็คเกจ com.pay.utils.weixin; นำเข้า java.security.messagedigest; คลาสสาธารณะ MD5UTIL {Public Final String String MD5 (String S) {Char hexdigits [] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; ลอง {byte [] btinput = s.getBytes (); // รับวัตถุที่ส่งข้อความของอัลกอริทึม MD5 Digest MESAGEDIGEST MDINST = MessageDigest.getInstance ("MD5"); // อัปเดต digest mdinst.update (btinput); // รับ ciphertext byte [] md = mdinst.digest (); // แปลง ciphertext เป็นรูปแบบสตริง hex int j = md.length; char str [] = ถ่านใหม่ [J * 2]; int k = 0; สำหรับ (int i = 0; i <j; i ++) {byte byte0 = md [i]; str [k ++] = hexdigits [byte0 >>> 4 & 0xf]; str [k ++] = hexdigits [byte0 & 0xf]; } ส่งคืนสตริงใหม่ (str); } catch (exception e) {e.printstacktrace (); คืนค่า null; -2. คลาสเครื่องมือ Commonutil ใช้เพื่อแทนที่ XML ที่จำเป็นสำหรับ WeChat ผลตอบแทนต่อไปนี้สตริงใหม่ (xml.toString (). getBytes (), "iso8859-1"); เปลี่ยน UTF-8 ในคลาสเครื่องมือเป็น ISO8859-1 มิฉะนั้นข้อความภาษาจีนในคำสั่ง WeChat จะปรากฏเป็นอ่านไม่ออกและสามารถแสดงได้อย่างถูกต้องหลังจากการเปลี่ยนแปลง
แพ็คเกจ com.pay.utils.weixin; นำเข้า java.io.unsupportencodingexception; นำเข้า java.net.urlencoder; นำเข้า java.util.*; นำเข้า java.util.map.entry; คลาสสาธารณะ Commonutil "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456789"; สตริง res = ""; สำหรับ (int i = 0; i <length; i ++) {random rd = new random (); res += chars.indexof (rd.nextint (chars.length () - 1)); } return res; } สตริงคงที่ public String createnonCestr () {string chars = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456789"; สตริง res = ""; สำหรับ (int i = 0; i <16; i ++) {random rd = new random (); res += chars.charat (rd.nextint (chars.length () - 1)); } return res; } public String String formatQueryParamap (HashMap <String, String> พารามิเตอร์) โยน sdkruntimeException {String buff = ""; ลอง {list <map.entry <string, string >> infoids = new ArrayList <map.entry <string, string >> (parameters.entryset ()); collections.sort (infoids, ตัวเปรียบเทียบใหม่ <map.entry <string, string >> () {public int compare (map.entry <string, string> o1, map.entry <string, string> o2) {return (o1.getKey ()). toString () สำหรับ (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) {โยน sdkruntimeException ใหม่ (e.getMessage ()); } return buff; } String สาธารณะ String formatBizQueryParamap (HashMap <String, String> Paramap, Boolean urlencode) พ่น sdkruntimeException {string buff = ""; ลอง {list <map.entry <string, string >> infoids = new ArrayList <map.entry <string, string >> (paramap.entryset ()); collections.sort (infoids, ตัวเปรียบเทียบใหม่ <map.entry <string, string >> () {public int compare (map.entry <string, string> o1, map.entry <string, string> o2) {return (o1.getKey ()). toString () สำหรับ (int i = 0; i <infoids.size (); i ++) {map.entry <string, string> item = infoids.get (i); //system.out.println (item.getKey ()); if (item.getKey ()! = "") {สตริงคีย์ = 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) {โยน sdkruntimeException ใหม่ (e.getMessage ()); } return buff; } บูลีนคงที่สาธารณะ isnumeric (str str) {if (str.matches ("// d *")) {return true; } else {return false; }} สตริงคงที่สาธารณะ arraytoxml (hashmap <string, string> arr) {string xml = "<xml>"; Iterator <entry <string, string >> iter = arr.entryset (). iterator (); ในขณะที่ (iter.hasnext ()) {entry <string, string> entry = iter.next (); สตริงคีย์ = entry.getKey (); String val = entry.getValue (); if (isnumeric (val)) {xml + = "<" + คีย์ + ">" + val + "</" + คีย์ + ">"; } else xml + = "<" + key + "> <! [cdata [" + val + "]> </" + คีย์ + ">"; } xml += "</xml>"; ลอง {ส่งคืนสตริงใหม่ (xml.toString (). getBytes (), "iso8859-1"); } catch (unsupportencodingexception e) {// toDo บล็อก catch ที่สร้างโดยอัตโนมัติ E.PrintStackTrace (); } กลับ ""; -3. ClientCustomsSL คลาสเครื่องมือ ใช้เพื่อสร้างสัญญาณและสร้างแพ็คเกจคำสั่งซื้อ weChat com.pay.utils.weixin;
นำเข้า java.util.arraylist; นำเข้า java.util.collections; นำเข้า java.util.comparator; นำเข้า java.util.hashmap; นำเข้า java.util.list; นำเข้า java.util.map; นำเข้า org.springframework */คลาสสาธารณะ clientCustomsSl {สตริงคงที่ public String getBizSign (HASHMAP <String, String> Bizobj) พ่น SDKRuntimeException {HashMap <String, String> BizParameters = HASHMAP ใหม่ <String, String> (); รายการ <map.entry <string, string >> infoids = new ArrayList <map.entry <string, string >> (bizobj.entryset ()); System.out.println (Infoids); collections.sort (infoids, ตัวเปรียบเทียบใหม่ <map.entry <string, string >> () {public int compare (map.entry <string, string> o1, map.entry <string, string> o2) {return (o1.getKey ()). System.out.println (Infoids); สำหรับ (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); // return sha1util.sha1 (bizstring); ส่งคืน md5util.md5 (bizstring); } / ** * weChat สร้างคำสั่ง * @param noncestr * @param orderdescribe * @param orderno * @param ราคา * @param timestart * @param timeexpire * @return * @throws sdkruntimeexception * / สตริงสตริง sdkruntimeException {hashmap <string, string> nativeObj = new hashmap <string, string> (); NativeObj.put ("appid", "ดูบัญชีสาธารณะ"); // ID บัญชีสาธารณะ NativeObj.put ("MCH_ID", "ดูอีเมล"); // หมายเลขผู้ค้า NativeObj.put ("nonce_str", noncestr); // สุ่มสตริง nativeObj.put ("ร่างกาย", orderDescribe); // คำอธิบายผลิตภัณฑ์ nativeObj.put ("แนบ", "tradeno"); // data ที่แนบมา NativeObj.put ("out_trade_no", orderno); // หมายเลขคำสั่งซื้อของผู้ค้า (ไม่ซ้ำกันทั่วโลก) NativeObj.put ("Total_fee", ราคา); // จำนวนเงินทั้งหมด (หน่วยเป็นเซ็นต์ไม่สามารถใช้กับทศนิยมได้) NativeObj.put ("spbill_create_ip", "192.168.0.144"); // เทอร์มินัล IP NativeObj.put ("time_start", timestart); // การทำธุรกรรมเวลาเริ่มต้น NativeObj.put ("time_expire", timeExpire); // การทำธุรกรรมสิ้นสุดเวลา NativeObj.put ("Notify_url", CustomizedPropertyPlaceHolderConfigurer.getContextProperty ("WXURL")+"/Weixin_Callback/Weixincallback/init.action"); // ที่อยู่การแจ้งเตือนการโทรกลับ nativeObj.put ("trade_type", "native"); // ประเภทการทำธุรกรรม String Sign = getBizSign (nativeObj); nativeObj.put ("sign", sign.touppercase ()); return Commonutil.arraytoxml (NativeObj); } /*** แบบสอบถามการชำระเงิน wechat คำสั่งซื้อ* @param noncestr* @param orderdescribe* @param orderno* @param ราคา* @param timestart* @param timeexpire* @return* @throws sdkruntimexception* {hashmap <string, string> nativeObj = new hashmap <string, string> (); nativeObj.put ("appid", "ดูบัญชีสาธารณะ"); // บัญชีสาธารณะ idnativeObj.put ("MCH_ID", "ดูอีเมล"); // หมายเลขผู้ค้า NativeObj.put ("nonce_str", noncestr); // สุ่มสตริงถ้า (! stringutils.isempty (transactionId)) {nativeObj.put ("transaction_id", transactionId); } if (! stringutils.isempty (OuttRadeno)) {nativeObj.put ("out_trade_no", outtradeno); // สุ่มสตริง} String sign = getBizSign (nativeObj); nativeObj.put ("sign", sign.touppercase ()); return Commonutil.arraytoxml (NativeObj); /*** การคืนเงิน wechat* @param outtradeno* @param outrefundno* @param totalfee* @param totalfee* @param refundefee* @return* @throws sdkruntimeException*/สตริง refundfee, สตริง outrefundno, สตริง sdkruntimeException {hashmap <string, string> nativeObj = new hashmap <string, string> (); nativeObj.put ("appid", "ดูบัญชีสาธารณะ"); // บัญชีสาธารณะ idnativeObj.put ("mch_id", "ดูอีเมล"); NativeObj.put ("out_trade_no", outtradeno); // หมายเลขคำสั่งซื้อของผู้ค้า (ไม่ซ้ำกันทั่วโลก) NativeObj.put ("out_refund_no", outrefundno); // หมายเลขคำสั่งซื้อคืนของผู้ค้า refundfee); // จำนวนเงินคืน (หน่วยเป็นเซ็นต์ไม่สามารถใช้ทศนิยมได้) NativeObj.put ("OP_USER_ID", "Mail"); String sign = getBizSign (nativeObj); NativeObj.put ("Sign", Sign.touppercase ()); return Commonutil.arraytoxml (NativeObj);}/*** wechat ที่จะจ่าย* @param noncestr* @param orderdescribe* @param ordno* @param ราคา* @param timestart* @param createjsapipapackage (สตริง noncestr, string orderdescribe, สตริง orderno, ราคาสตริง, สตริง timestart, สตริง timexpire, สตริง openId) พ่น sdkruntimeexception {hashmap <สตริงสตริง> nativeObj = new hashmap <string, string> () openId); // บัญชีสาธารณะ idnativeObj.put ("mch_id", "ดูอีเมล") // หมายเลขผู้ค้า nativeObj.put ("nonce_str", noncestr); // rand string nativeObj.put ("body", orderdescribe); // คำอธิบายผลิตภัณฑ์ nativebj.put ("แนบ" OrderNo); // หมายเลขคำสั่งซื้อของผู้ค้า (ไม่ซ้ำกันทั่วโลก) NativeObj.put ("total_fee", ราคา); // จำนวนรวม (หน่วยเป็นเซ็นต์ไม่สามารถใช้ทศนิยมได้) NativeObj.put ("spbill_create_ip", "192.168.0.144"); NativeObj.put ("time_expire", timeExpire) // การทำธุรกรรมสิ้นสุดเวลา NativeObj.put ("Notify_url", CustomizedPropertyplaceHolderConfigurer.getContextProperty ("WXURL")+"/Weixin_Callback/Weixincallback/Init.Action" "jsapi"); // ประเภทการทำธุรกรรม String sign = getBizSign (nativeObj); nativeObj.put ("sign", sign.touppercase ()); return Commonutil.arraytoxml (nativeObj);}/*** คำสั่งปิดเกี่ยวกับ weChat* @param noncestr* @param orderdescribe* @param orderno* @param ราคา* @param timestart* @param timeexpire* @param openid* @return* @throws sdkruntimeex sdkruntimeException {hashmap <string, string> nativeObj = new hashmap <string, string> (); nativeObj.put ("appid", "ดูบัญชีสาธารณะ"); // บัญชีสาธารณะ idnativeObj.put ("mch_id", "ดูอีเมล"); (ไม่ซ้ำกันทั่วโลก) NativeObj.put ("nonce_str", noncestr); // sign string string sign = getBizSign (nativeObj); nativeObj.put ("sign", sign.touppercase ()); return Commonutil.arraytoxml (nativeObj);}} 4. โทรหาอินเทอร์เฟซการชำระเงิน WeChat
แพ็คเกจ com.pay.controller.weixin; นำเข้า java.io.file; นำเข้า java.io.fileinputstream; นำเข้า java.security.keystore; นำเข้า java.text.simpledateFormat; นำเข้า Java.util.date; javax.servlet.http.httpservletrequest; นำเข้า Javax.servlet.http.httpservletResponse; นำเข้า net.sf.json.jsonarray; นำเข้า net.sf.json.jsonobject; org.apache.http.client.methods.closeablehttpresponse; นำเข้า org.apache.http.client.methods.httppost; นำเข้า org.apache.http.conn.ssl.sslconnectionsocketatory; org.apache.http.entity.stringentity; นำเข้า org.apache.http.impl.client.closeablehttpClient; นำเข้า org.apache.http.impl.client.httpclients; นำเข้า org.http.util.entityutils; org.dom4j.documenthelper; นำเข้า org.dom4j.element; นำเข้า org.dom4j.io.saxreader; นำเข้า org.springframework.beans.factory.annotation.autowired; นำเข้า org.springframework.http.httpstatus; org.springframework.web.bind.annotation.requestbody; นำเข้า org.springframework.web.bind.annotation.requestmapping; นำเข้า org.springframework.web.bind.annotation.RequestMethod; org.springframework.web.bind.annotation.restcontroller; นำเข้า com.pay.bo.payhistants.import com.pay.constants.payhistorypaystatus; นำเข้า com.pay.constants.payhistorypaytype; com.pay.utils.weixin.clientcustomssl; นำเข้า com.pay.utils.weixin.closeweixinorderutils; นำเข้า com.pay.utils.weixin.customizedpropertyplaceholderconfigurer;@restcontroller@requestmapping ( Weixinpayservice; มาตรฐานคงที่แบบคงที่ส่วนตัว = 1662652800000L; /** * ส่งคืน URL ที่สร้างรหัส QR * @param Request * @param Response * @return */@requestmapping (value = "/geturl", method = requestmethod.post) @responsestatus (httpstatus.ok) JsonObject.FromObject (ร่างกาย); payhist pH = null; // list <map <string, object >> td = weixinpayservice.getTrade (orderno); วันที่ dt = วันที่ใหม่ (); SimpledateFormat SDF = ใหม่ SimpleDateFormat ("yyyymmddhhmmss"); สตริง noncestr = sdf.format (dt) .toString (); วันที่ตอนนี้ = วันที่ใหม่ (); 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)); ราคาสตริง = math.round (float.valueof (jsono.get ("ราคา"). toString ())*100)+""; Long TimeExpirestrold = dt.getTime (); Long Timenew = long.parselong (กำหนดเอง propertyplaceholderconfigurer.getContextProperty ("weixin.send2finish.overtime"). ToString ()); TimeExpiRenew ยาว = timeExpirestrold+timenew; วันที่ dttimeExpire = วันที่ใหม่ (timeExpirenew); SimpledateFormat dtsdf = ใหม่ simpledateFormat ("yyyymmddhhmmss"); String timeExpire = dtsdf.format (dttimeExpire) .toString (); System.out.println ("noncestr =="+noncestr); System.out.println ("orderno =="+jsono.get ("orderno"). toString ()); System.out.println ("ราคา =="+ราคา); System.out.println ("timestart =="+noncestr); System.out.println ("timeExpire =="+timeExpire); jsonObject result = (jsonObject) seturl (noncestr, "คำสั่ง", tradepayno, ราคา, noncest, timeExpire); if (result.get ("สถานะ"). toString (). เท่ากับ ("ความสำเร็จ")) {pH = new PayHist (); Ph.SetTradepayurl (result.getString ("Weixinpayurl")); // ฟิลด์นี้เป็นลิงค์การชำระเงิน คุณสามารถสร้างรหัส QR เพื่อสแกนรหัสเพื่อจ่ายค่า 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 (ราคา); result.put ("paytradeno", ph.getpaytradeno ()); result.put ("tradepayno", ph.gettradepayno ()); result.put ("paystatus", ph.getpaystatus ()); result.put ("paytype", ph.getpaytype ()); } ผลตอบแทนผลลัพธ์; } catch (exception e) {e.printstacktrace (); jsonObject result = new JSonObject (); result.put ("สถานะ", "ข้อผิดพลาด"); result.put ("msg", e.getMessage ()); // return result.toString (); } return null; } วัตถุสาธารณะ seturl (สตริง noncestr, string orderdescribe, string orderno, ราคาสตริง, สตริง timestart, สตริง timeExpire) {ลอง {keystore keystore = keystore.getInstance ("PKCS12"); FileInputStream Instream = ใหม่ FileInputStream (ไฟล์ใหม่ (เส้นทางสัมบูรณ์ของใบรับรอง WeChat)); ลอง {keystore.load (stream, "Merchant ID" .toChararray ()); } ในที่สุด {enterstream.close (); } // Trust CA ของตัวเองและ Certs SylContext sslContext = sslContexts.custom (). loadKeyMaterial (Keystore, <span style = "Font-Family: Arial, Helvetica, sans-serif;" // อนุญาตให้ใช้โปรโตคอล TLSV1 เฉพาะ sslConnectionsOcketFactory sslsf = ใหม่ sslconnectionsocketFactory (sslContext, สตริงใหม่ [] {"tlsv1"}, null, sslconnectionsocketfactory.allow_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.qq.com/pay/unifiedOrder"); String xml = clientcustomssl.createnativePackage (noncestr, orderdescribe, orderno, ราคา, timestart, timeExpire); ลอง {stringEntity se = new StringEntity (XML); httppost.setEntity (SE); System.out.println ("การดำเนินการคำขอ" + httppost.getRequestline ()); closeblehtpResponse ResponseEntry = httpClient.execute (HTTPPOST); ลอง {httpentity entity = responseentry.getEntity (); System.out.println ("----------------------------------------"); System.out.println (ResponseEntry.getStatusline ()); if (เอนทิตี! = null) {system.out.println ("ความยาวเนื้อหาตอบกลับ:" + entity.getContentLength ()); /* bufferedReader bufferedReader = ใหม่ bufferedReader (ใหม่ inputStreamReader (entity.getContent ())); ข้อความสตริง; ในขณะที่ ((text = bufferedreader.readline ()))! = null) {system.out.println ("===================="+ข้อความ); }*/ saxReader saxReader = new SaxReader (); เอกสารเอกสาร = saxReader.read (entity.getContent ()); Element Rootelt = document.getRootElement (); System.out.println ("รูทโหนด:" + 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 (); Documentxml = documenthelper.parsetext (XML); Element RootelTxml = documentxml.getRootelement (); if (resultcode.equals ("ความสำเร็จ")) {system.out.println ("========================================================================================"+ rootelt.elementText ("prepay_id")); System.out.println ("=================== เครื่องหมาย ======================"+ rooteltxml.elementText ("sign")); result.put ("weixinpayurl", rootelt.elementText ("code_url")); result.put ("prepayid", rootelt.elementText ("prepay_id")); result.put ("สถานะ", "ความสำเร็จ"); result.put ("msg", "ความสำเร็จ"); } else {result.put ("สถานะ", "false"); result.put ("msg", rootelt.elementText ("err_code_des")); } ผลตอบแทนผลลัพธ์; } entityUtils.consume (เอนทิตี); } ในที่สุด {ResponseEntry.close (); }} ในที่สุด {httpClient.close (); } return null; } catch (exception e) {e.printstacktrace (); jsonObject result = new JSonObject (); result.put ("สถานะ", "ข้อผิดพลาด"); result.put ("msg", e.getMessage ()); ผลการกลับมา; }}} แพ็คเกจ HttpClient Jar และ JSON JAR แพ็คเกจ: ดาวน์โหลดที่อยู่
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น