Introduction to WeChat Payment
The merchant background system calls the unified order-placing interface of WeChat payment first, and the WeChat background system returns the link parameter code_url, the merchant background system will code_ The URL value generates a two-dimensional code picture, and the user starts to pay when the WeChat client scans the code. Note: code_ The URL is valid for 2 hours, after which the scanner cannot initiate payment.
Business Process Description:
(1) Business background system generates orders based on the goods selected by users.
(2) Users invoke WeChat Payment (Unified Order API) to generate prepayment transactions after confirming the payment;
(3) The WeChat payment system receives the request, generates the prepayment transaction and returns the two-dimensional code link code_of the transaction session. Url.
(4) Business background system based on the returned code_url generates a two-dimensional code.
(5) The user opens WeChat to scan the QR code, and the WeChat client sends the scanned content to the WeChat payment system.
(6) The WeChat payment system receives a client request, verifies the validity of the link, and initiates a user payment, which requires authorization from the user.
(7) After the user enters the password in the Wechat client and confirms the payment, the Wechat client submits the authorization.
(8) The WeChat payment system completes payment transactions according to user authorization.
(9) After the payment transaction is completed, the Wechat payment system returns the transaction results to the Wechat client, and prompts the user through SMS and Wechat messages. The WeChat client displays the Payment Transaction Results page.
(10) The WeChat payment system notifies the merchant's background system of the payment result by sending an asynchronous message. The merchant background system needs to reply to the receipt and notify the WeChat background system not to send any more payment notifications for the order.
(11) In case no payment notification is received, the merchant background system calls [Query Order API] (Check list implementation can refer to: Payment callback and Check list implementation guide).
(12) The merchant sends the goods to the user after confirming that the order has been paid.
Generate WeChat Payment QR Code
Application Scenarios
In addition to payment code payment scenarios, the merchant system calls this interface to generate prepayment transactions in the WeChat payment service background, return the correct prepayment transaction session identity, and then generate transaction strings to initiate payment according to different scenarios such as Native, JSAPI, APP, etc.
This time press Native
state machine
Interface Links
URL address: https://api.mch.weixin.qq.com/pay/unifiedorder
URL address: https://api2.mch.weixin.qq.com/pay/unifiedorder (Alternate domain name) See Cross-City Redundancy Project
Need Certificate: No
To pass in parameters, refer to the following documentation
https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1
SpringBoot Project Setup
Introducing dependencies
<dependencies> <dependency> <groupId>com.github.wxpay</groupId> <artifactId>wxpay-sdk</artifactId> <version>0.0.3</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.28</version> </dependency> <!--httpclient--> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.1</version> </dependency> </dependencies>
Tool class
1. Combine order numbers based on time and random number of generations
** * Order Number Tool Class * * @author qy * @since 1.0 */ public class OrderNoUtil { /** * Get Order Number * @return */ public static String getOrderNo() { SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); String newDate = sdf.format(new Date()); String result = ""; Random random = new Random(); for (int i = 0; i < 3; i++) { result += random.nextInt(10); } return newDate + result; } }
2. Send request class HttpClient
/** * http Request Client * * @author qy * */ public class HttpClient { private String url; private Map<String, String> param; private int statusCode; private String content; private String xmlParam; private boolean isHttps; public boolean isHttps() { return isHttps; } public void setHttps(boolean isHttps) { this.isHttps = isHttps; } public String getXmlParam() { return xmlParam; } public void setXmlParam(String xmlParam) { this.xmlParam = xmlParam; } public HttpClient(String url, Map<String, String> param) { this.url = url; this.param = param; } public HttpClient(String url) { this.url = url; } public void setParameter(Map<String, String> map) { param = map; } public void addParameter(String key, String value) { if (param == null) param = new HashMap<String, String>(); param.put(key, value); } public void post() throws ClientProtocolException, IOException { HttpPost http = new HttpPost(url); setEntity(http); execute(http); } public void put() throws ClientProtocolException, IOException { HttpPut http = new HttpPut(url); setEntity(http); execute(http); } public void get() throws ClientProtocolException, IOException { if (param != null) { StringBuilder url = new StringBuilder(this.url); boolean isFirst = true; for (String key : param.keySet()) { if (isFirst) url.append("?"); else url.append("&"); url.append(key).append("=").append(param.get(key)); } this.url = url.toString(); } HttpGet http = new HttpGet(url); execute(http); } /** * set http post,put param */ private void setEntity(HttpEntityEnclosingRequestBase http) { if (param != null) { List<NameValuePair> nvps = new LinkedList<NameValuePair>(); for (String key : param.keySet()) nvps.add(new BasicNameValuePair(key, param.get(key))); // parameter http.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8)); // Setting parameters } if (xmlParam != null) { http.setEntity(new StringEntity(xmlParam, Consts.UTF_8)); } } private void execute(HttpUriRequest http) throws ClientProtocolException, IOException { CloseableHttpClient httpClient = null; try { if (isHttps) { SSLContext sslContext = new SSLContextBuilder() .loadTrustMaterial(null, new TrustStrategy() { // Trust All public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { return true; } }).build(); SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( sslContext); httpClient = HttpClients.custom().setSSLSocketFactory(sslsf) .build(); } else { httpClient = HttpClients.createDefault(); } CloseableHttpResponse response = httpClient.execute(http); try { if (response != null) { if (response.getStatusLine() != null) statusCode = response.getStatusLine().getStatusCode(); HttpEntity entity = response.getEntity(); // Response Content content = EntityUtils.toString(entity, Consts.UTF_8); } } finally { response.close(); } } catch (Exception e) { e.printStackTrace(); } finally { httpClient.close(); } } public int getStatusCode() { return statusCode; } public String getContent() throws ParseException, IOException { return content; } }
controller
@ApiOperation(value = "Generate payment QR code based on order number") @GetMapping("createNative/{orderNo}") public R createNative(@PathVariable String orderNo){ Map<String,Object> map= payLogService.createNative(orderNo); return R.ok().data(map); }
service
//Generate payment QR code based on order number @Override public Map<String, Object> createNative(String orderNo) { try { //1 Query order information QueryWrapper<TOrder> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("order_no", orderNo); TOrder order = orderService.getOne(queryWrapper); //1.1 Verify orders if (order == null) { throw new GuliException(20001, "Order Invalidation"); } //2 Encapsulate payment parameters Map m = new HashMap(); //Set Payment Parameters m.put("appid", "wx74862e0dfcf69954");//Required application id m.put("mch_id", "1558950191");//Mandatory Business Number m.put("nonce_str", WXPayUtil.generateNonceStr());//Required WeChat Generate Random String m.put("body", order.getCourseTitle());//Own Business Content Course Name m.put("out_trade_no", orderNo);//Order Number m.put("total_fee", order.getTotalFee().multiply(new BigDecimal("100")).longValue() + "");//Transaction amount m.put("spbill_create_ip", "127.0.0.1");//Terminal ip m.put("notify_url", "http://guli.shop/api/order/weixinPay/weixinNotify\n";//required callback address m.put("trade_type", "NATIVE");//Transaction type //3 Send the request through httpclient, and the parameters are converted to xml HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder ";//official request address //client Setting Parameters client.setXmlParam(WXPayUtil.generateSignedXml(m, "T6m9iK73b0kn9g5v426MKfHQH7X8rKwb"));//Required Merchant Key client.setHttps(true); client.post(); //4 Get the return value String xml = client.getContent(); System.out.println("xml=" + xml); //Parse returns map collection Map<String, String> resultMap = WXPayUtil.xmlToMap(xml); //5. Encapsulate Return Result Set Map map = new HashMap<>(); map.put("out_trade_no", orderNo);//Order number map.put("course_id", order.getCourseId());//Customized commodity id map.put("total_fee", order.getTotalFee());//Amount of money map.put("result_code", resultMap.get("result_code"));//Payment Result Code map.put("code_url", resultMap.get("code_url"));//Pay for QR link return map; } catch (Exception e) { e.printStackTrace(); throw new GuliException(20001, "Failed to get QR code"); } }
Examples of results returned are as follows:
<xml> <appid>wx2421b1c4370ec43b</appid> <attach>Payment Test</attach> <body>JSAPI Payment Test</body> <mch_id>10000100</mch_id> <detail><![CDATA[{ "goods_detail":[ { "goods_id":"iphone6s_16G", "wxpay_goods_id":"1001", "goods_name":"iPhone6s 16G", "quantity":1, "price":528800, "goods_category":"123456", "body":"IPhone" }, { "goods_id":"iphone6s_32G", "wxpay_goods_id":"1002", "goods_name":"iPhone6s 32G", "quantity":1, "price":608800, "goods_category":"123789", "body":"IPhone" } ] }]]></detail> <nonce_str>1add1a30ac87aa2db72f57a2375d8fec</nonce_str> <notify_url>https://wxpay.wxutil.com/pub_v2/pay/notify.v2.php</notify_url> <openid>oUpF8uMuAJO_M2pxb1Q9zNjWeS6o</openid> <out_trade_no>1415659990</out_trade_no> <spbill_create_ip>14.23.150.211</spbill_create_ip> <total_fee>1</total_fee> <trade_type>JSAPI</trade_type> <sign>0CB01533B8C1EF103065174F50BCA001</sign> </xml>
Finally, return the code_url pays for a link to a QR code and puts it inside the QR code at the front
Query Payments
Application Scenarios
This interface provides queries for all WeChat payment orders. Merchants can actively query the order status through the query order interface to complete the next business logic.
When a query interface needs to be invoked:
When the business background, network, server and other abnormalities occur, the business system does not receive payment notifications (check list implementation can be referred to: payment callbacks and check list implementation guidelines);
_Return system error or unknown transaction status after calling payment interface;
_Call the payment code payment API to return the status of USERPAYING;
_Confirm payment status before invoking bills of lading or revoking interface API;
Interface Links
URL address: https://api.mch.weixin.qq.com/pay/orderquery
URL address: https://api2.mch.weixin.qq.com/pay/orderquery (Alternate domain name) See Cross-City Redundancy Project
Need a certificate: No
Request parameters to see documentation: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_2
controller
@GetMapping("queryPayStatus/{orderNo}") @ApiOperation(value = "Query payment status based on order number") public R queryPayStatus(@PathVariable String orderNo) { //1 Invoke WeChat interface to query payment status Map<String, String> map = payLogService.queryPayStatus(orderNo); //2 Determine payment status if (map == null) { return R.error().message("Payment Error"); } if ("SUCCESS".equals(map.get("trade_state"))) { //3 Update order status and record payment log after successful payment payLogService.updateOrderStatus(map); return R.ok().message("Successful Payment"); } return R.ok().code(25000).message("Payment in progress"); }
service
//Invoke WeChat interface to query payment status @Override public Map<String, String> queryPayStatus(String orderNo) { try { //1 Encapsulate payment parameters Map m = new HashMap(); //Set Payment Parameters m.put("appid", "wx74862e0dfcf69954");//Required application id m.put("mch_id", "1558950191");//Mandatory Business Number m.put("out_trade_no", orderNo);//Required Order Number m.put("nonce_str", WXPayUtil.generateNonceStr());//WeChat Tool Generate Random Characters //2. Setup Request HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/orderquery ";//Official Query Request Address client.setXmlParam(WXPayUtil.generateSignedXml(m, "T6m9iK73b0kn9g5v426MKfHQH7X8rKwb"));//Merchant Key client.setHttps(true); client.post(); //3. Return data from third parties String xml = client.getContent(); System.out.println("Order Status="+xml); //Escape to map Map<String, String> resultMap = WXPayUtil.xmlToMap(xml); //6. Convert to Map //7. Return return resultMap; } catch (Exception e) { e.printStackTrace(); throw new GuliException(20001,"Failed to query order status"); } }
Examples of results returned:
<xml> <appid>wx2421b1c4370ec43b</appid> <mch_id>10000100</mch_id> <nonce_str>ec2316275641faa3aacf3cc599e8730f</nonce_str> <transaction_id>1008450740201411110005820873</transaction_id> <sign>FDD167FAA73459FD921B144BAF4F4CA2</sign> </xml>
Tips
The front end can set a timer to query the payment status every few seconds until the payment succeeds or fails
//Query order payment status every 5 seconds //Need to create timer setIntervar (() =>{}, 5000) data() { return { timer1: "" }; }, mounted() { this.timer1 = setInterval(() => { this.queryPayStatusInfo(); }, 5000); }, methods: { queryPayStatusInfo() { pay.queryPayStatus(this.orderNo).then(response => { if (response.data.success) { //Clear timer if payment is successful clearInterval(this.timer1); //Prompt for success this.$message({ type: "success", message: "Successful Payment!" }); //Jump to the course details page to watch the video this.$router.push({ path: "/course/" + this.payObj.course_id }); } }); } }