1. Persiapan
Banyak orang bertanya tentang pengembangan model satu, jadi saya mempostingnya di sini hanya untuk referensi. Saya telah menjelaskan perbedaan antara mode satu dan mode dua kali. Tidak lebih dari kode mode QR satu adalah untuk produk, dan kode mode QR dua adalah untuk pesanan. Saya tidak perlu berbicara tentang detail spesifik lainnya. Anda dapat pergi ke dokumen resmi untuk melihat dokumen sendiri, dan kemudian memilih mode satu atau mode dua dan itu tergantung pada bisnis Anda.
1.1. Parameter konfigurasi terkait
Keempat hal sebelumnya, App_id dan App_secret dapat ditemukan di platform publik, sementara MCH_ID dan API_Key ditemukan di platform pedagang, terutama API_Key harus diatur pada platform pedagang. Hal ini terkait dengan kebenaran verifikasi parameter, sehingga harus diatur dengan benar. Model pembayaran kode QR 1 sebenarnya mirip dengan model pembayaran kode QR 2. Faktanya, hanya menggunakan APP_ID, MCH_ID dan API_KEY, dan tidak menggunakan yang lain. Alamat dokumen resmi mode satu adalah di sini: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4
1.2. Konsep terkait
Di sini saya ingin memperbaiki konsep terlebih dahulu. Selama pengembangan model kedua, saya menyebutkan konsep seperti "alamat panggilan balik pembayaran". Fungsinya adalah bahwa setelah pelanggan memindai dan menyelesaikan pembayaran, server WeChat perlu mengakses alamat yang disediakan oleh kami dan mengirimkan hasil pembayaran kepada kami sehingga kami dapat memverifikasi pesanan untuk pengiriman. Ini adalah konsep dan nama yang relatif umum untuk alat pembayaran lainnya. Namun, kemudian saya melihat -lihat dokumen di situs web resmi WeChat dan menemukan bahwa dalam pengembangan pertama model, mereka menyebut ini "URL pemberitahuan asinkron" alih -alih "alamat panggilan balik pembayaran", tetapi pada dasarnya ini mengacu pada makna yang sama. Tapi mengapa saya menyebutkan hal ini di sini? Ini karena dalam mode satu, sebenarnya ada apa yang disebut "panggilan balik pembayaran" yang disebut "URL panggilan balik pembayaran kode pemindaian". Hal ini berbeda dari "URL pemberitahuan asinkron" di atas. Dapat dengan mudah dipahami bahwa itu adalah antarmuka di server kami untuk membantu menyelesaikan pesanan. Pengembangan mode One membutuhkan kerja sama dari dua antarmuka "Pindai kode QR untuk membayar URL callback" dan "URL pemberitahuan asinkron", sehingga semua orang harus membedakannya di sini.
"URL Pemberitahuan Async" diatur saat memanggil antarmuka tunggal yang terpadu. Ini dapat diatur secara dinamis, selama antarmuka ini menerima parameter respons parameter sesuai dengan aturan yang relevan. "Pindai kode QR untuk membayar URL callback" relatif tetap. Itu ditetapkan pada platform publik WeChat. Dibutuhkan sekitar 10 menit untuk berlaku setelah pengaturan. Setelah masuk ke platform publik WeChat, pilih WeChat Pay dan Anda dapat menemukannya di bawah tab Konfigurasi Pengembangan:
Di sini kita perlu mengatur alamat server kami sendiri (dan mengatakan alamat jaringan publik lagi, sehingga server WeChat dapat menemukan Anda).
1.3. Lingkungan pengembangan
Saya menggunakan Servlet 3.0 paling dasar sebagai lingkungan sampel di sini. Mengenai referensi paket toples pihak ketiga, dibandingkan dengan pengembangan Model 2, di samping menggunakan Operasi XML JDOM, ada paket kode QR Google Zxing dan paket log4J. Seperti yang ditunjukkan pada gambar di bawah ini:
Untuk memfasilitasi debugging, disarankan agar Anda pertama kali menurunkan penyesuaian di lingkungan ini sebelum mentransplantasikannya ke proyek nyata.
2. Pengembangan dan pertempuran praktis
Sebelum memulai, saya menyarankan agar Anda pergi ke dokumen resmi untuk memperhatikan grafik waktu. Setelah memahami bagan waktu, kode menulis bukanlah tugas yang sulit. Tentu saja, jika Anda tidak dapat memahami gambarnya, Anda juga dapat mencoba memahaminya secara kombinasi dengan kode saya berikut.
2.1. Pembuatan kode QR
Pertama -tama, ada kode QR. Konten dalam kode QR adalah tautan, dan formulirnya adalah:
weixin: // wxpay/bizpayurl? Sign = xxxxx & appid = xxxxx & mch_id = xxxxx & product_id = xxxxx & time_stamp = xxxxx & nonce_str = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Untuk detailnya, Anda dapat merujuk ke mode dokumen resmi untuk menghasilkan aturan kode QR. Selanjutnya kita perlu menghasilkan kode QR untuk tautan ini. Saya menggunakan Google Zxing di sini untuk menghasilkan kode QR.
paket com.wqy; impor java.io.ioException; impor java.io.outputStream; impor java.util.hashmap; impor java.util.iterator; impor java.util.map; impor java.util.set; impor java.util.sortedmap; impor java.util.treemap; impor javax.servlet.servletException; impor javax.servlet.annotation.webservlet; impor javax.servlet.http.httpservlet; impor javax.servlet.http.httpservletRequest; impor javax.servlet.http.httpservletResponse; impor org.apache.log4j.logger; impor com.google.zxing.barcodeformat; impor com.google.zxing.encodehinttype; impor com.google.zxing.multiformatwriter; impor com.google.zxing.writerException; impor com.google.zxing.client.j2se.matrixtoimagewriter; impor com.google.zxing.common.bitmatrix; impor com.google.zxing.qrcode.decoder.errorcorrectionlevel; impor com.wqy.util.paycommonutil; impor com.wqy.util.payconfigutil; /** * Kelas Implementasi Servlet PAY1 */@WebServlet ("/PAY1") PAY PAY1 Memperluas httpservlet {private static final long serialversionuid = 1l; private static logger logger = logger.getLogger (pay1.class); public static int defaultwidthandHeight = 200; / ** * @see httpservlet#httpservlet () */ public pay1 () {super (); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse * response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub String nonce_str = PayCommonutil.getnonce_str (); long time_stamp = system.currentTimeMillis () / 1000; String product_id = "hd_goodssssss_10"; Key string = payconfigutil.api_key; // kunci sortedmap <objek, objek> packageParams = treemap baru <objek, objek> (); 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 ("tanda", tanda); // menghasilkan parameter string str = tourlparams (packageParams); String payurl = "weixin: // wxpay/bizpayurl?" + str; logger.info ("payurl:"+payurl); // Hasilkan Peta Kode QR <EncodeHintType, Object> Hints = HashMap baru <encodehintType, Object> (); // Hasilkan Peta Kode QR <EncodeHintType, Object> (); // tentukan level koreksi kesalahan hints.put (encodehinttype.error_correction, errorCorrectionLevel.l); // Tentukan format pengkodean hints.put (encodehinttype.character_set, "UTF-8"); hints.put (encodehinttype.margin, 1); coba {bitmatrix bitmatrix = multiformatwriter baru (). Encode (payurl, Barcodeformat.qr_code, defaultwidthandheight, defaultwidthandheight, petunjuk); OutputStream out = response.getoutputStream (); MatrixtoimageWriter.WriteToStream (bitmatrix, "png", out); // output kode qr out.flush (); out.close (); } catch (WriteRexception e) {// TODO Auto-Eynerated Catch Block E.PrintStackTrace (); }} public String tourlparams (sortedmap <objek, objek> packageParams) {// sebenarnya, Anda tidak dapat mengurutkan stringBuffer sb = new stringBuffer (); Set es = packageParams.entryset (); Iterator it = es.iterator (); while (it.hasnext ()) {map.entry entri = (map.entry) it.next (); String k = (string) entri.getKey (); String v = (string) entry.getValue (); if (null! = v &&! "". Equals (v)) {sb.append (k + "=" + v + "&"); }} sb.deleteCharat (sb.length ()-1); // hapus sb.tostring () yang terakhir & return; } / ** * @see httpservlet#dopost (permintaan httpservletRequest, httpservletResponse * respons) * / void dopost (httpservletequest request, httpservletsponse response (httpo-methydo (IoException {httpservletsponse Auto) }} 2.2. Pindai Antarmuka URL Callback Pembayaran
Ketika pelanggan memindai kode dua digit di atas dengan WeChat, server WeChat akan mengakses antarmuka ini. Di sini kita perlu menyelesaikan pesanan terpadu untuk mendapatkan pengidentifikasi sesi transaksi. Proses pemrosesan utama adalah sebagai berikut:
1) menerima parameter yang dikirim oleh server WeChat dan melakukan verifikasi tanda tangan dari parameter;
2) Keluarkan parameter Product_id, yang merupakan satu -satunya parameter yang dapat ditransmisikan melalui kode QR. Parameter lain dapat dimasukkan sesuai dengan mode dokumen resmi 1.1;
3) memproses bisnis Anda sendiri sesuai dengan Product_ID, seperti menghitung jumlah pembayaran, menghasilkan nomor pesanan, dll.;
4) Hubungi antarmuka tunggal terpadu untuk mendapatkan pengidentifikasi sesi transaksi prepay_id;
4.1) Siapkan parameter yang relevan (seperti appid, mch_id, jumlah pembayaran, nomor pesanan, deskripsi produk, dll.), Panggilan weChat untuk menyatukan antarmuka tunggal (mirip dengan antarmuka tunggal terpadu dari panggilan mode 2). Perhatikan "URL pemberitahuan asinkron" yang disebutkan di atas, yang merupakan antarmuka URL pemberitahuan asinkron yang akan disebutkan nanti. Untuk parameter tertentu, lihat dokumen resmi untuk menyatukan parameter permintaan tunggal;
4.2) menerima parameter yang dikembalikan oleh antarmuka tunggal terpadu dan memverifikasi parameter;
4.3) Keluarkan parameter prepay_id, yang merupakan pengidentifikasi sesi transaksi, yang sangat penting. Parameter lain dapat dirujuk ke dokumen resmi untuk mengembalikan hasilnya;
5) Siapkan parameter yang relevan (seperti AppID, MCH_ID, return_code, prepay_id, dll.), Dan menanggapi panggilan balik pembayaran awal (jika langkah-langkah di atas salah, jika verifikasi masuk gagal, Anda dapat mengembalikan parameter kesalahan ke server WeChat). Untuk parameter tertentu, silakan merujuk ke mode dokumen resmi 1.2 parameter output.
paket com.wqy; impor java.io.bufferedoutputStream; impor java.io.bufferedReader; impor java.io.ioException; impor java.io.inputStreamReader; impor java.io.inputStreamReader; impor java.util.sortedmap; impor java.util.treemap; impor javax.servlet.servletException; impor javax.servlet.annotation.webservlet; impor javax.servlet.http.httpservlet; impor javax.servlet.http.httpservletRequest; impor javax.servlet.http.httpservletResponse; impor org.apache.log4j.logger; impor com.wqy.util.httputil; impor com.wqy.util.paycommonutil; impor com.wqy.util.payconfigutil; /** * Kelas Implementasi Servlet Notify1 */@WebServlet ("/notify1") Kelas publik Notify1 memperluas httpservlet {private static final long serialversionuid = 1l; Private Static Logger Logger = Logger.getLogger (notify1.class); / ** * @see httpservlet#httpservlet () */ public notify1 () {super (); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse * response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub // Read XML InputStream InputStream; StringBuffer SB = StringBuffer baru (); inputStream = request.getInputStream (); String s; BufferedReader di = BufferedReader baru (inputStreamReader baru (inputStream, "UTF-8"))); while ((s = in.readline ())! = null) {sb.append (s); } in.close (); inputStream.close (); Sortedmap <object, object> packageParams = paycommonutil.xmlConvertToMap (sb.tostring ()); logger.info (packageParams); // Informasi Akun Kunci String = payConfigutil.api_key; // Kunci string resxml = ""; // umpan balik ke server weChat // verifikasi masuk if (paycommonutil.istenpaysign ("UTF-8", packageParams, key)) {// appid openId mch_id is_subscribe nonce_str product_id tanda // unify string singleed ("string oudeD = (" string oudeD = ("string oudepare (" String product_id = (string) packageParams.get ("product_id"); // parse product_id, Hitung harga, dll. String out_trade_no = string.valueof (System.CurrentTimeMillis ()); // Pesanan Nomor String order_price = "1"; // CATATAN HARGA: Unit harga dibagi menjadi string body = product_id; // Nama produk diatur ke string Product_ID lampiran = "XXX Store"; // string data tambahan nonce_str0 = paycommoneutil.getnonce_str (); // Dapatkan Inisiasi Komputer IP String SPBill_Create_IP = payconfigutil.create_ip; String trade_type = "asli"; Sortedmap <object, object> unifiedParams = new treemap <object, object> (); 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 ("tubuh", tubuh); // unifiedparams.put ("lampirkan", lampirkan); unifiedparams.put ("total_fee", order_price); // harus unifiedparams.put ("nonce_str", nonce_str0); // harus unifiedparams.put ("spbill_create_ip", spbill_create_ip); // harus unifiedparams.put ("trade_type", trade_type); // Harus UnifiedParams.put ("OpenId", OpenID); unifiedparams.put ("notify_url", payconfigutil.notify_url); // Pemberitahuan Asynchronous URL String Sign0 = payCommonutil.createsign ("UTF-8", UnifiedParams, Key); unifiedparams.put ("tanda", tanda0); // string Signature requestXml = paycommoneTil.getRequestXml (UnifiedParams); logger.info (requestXml); // String antarmuka tunggal terpadu rxml = httputil.postdata (payconfigutil.ufdoder_url, requestXml); // respons tunggal terpadu sortedmap <object, object> reparams = paycommonutil.xmlConvertTomap (rxml); logger.info (reparams); // Verifikasi if (paycommonutil.istenpaysign ("UTF-8", reparams, key)) {// menyatukan parameter yang dikembalikan oleh string tunggal prepay_id = (string) reparams.get ("prepay_id"); // Identifikasi sesi transaksi valid dalam 2 jam string nonCE_STR1 = payCommonutil.getnonce_str (); Sortedmap <objek, objek> resparams = treemap baru <objek, objek> (); resparams.put ("return_code", "Success"); // 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", "sukses"); // harus resparams.put ("err_code_des", "ok"); String tanda1 = paycommonutil.createSign ("UTF-8", resparams, kunci); resparams.put ("tanda", tanda1); // Signature resxml = paycommonutil.getRequestXml (resparams); logger.info (resxml); } else {logger.info ("kesalahan verifikasi tanda tangan"); resxml = "<xml>" + "<return_code> <! [cdata [fail]]> </ return_code>" + "<agulat_msg> <! [CDATA [kesalahan verifikasi tanda tangan]]> </ return_msg>" + "</xml>"; }} else {logger.info ("kesalahan verifikasi tanda tangan"); resxml = "<xml>" + "<return_code> <! [cdata [fail]]> </ return_code>" + "<agulat_msg> <! [CDATA [kesalahan verifikasi tanda tangan]]> </ return_msg>" + "</xml>"; } //------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ BufferedOutputStream( response.getOutputStream()); out.write (resxml.getbytes ()); out.flush (); out.close (); } / ** * @see httpservlet#dopost (permintaan httpservletRequest, httpservletResponse * respons) * / void dopost (httpservletequest request, httpservletsponse response (httpo-methydo (IoException {httpservletsponse Auto) }}Pada titik ini, pesanan WeChat pengguna akan menunjukkan jumlah yang harus dibayar dan deskripsi produk, dan kemudian menunggu pelanggan untuk menyelesaikan pembayaran.
2.3. Pemberitahuan asinkron dari antarmuka URL
Ketika pengguna menyelesaikan operasi pembayaran di WeChat, server WeChat akan secara tidak sinkron memberi tahu antarmuka dan mengirimkan hasil pembayaran akhir kepada kami sehingga kami dapat memverifikasi pesanan untuk pengiriman dan operasi lainnya. Perhatikan bahwa antarmuka ini persis sama dengan pengembangan model 2. Proses umum adalah sebagai berikut:
1) menerima parameter yang dikirim oleh server WeChat dan melakukan verifikasi tanda tangan dari parameter;
2) Keluarkan parameter result_code, nomor pesanan out_trade_no, jumlah pesanan total_fee dan parameter terkait bisnis lainnya. Parameter spesifik dapat dirujuk ke parameter pemberitahuan pemberitahuan umum tentang hasil pembayaran dalam dokumen resmi;
3) memproses bisnis, seperti memverifikasi nomor pesanan dan jumlah pesanan, memodifikasi status pesanan, dll.;
4) Siapkan parameter yang relevan (return_code dan return_msg) dan jawab server WeChat.
Perhatikan bahwa jika WeChat menerima jawaban pedagang yang tidak berhasil atau diatur waktunya dan WeChat percaya bahwa pemberitahuan telah gagal, WeChat akan secara teratur memulai pemberitahuan melalui strategi tertentu untuk meningkatkan tingkat keberhasilan pemberitahuan sebanyak mungkin, tetapi WeChat tidak menjamin bahwa pemberitahuan akan berhasil pada akhirnya. (Frekuensi pemberitahuan adalah 15/15/30/1800/1800/1800/1800/1800/1800/3600, unit: detik)
paket com.wqy; impor java.io.bufferedoutputStream; impor java.io.bufferedReader; impor java.io.ioException; impor java.io.inputStreamReader; impor java.io.inputStreamReader; impor java.util.sortedmap; impor javax.servlet.servletException; impor javax.servlet.annotation.webservlet; impor javax.servlet.http.httpservlet; impor javax.servlet.http.httpservletRequest; impor javax.servlet.http.httpservletResponse; impor org.apache.log4j.logger; impor com.wqy.util.paycommonutil; impor com.wqy.util.payconfigutil; /** * Kelas Implementasi Servlet RE_NOTIFY */@WebServlet ("/re_notify") kelas publik re_notify Extends httpservlet {private static final long serialVersionuid = 1l; Private Static Logger Logger = Logger.getLogger (re_notify.class); / ** * @see httpservlet#httpservlet () */ public re_notify () {super (); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse * response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub // Read parameter inputStream inputStream; StringBuffer SB = StringBuffer baru (); inputStream = request.getInputStream (); String s; BufferedReader di = BufferedReader baru (inputStreamReader baru (inputStream, "UTF-8"))); while ((s = in.readline ())! = null) {sb.append (s); } in.close (); inputStream.close (); Sortedmap <object, object> packageParams = paycommonutil.xmlConvertToMap (sb.tostring ()); logger.info (packageParams); // Informasi Akun Kunci String = payConfigutil.api_key; // Kunci string resxml = ""; // Umpan Balik ke WeChat Server // Tentukan apakah tanda tangannya benar jika (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); ////////////////////////////////////////// // Beri tahu WeChat. Konfirmasi asinkron berhasil. Harus menulisnya. Kalau tidak, latar belakang akan diberitahukan sepanjang waktu. Setelah delapan kali, Anda akan berpikir bahwa transaksi telah gagal. resxml = "<xml>" + "<return_code> <! [cdata [sukses]]> </return_code>" + "<return_msg> <! [Cdata [ok]]> </eturn_msg>" + "</xml>"; } else {logger.info ("bayar gagal, pesan kesalahan:" + packageParams.get ("err_code"))); resxml = "<xml>" + "<return_code> <! [cdata [fail]]> </ return_code>" + "<return_msg> <! [CDATA [pesan kosong]]> </return_msg>" + "</xml>"; }} else {logger.info ("kesalahan verifikasi tanda tangan"); resxml = "<xml>" + "<return_code> <! [cdata [fail]]> </ return_code>" + "<agulat_msg> <! [CDATA [kesalahan verifikasi tanda tangan]]> </ return_msg>" + "</xml>"; } // ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- BufferedOutputStream (response.getoutputStream ()); out.write (resxml.getbytes ()); out.flush (); out.close (); } / ** * @see httpservlet#dopost (permintaan httpservletRequest, httpservletResponse * respons) * / void dopost (httpservletequest request, httpservletsponse response (httpo-methydo (IoException {httpservletsponse Auto) }} 3. Hasil tes
3.1. Tautan kode QR pembayaran yang dihasilkan
3.2. Parameter yang diterima oleh Antarmuka URL panggilan balik pembayaran
3.3. Memulai parameter permintaan tunggal terpadu
3.4. Menyatukan parameter pengembalian tunggal
3.5. Parameter respons akhir dari antarmuka URL panggilan balik pembayaran
Di atas adalah semua konten artikel ini. Saya berharap ini akan membantu untuk pembelajaran semua orang dan saya harap semua orang akan lebih mendukung wulin.com.