preface
The recent project involves the function of wechat payment. Here we briefly share the overall development process. Here we want to introduce JSAPI payment.
JSAPI web page payment, which is called daily official account payment, can click on page links in WeChat official account, friends circle, chat session, or scan WeChat address with WeChat scan code, open the merchant HTML5 page in WeChat, and complete the payment within the page.
The above introduction can be simply understood as that jsapi payment must be carried out in wechat browser.
Wechat payment supports a variety of access modes, including direct connection mode and service provider mode.
Direct connection mode refers to the system developed by the merchant to conduct transactions with wechat payment. Wechat payment directly settles the funds to the merchant's settlement account, and the merchant provides payment services to users. This mode requires the merchant to have the ability of system development, and the merchant can go to the merchant platform to complete the settlement.
Service provider mode refers to a mode in which some small and medium-sized merchants in the market who have no development ability are assisted by system developers or solution providers who have officially registered and settled in wechat payment to complete the settlement, development and daily operation of these merchants. Service providers can go to the service provider platform to complete registration.
Select the access mode according to the actual project situation. The APIs of the two modes are similar, in which the service provider mode supports the entry of multiple sub merchants, and supports Cash counting plan.
The following describes the development process of wechat payment under ordinary merchants (direct connection mode).
prepare
1. apply for official account number appId, and configure corresponding web page authorized domain name and ip white list.
2. Apply for mchid, settle in ordinary merchants, and open JSAPI payment.
3. Bind APPID and mchid
4. Configure API key and api certificate
5. Set payment directory
The merchant finally requested to pull up the page address of the wechat payment cashier, which we call "payment directory".
If the payment authorization directory is set as a top-level domain name, only the top-level domain name is verified, and the suffix is not verified; If the payment authorization directory is set to multi-level directory, full matching will be performed.
development
After the preparation, you can happily develop the interface. It should be noted here that there are two versions of wechat payment API, V2 and V3, which are valid for a long time. The signature method and parameter format may be slightly different. V3 also requires merchant platform certificate (different from API certificate), but the general development ideas and key parameters are consistent.
1. Process description
(a) The basic process of wechat order placement and payment is that the business system places an order in the background, generates a wechat payment order (pre payment), and returns the corresponding parameters (pre pay_id) returned by the interface to the foreground. The foreground calls up the wechat payment page. After entering the password for payment, wechat will asynchronously notify the business system of the payment result, and the system will process the corresponding business.
(b) The process of wechat refund is that the business system initiates a refund application, and then wechat will asynchronously notify the business system of the refund result, and the business system will process it accordingly.
Note: after the background initiates the order application or refund application, it does not mean that the payment or refund is successful. It needs to be judged according to the asynchronous notice. Moreover, the notice may be initiated many times, and the business system needs to correctly process the notice. The following is the official suggestion.
When the merchant system receives the notice for processing, first check the status of the corresponding business data and judge whether the notice has been processed. If it is not processed, it shall be processed again; If it has been processed, the result is returned directly. Before checking and processing the status of business data, data lock should be used for concurrency control to avoid data confusion caused by function reentry.
Considering that the order status is still not updated in time after multiple asynchronous notification processing, you can use the scheduled task to query the order status regularly and update the order status in the business system.
2. Order placement (advance payment)
WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig(); Map<String, String> params = UnifiedOrderModel .builder() .appid(wxPayApiConfig.getAppId()) .mch_id(wxPayApiConfig.getMchId()) .nonce_str(WxPayKit.generateStr()) .body("Official account payment") .attach("hello world") .out_trade_no(WxPayKit.generateStr()) .total_fee("1000") .spbill_create_ip(ip) .notify_url(notifyUrl) .trade_type(TradeType.JSAPI.getTradeType()) .openid(openId) .build() .createSign(wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256); String xmlResult = WxPayApi.pushOrder(false, params); log.info(xmlResult); Map<String, String> resultMap = WxPayKit.xmlToMap(xmlResult); String returnCode = resultMap.get("return_code"); String returnMsg = resultMap.get("return_msg"); if (!WxPayKit.codeIsOk(returnCode)) { return new AjaxResult().addError(returnMsg); } String resultCode = resultMap.get("result_code"); if (!WxPayKit.codeIsOk(resultCode)) { return new AjaxResult().addError(returnMsg); } // The following fields are in return_code and result_ Returns when all codes are SUCCESS String prepayId = resultMap.get("prepay_id"); Map<String, String> packageParams = WxPayKit.prepayIdCreateSign(prepayId, wxPayApiConfig.getAppId(), wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256); String jsonStr = JSON.toJSONString(packageParams); return new AjaxResult().success(jsonStr);
There is a key parameter in the information returned from the wechat order, prepay_id, which needs to be returned to the front end.
3. Front end start-up payment
function onBridgeReady(){ WeixinJSBridge.invoke( 'getBrandWCPayRequest', { "appId":"wx2421b1c4370ec43b", //The official account number ID is introduced by merchants. "timeStamp":"1395712654", //Timestamp, seconds since 1970 "nonceStr":"e61463f8efa94090b1f366cccfbbb444", //Random string "package":"prepay_id=u802345jgfjsdfgsdg888", "signType":"MD5", //Wechat signature method: "paySign":"70EA570631E4BB79628FBCA90534C63FF7FADD89" //Wechat signature }, function(res){ if(res.err_msg == "get_brand_wcpay_request:ok" ){ // Use the above methods to judge the front-end return, and the wechat team solemnly prompts: //res.err_msg will return ok after the user pays successfully, but it is not guaranteed to be absolutely reliable. } }); } if (typeof WeixinJSBridge == "undefined"){ if( document.addEventListener ){ document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false); }else if (document.attachEvent){ document.attachEvent('WeixinJSBridgeReady', onBridgeReady); document.attachEvent('onWeixinJSBridgeReady', onBridgeReady); } }else{ onBridgeReady(); }
When a request is initiated, the package parameter is prepay in a unified format_ Id = * * *, which is the prepay returned by the unified ordering interface_ The ID parameter value is the key parameter returned as mentioned above. Considering that the signature algorithm is troublesome, all parameters required by the front end to retrieve js payment can be returned by the back end.
4. Asynchronous notification of payment results
@RequestMapping(value = "/payNotify", method = {RequestMethod.POST, RequestMethod.GET}) public String payNotify(HttpServletRequest request) { String xmlMsg = HttpKit.readData(request); log.info("Payment notice=" + xmlMsg); Map<String, String> params = WxPayKit.xmlToMap(xmlMsg); String returnCode = params.get("return_code"); // Pay attention to repeated notifications. Multiple notifications may be received for the same order number. Please be sure to judge the order status first // Note that the signature method here should be consistent with the signature type of unified order if (WxPayKit.verifyNotify(params, WxPayApiConfigKit.getWxPayApiConfig().getPartnerKey(), SignType.HMACSHA256)) { if (WxPayKit.codeIsOk(returnCode)) { // Update order information (specific business processing of the system) // Send notifications, etc Map<String, String> xml = new HashMap<String, String>(2); xml.put("return_code", "SUCCESS"); xml.put("return_msg", "OK"); return WxPayKit.toXml(xml); } } return null; }
The address of the notification interface is through the parameter notify submitted in the unified ordering API_ URL setting, if the link cannot be accessed, the merchant will not be able to receive wechat notification. After receiving the notice, update the order information (status).
After processing, the merchant needs to return to wechat parameters. If wechat receives the merchant's response that does not meet the specification or times out, wechat will determine that this notification fails and resend the notification until it succeeds.
5. Refund application
@RequestMapping(value = "/refund", method = {RequestMethod.POST, RequestMethod.GET}) public String refund(@RequestParam(value = "transactionId", required = false) String transactionId, @RequestParam(value = "outTradeNo", required = false) String outTradeNo) { try { log.info("transactionId: {} outTradeNo:{}", transactionId, outTradeNo); if (StrKit.isBlank(outTradeNo) && StrKit.isBlank(transactionId)) { return "transactionId,out_trade_no either-or"; } WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig(); Map<String, String> params = RefundModel.builder() .appid(wxPayApiConfig.getAppId()) .mch_id(wxPayApiConfig.getMchId()) .nonce_str(WxPayKit.generateStr()) .transaction_id(transactionId) .out_trade_no(outTradeNo) .out_refund_no(WxPayKit.generateStr()) .total_fee("1") .refund_fee("1") .notify_url(refundNotifyUrl) .build() .createSign(wxPayApiConfig.getPartnerKey(), SignType.MD5); String refundStr = WxPayApi.orderRefund(false, params, wxPayApiConfig.getCertPath(), wxPayApiConfig.getMchId()); log.info("refundStr: {}", refundStr); return refundStr; } catch (Exception e) { e.printStackTrace(); } return null; }
api certificate is required for refund. The certificate should be placed in the directory with access control to prevent it from being downloaded by others.
6. Asynchronous notification of refund results
@RequestMapping(value = "/refundNotify", method = {RequestMethod.POST, RequestMethod.GET}) public String refundNotify(HttpServletRequest request) { String xmlMsg = HttpKit.readData(request); log.info("Refund notice=" + xmlMsg); Map<String, String> params = WxPayKit.xmlToMap(xmlMsg); String returnCode = params.get("return_code"); // Pay attention to repeated notifications. Multiple notifications may be received for the same order number. Please be sure to judge the order status first if (WxPayKit.codeIsOk(returnCode)) { String reqInfo = params.get("req_info"); String decryptData = WxPayKit.decryptData(reqInfo, WxPayApiConfigKit.getWxPayApiConfig().getPartnerKey()); log.info("Decrypted data of refund notice=" + decryptData); // Update order information // Send notifications, etc Map<String, String> xml = new HashMap<String, String>(2); xml.put("return_code", "SUCCESS"); xml.put("return_msg", "OK"); return WxPayKit.toXml(xml); } return null; }
The processing method of asynchronous notification of refund result is similar to that of asynchronous payment notification, which will not be repeated here.
epilogue
Here is just an introduction to the general development process of wechat JSAPI payment. In the actual development, we also need to consider avoiding repeated orders and repeated refunds, and whether the order status of the business system is consistent with the actual payment (refund) status; When checking and processing business data, data lock should be used for concurrency control to avoid data confusion caused by function reentry and transaction control.
The specific api implementation can refer to the official documents, official SDK and Demo of wechat payment. The wechat open community also has corresponding code practice for use.
Related links:
[1]Wechat payment official document
[2]:Official sdk and DEMO
[3]: Excellent practice source code of wechat open community