1. Preparation
Countless people have asked about the development of model one, so I posted it here for reference only. I have explained the difference between mode one and mode two many times. It is nothing more than that the QR code of mode one is for the product, and the QR code of mode two is for the order. I don’t have to talk about other specific details. You can go to the official document to view the document by yourself, and then choose mode one or mode two and it depends on your business.
1.1. Related configuration parameters
The four things before, APP_ID and APP_SECRET can be found on the public platform, while MCH_ID and API_KEY are found on the merchant platform, especially API_KEY must be set on the merchant platform. This thing is related to the correctness of the parameter verification, so it must be set correctly. The QR code payment model 1 is actually similar to the QR code payment model 2. In fact, it only uses APP_ID, MCH_ID and API_KEY, and does not use anything else. The official document address of Mode One is here: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4
1.2. Related Concepts
Here I want to correct a concept first. During the development of the second model, I mentioned a concept like "payment callback address". Its function is that after the customer scans and completes the payment, the WeChat server needs to access the address provided by us and send us the payment results so that we can verify the order for delivery. This is a relatively common concept and name for other payment tools. However, later I looked through the documents on WeChat’s official website and found that in the first development of the model, they called this "asynchronous notification url" instead of a "payment callback address", but essentially this refers to the same meaning. But why do I mention this thing here? This is because in mode one, there is actually another so-called "payment callback" called "scan code payment callback URL". This thing is different from the "asynchronous notification url" above. It can be simply understood that it is an interface on our server to assist in completing orders. The development of mode one requires the cooperation of the two interfaces of "scan the QR code to pay callback URL" and "asynchronous notification url", so everyone should distinguish it here.
"Async Notification URL" is set when calling a unified single interface. It can be set dynamically, as long as this interface receives parameter response parameters according to relevant rules. The "Scan the QR code to pay callback URL" is relatively fixed. It is set on the WeChat public platform. It takes about 10 minutes to take effect after setting. After logging in to the WeChat public platform, select WeChat Pay and you can find it under the Development Configuration tab:
Here we need to set up the address of our own server (and say the public network address again, so that the WeChat server can find you).
1.3. Development environment
I'm using the most basic Servlet 3.0 as the sample environment here. Regarding the reference of third-party jar packages, compared with the development of model 2, in addition to using the xml operation jdom, there is a Google ZXing QR code package and log4j package. As shown in the figure below:
In order to facilitate debugging, it is recommended that you first lower the adjustment in this environment before transplanting it to the real project.
2. Development and practical combat
Before starting, I suggest that you go to the official document to take a good look at the timing chart. After understanding the timing chart, writing code is not a difficult task. Of course, if you can't understand the picture, you can also try to understand it in combination with my following code.
2.1. QR code generation
First of all, there is a QR code. The content in the QR code is a link, and the form is:
weixin://wxpay/bizpayurl?sign=XXXXX&appid=XXXXX&mch_id=XXXXX&product_id=XXXXX&time_stamp=XXXXX&nonce_str=XXXXXXXXX&nonce_str=XXXXXXXXXXXX
For details, you can refer to the official document mode to generate QR code rules. Next we need to generate a QR code for this link. I used Google ZXing here to generate a QR code.
package com.wqy; import java.io.IOException; import java.io.OutputStream; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; import com.google.zxing.BarcodeFormat; import com.google.zxing.EncodeHintType; import com.google.zxing.MultiFormatWriter; import com.google.zxing.WriterException; import com.google.zxing.client.j2se.MatrixToImageWriter; import com.google.zxing.common.BitMatrix; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; import com.wqy.util.PayCommonUtil; import com.wqy.util.PayConfigUtil; /** * Servlet implementation class Pay1 */ @WebServlet("/Pay1") public class Pay1 extends 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_goodsssss_10"; String key = PayConfigUtil.API_KEY; // key SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>(); 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("sign", sign); // Generate parameters String str = ToUrlParams(packageParams); String payurl = "weixin://wxpay/bizpayurl?" + str; logger.info("payurl:"+payurl); // Generate QR code Map<EncodeHintType, Object> hints=new HashMap<EncodeHintType, Object>(); // Generate QR code Map<EncodeHintType, Object>(); // Specify the error correction level hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L); // Specify the encoding format hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); hints.put(EncodeHintType.MARGIN, 1); try { BitMatrix bitMatrix = new MultiFormatWriter().encode(payurl,BarcodeFormat.QR_CODE, defaultWidthAndHeight, defaultWidthAndHeight, hints); OutputStream out = response.getOutputStream(); MatrixToImageWriter.writeToStream(bitMatrix, "png", out);//Output QR code out.flush(); out.close(); } catch (WriterException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public String ToUrlParams(SortedMap<Object, Object> packageParams){ //In fact, you can not sort StringBuffer sb = new StringBuffer(); Set es = packageParams.entrySet(); Iterator it = es.iterator(); while (it.hasNext()) { Map.Entry entry = (Map.Entry) it.next(); String k = (String) entry.getKey(); String v = (String) entry.getValue(); if (null != v && !"".equals(v)) { sb.append(k + "=" + v + "&"); } } sb.deleteCharAt(sb.length()-1);//Delete the last& return sb.toString(); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse * response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); } } 2.2. Scan the payment callback URL interface
When the customer scans the above two-digit code with WeChat, the WeChat server will access this interface. Here we need to complete the unified order to obtain the transaction session identifier. The main process of processing is as follows:
1) Receive parameters sent by the WeChat server and perform signature verification of the parameters;
2) Take out the parameter product_id, which is the only parameter that can be transmitted through the QR code. Other parameters can be entered in accordance with the official document mode 1.1;
3) Process your own business according to product_id, such as calculating payment amount, generating order numbers, etc.;
4) Call the unified single interface to obtain the transaction session identifier prepay_id;
4.1) Prepare the relevant parameters (such as appid, mch_id, payment amount, order number, product description, etc.), call WeChat to unify the single interface (similar to the unified single interface of the mode 2 call). Pay attention to the above-mentioned "asynchronous notification url", which is the asynchronous notification url interface that will be mentioned later. For specific parameters, refer to the official document to unify the single request parameters;
4.2) Receive the parameters returned by the unified single interface and verify the parameters;
4.3) Take out the parameter prepay_id, which is the transaction session identifier, which is extremely important. Other parameters can be referred to the official document to return the result;
5) Prepare the relevant parameters (such as appid, mch_id, return_code, prepay_id, etc.), and respond to the initial payment callback (if the above steps are wrong, if the sign-in verification fails, you can return the error parameters to the WeChat server). For specific parameters, please refer to the official document mode 1.2 output parameters.
package com.wqy; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.InputStreamReader; import java.util.SortedMap; import java.util.TreeMap; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; import com.wqy.util.HttpUtil; import com.wqy.util.PayCommonUtil; import com.wqy.util.PayConfigUtil; /** * Servlet implementation class Notify1 */ @WebServlet("/Notify1") public class Notify1 extends 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 = new StringBuffer(); inputStream = request.getInputStream(); String s; BufferedReader in = new BufferedReader(new InputStreamReader(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); // Account information String key = PayConfigUtil.API_KEY; // key String resXml="";//Feedback to WeChat server// Sign-in verification if (PayCommonUtil.isTenpaySign("UTF-8", packageParams, key)) { //appid openid mch_id is_subscribe nonce_str product_id sign //Unify single String openid = (String)packageParams.get("openid"); String product_id = (String)packageParams.get("product_id"); //Parse product_id, calculate price, etc. String out_trade_no = String.valueOf(System.currentTimeMillis()); // Order number String order_price = "1"; // Price Note: The unit of price is divided into String body = product_id; // Product name is set to product_id String attach = "XXX Store"; // Additional data String nonce_str0 = PayCommonUtil.getNonce_str(); // Get the initiating computer ip String spbill_create_ip = PayConfigUtil.CREATE_IP; String trade_type = "NATIVE"; 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("body", body); // UnifiedParams.put("attach", attach); unifiedParams.put("total_fee", order_price); // must be unifiedParams.put("nonce_str", nonce_str0); // must be unifiedParams.put("spbill_create_ip", spbill_create_ip); // must be unifiedParams.put("trade_type", trade_type); // must be unifiedParams.put("openid", openid); unifiedParams.put("notify_url", PayConfigUtil.NOTIFY_URL); // Asynchronous Notification url String sign0 = PayCommonUtil.createSign("UTF-8", unifiedParams,key); unifiedParams.put("sign", sign0); //Signature String requestXML = PayCommonUtil.getRequestXml(unifiedParams); logger.info(requestXML); //Unified single interface String rXml = HttpUtil.postData(PayConfigUtil.UFDODER_URL, requestXML); //Unified single response SortedMap<Object, Object> reParams = PayCommonUtil.xmlConvertToMap(rXml); logger.info(reParams); //Verify if (PayCommonUtil.isTenpaySign("UTF-8", reParams, key)) { //Unify the parameters returned by the single String prepay_id = (String)reParams.get("prepay_id"); //Transaction session identification valid within 2 hours String nonce_str1 = PayCommonUtil.getNonce_str(); SortedMap<Object,Object> resParams = new TreeMap<Object,Object>(); 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", "SUCCESS"); // Must be resParams.put("err_code_des", "OK"); String sign1 = PayCommonUtil.createSign("UTF-8", resParams,key); resParams.put("sign", sign1); //Signature resXml = PayCommonUtil.getRequestXml(resParams); logger.info(resXml); }else{ logger.info("Signature verification error"); resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[Signature Verification Error]]></return_msg>" + "</xml> "; } }else{ logger.info("Signature Verification Error"); resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[Signature Verification Error]]></return_msg>" + "</xml> "; } //------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ BufferedOutputStream( response.getOutputStream()); out.write(resXml.getBytes()); out.flush(); out.close(); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse * response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); } }At this point, the user's WeChat order will show the amount to be paid and the product description, and then wait for the customer to complete the payment.
2.3. Asynchronous notification of the url interface
When the user completes the payment operation on WeChat, the WeChat server will asynchronously notify the interface and send us the final payment result so that we can verify the order for delivery and other operations. Note that this interface is exactly the same as the development of Model 2. The general process is as follows:
1) Receive parameters sent by the WeChat server and perform signature verification of the parameters;
2) Take out the parameters result_code, order number out_trade_no, order amount total_fee and other business-related parameters. The specific parameters can be referred to the notification parameters of the general notification of payment results in the official document;
3) Processing business, such as verifying order number and order amount, modifying order status, etc.;
4) Prepare the relevant parameters (return_code and return_msg) and answer the WeChat server.
Note that if WeChat receives the merchant's answers that are not successful or timed out and WeChat believes that the notification has failed, WeChat will regularly re-initiate notifications through certain strategies to increase the success rate of notifications as much as possible, but WeChat does not guarantee that the notification will be successful in the end. (Notification frequency is 15/15/30/1800/1800/1800/1800/1800/1800/3600, unit: seconds)
package com.wqy; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.InputStreamReader; import java.util.SortedMap; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; import com.wqy.util.PayCommonUtil; import com.wqy.util.PayConfigUtil; /** * Servlet implementation class Re_notify */ @WebServlet("/Re_notify") public class 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 parameters InputStream inputStream; StringBuffer sb = new StringBuffer(); inputStream = request.getInputStream(); String s; BufferedReader in = new BufferedReader(new InputStreamReader(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); // Account information String key = PayConfigUtil.API_KEY; // key String resXml = ""; // Feedback to WeChat server// Determine whether the signature is correct if (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); ////////////////////////////////// Execute your own business logic ////////////////// logger.info("Payment successful"); // Notify WeChat. Asynchronous confirmation is successful. Must write it. Otherwise, the background will be notified all the time. After eight times, you will think that the transaction has failed. resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> "; } else { logger.info("Pay failed, error message: " + packageParams.get("err_code")); resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[Message is empty]]></return_msg>" + "</xml> "; } } else { logger.info("Signature Verification Error"); resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[Signature Verification Error]]></return_msg>" + "</xml> "; } // ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------------------------------ BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream()); out.write(resXml.getBytes()); out.flush(); out.close(); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse * response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); } } 3. Test results
3.1. The generated payment QR code link
3.2. Parameters received by the payment callback URL interface
3.3. Initiate unified single request parameters
3.4. Unify single return parameters
3.5. Final response parameters of payment callback URL interface
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.