I have been studying Alipay’s QR code payment a while ago. I have to say that the Alipay document is really bad (at least it was from Mengbi when I first read it). The examples above the document look completely different from the examples in the demo. Often, the examples above the document are very simple, while the code of demo is very complicated, so I didn't know which code to use at the beginning. Later, I carefully looked at the code in the demo package and found that the interfaces of the document examples were also called. Only then did I realize that they were the same thing, but demo only wrapped the interfaces of the document.
First, apply for an Alipay account of a company. This account has a pid, and you need to add an application to this account. Each application has an appid, and a public and private key. Public and private keys can be generated through tools provided by Alipay. In addition, Java developers need to use private keys in pkcs6 format. If the application needs to use the scanning function, it is necessary to add the option of in-person payment in the application, which requires signing a contract. After signing the in-person payment function, it cannot be used directly because the application needs to be online before it can be used. Therefore, you can use the sandbox version of the application during development. Alipay provides the sandbox version of the gateway, Alipay public key, pid and appid, which need to be modified during configuration.
The code can directly use the code in the demo, first import the API provided by Alipay in the project (note that it is not the demo code), and then import the demo code, as shown in the figure:
This com.alipay.demo.trade.Main file can be run directly, but a resource file needs to be configured:
# Alipay gateway name, partnerId and appId# This is the gateway for the sandbox environment open_api_domain = https://openapi.alipaydev.com/gateway.domcloud_api_domain = http://mcloudmonitor.com/gateway.do# This is the merchant UIDpid for the sandbox environment = 2088102172329883# Please fill in the APPIDappid for your sandbox environment in person here = 2016082000300485# RSA private key, public key and Alipay public key # Please fill in your merchant private key here and transfer to PKCS8 format private_key = MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBAMKXZrFR+rnvYgBs9qz2cE1mCSIBReaqan+5Pf5+02Hyj4HzcNTTWqHFm91IH3wYPyhpM7XlbgJ5yWJtgC4g1lz75r8a+UCyuxP8by1LV/44Gi/TIfLSgATfQ73OcM9imXocRdYz2ZCwqi1gV+b3UDoy/Da5w07gRWizFzS6Vq 1rAgMBAAECgYEAqHHc4GRBsRCKeinYtK1Vhqcj0Yg11Lvy85z3si0fNY26dvs8R5gFydzC/Mx5f8rNPUUYUHQn+4CqOR3D/c291X1iToV2NEVLHeJrOUDknP4oQriqt2w9pZ8rzwZp2jcWvRVUF4zTpEiMppmORP6spRfX6DLZg29SFI6GZWu6TkCQQDp3mim1BhuS3YONEZgqC69zn0/DGOFk eIx0S18qAu1X4I1FEjVTkY4HPdwihpgYajm0UFg1lk8mTiunHpZRCnAkEA1QF6U1AKjM6zsVdEnRXEDTCC75uVJGSYFJWHHx9Pjyd9vX8nSZV0Z0U4V0ZG0n0yvHj5LRO6U5FCqFRw1WixnQJBALmCKz8SvF/H9N6LiwmSPY6w5q82kNRlRc7wSceNspQT0wqL5+SACG98M0xXY5j1HmiOlHxg CTvyriXOwObivQcCQQCTNaNB4uZ3q/86R/KukbVd3DIRwLfRYAhO6Yxp8Oy+Je/bv/359+Vr3cXzYyldHZOr9/tVsPWr/Y9Q4JLemq1tAkEAlBU7+4EdzFap7e/FMgyKD5DmL8H2iAEuMRRCPL84GhFfK/7PSQ/40NgKxpTgY44NlElHXcRPw5CZu6gqdiNJOA==#Please fill in your merchant public_key here = MIGfMA0GCSqGSIbDQEBAQUAA4GNADCBiQKBgQDCl2axUfq572IAbPas9nBNZgkiAUXmqmp/uT3+ftNh8o+B83DU01qhxZvdSB98GD8oaTO15W4CeclibYAuINZc++a/GvlAsrsT/G8tS1f+OBov0yHy0oAE30O9znDPYpl6HEXWM9mQsKotYFfm91A6Mvw2ucNO4EVosxc0ulatawIDAQAB#This is the public key of the sandbox environment alipay_public_key = MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDIgHnOn7LLILlKETd6BFRJ0GqgS2Y3mn1wMQmyh9zEyWlz5p1zrahRahbXAfCfSqshSNfqOmAQzSHRVjCqjsAw1jyqrXaPdKBmr90DIpIxmIyKXv4GGAkPyJ/6FTFY99uhpiq0qadD/uSzQsefWo0aTvP/65zi3eof7TcZ32oWpwIDAQAB# Maximum number of queries and query interval (milliseconds) max_query_retry = 5query_duration = 5000# Maximum number of undoings and undoing intervals (ms) in person max_cancel_retry = 3cancel_duration = 2000# Transaction guarantee thread first scheduling delay and scheduling intervals (seconds) heartbeat_delay = 5heartbeat_duration = 900
Then run the Main.java file. As for the payment code for scanning code in our actual application, we can directly copy the test_trade_precreate() function in the Main.java file and create a function in the Controller:
@RequestMapping(value = "/pay/alipay", method = RequestMethod.POST) public Map<String, String> alipay(@RequestParam String amount, @RequestParam int userid) { Map<String, String> map = new HashMap<String, String>(); // (Required) The unique order number in the merchant website order system, with only 64 characters, can only contain letters, numbers, and underscores. // It is necessary to ensure that the merchant system cannot be repeated. It is recommended to generate it through the database sequence, String outTradeNo = "xxxxx" + System.currentTimeMillis() + (long)(Math.random() * 10000000L); // (Required) Order title, roughly describes the user's payment purpose. For example, "xxx brand xxx store pays in person and scans the code to consume" String subject = "pay"; // (Required) The total amount of the order is RMB 100 million, and cannot exceed RMB 100 million// If [discounted amount], [not discounted amount], and [total order amount] are transmitted at the same time, the following conditions must be met: [total order amount] = [discounted amount] + [not discounted amount] String totalAmount = amount; // (Optional) The order cannot be discounted amount, and can be configured with the merchant platform to configure discount activities. If the alcohol does not participate in the discount, the corresponding amount will be filled in this field// If the value is not transmitted, but [total order amount] and [discounted amount] are transmitted, the value defaults to [total order amount]-[discounted amount] String undiscountableAmount = "0"; // Seller's Alipay account ID is used to support payment to different payment accounts under a contract account (pay to the Alipay account corresponding to sellerId) // If this field is empty, it defaults to the PID of the merchant signed with Alipay, that is, the PID corresponding to the appid String sellerId = "2088102172329883"; // Order description, you can describe the transaction or product in a detailed manner, such as filling in "2 purchases of 2 items in total 15.00 yuan" String body = "3 purchases of 3 items in total 20.00 yuan"; // Merchant operator number, add this parameter to do sales statistics for merchant operator String operatorId = "test_operator_id"; // (Required) Merchant store number, through the store number and the merchant backend, you can configure the discount information to the store accurately. For details, please consult Alipay technical support String storeId = "2088102172329883"; // Business expansion parameters, currently you can add the system provider number assigned by Alipay (through the setSysServiceProviderId method). For details, please consult Alipay technical support ExtendParams extendParams = new ExtendParams(); extendParams.setSysServiceProviderId("2088100200300400500"); // Payment timeout, defined as 120 minutes String timeoutExpress = TIMEOUT;// // Product details list, you need to fill in the details of the purchase product, // List<GoodsDetail> goodsDetailList = new ArrayList<GoodsDetail>();// // Create a product information, the parameters are the product id (using national standard), name, unit price (unit in points), and quantity. If you need to add product categories, please refer to GoodsDetail// GoodsDetail goods1 = GoodsDetail.newInstance("goods_id001", "xxx small bread", 1000, 1);// // Add to the product details list after creating a product // goodsDetailList.add(goods1);//// // Continue to create and add the first product information. The product purchased by the user is "Black Toothbrush", with a unit price of 5.00 yuan. I purchased two pieces // GoodsDetail goods2 = GoodsDetail.newInstance("goods_id002", "xxx Toothbrush", 500, 2);// goodsDetailList.add(goods2); // Create a scan code to pay the request builder, set the request parameters AlipayTradePrecreateRequestBuilder builder = new AlipayTradePrecreateRequestBuilder() .setSubject(subject) .setTotalAmount(totalAmount) .setOutTradeNo(outTradeNo) .setUndiscountableAmount(undiscountableAmount) .setSellerId(sellerId) .setBody(body) .setOperatorId(operatorId) .setStoreId(storeId) .setExtendParams(extendParams) .setTimeoutExpress(timeoutExpress) .setNotifyUrl("http://xxx.xx.xxx.xxx:8080/baobiao/pay/notify");//Alipay server actively notifies the page http path specified in the merchant server. Set as needed. Here we set an interface we wrote ourselves. We will introduce it later. // .setGoodsDetailList(goodsDetailList); AlipayF2FPrecreateResult result = tradeService.tradePrecreate(builder); switch (result.getTradeStatus()) { case SUCCESS: log.info("Alipay pre-ordered successfully: )"); System.out.println("Alipay pre-ordered successfully: )"); AlipayTradePrecreateResponse response = result.getResponse();// dumpResponse(response);// System.out.println(response.getBody());// // // It needs to be modified to the path on the running machine// String filePath = String.format("/Users/liuyangkly/qr-%s.png", response.getOutTradeNo());// log.info("filePath:" + filePath);// ZxingUtils.getQRCodeImge(response.getQrCode(), 256, filePath);// System.out.println(response.getQrCode()); // Generate an order and insert the database BaobiaoOrder order = new BaobiaoOrder(userid, outTradeNo, "", Double.parseDouble(amount), new Date(), 1); baobiaoOrderService.insertOrder(order); map.put("status", "true"); map.put("qrcode", response.getQrCode()); //Return to the client QR code map.put("outtradeno", outTradeNo); return map; case FAILED: log.error("Alipay pre-order failed!!!"); System.out.println("Alipay pre-order failed!!!"); System.out.println(result.getResponse().getBody()); break; case UNKNOWN: log.error("System exception, pre-order status unknown!!!"); System.out.println("System exception, pre-order status unknown!!!"); break; default: log.error("Unsupported transaction status, transaction returns exception!!!"); System.out.println("Unsupported transaction status, transaction returns exception!!!"); break; } map.put("status", "False"); map.put("msg", "The system has an exception, please try again later! "); return map; }The logic is that the user will scan the code on his mobile phone to pay Alipay, and then after Alipay receives it, it will send a message of successful payment to us to set notify_url, as shown below:
@RequestMapping(value = "/pay/notify", method = RequestMethod.POST) public String notifyResult(HttpServletRequest request, HttpServletResponse response) { log.info("Received Alipay asynchronous notification!"); Map<String, String> params = new HashMap<String, String>(); //Retrieve all parameters to verify the signature Enumeration<String> parameterNames = request.getParameterNames(); while (parameterNames.hasMoreElements()) { String parameterName = parameterNames.nextElement(); params.put(parameterName, request.getParameter(parameterName)); } boolean signVerified; try { signVerified = AlipaySignature.rsaCheckV1(params, Configs.getAlipayPublicKey(), "UTF-8"); } catch (AlipayApiException e) { e.printStackTrace(); return "failed"; } if (signVerified) { String outtradeno = params.get("out_trade_no"); log.info(outtradeno + "Order callback notification.");// System.out.println("Verify signature successfully!"); log.info("Verify signature successfully!"); // If the appid in the parameter is different from the appid filled in, it is an exception notification if (!Configs.getAppid().equals(params.get("app_id")))) { log.warn("Different from the appid at the time of payment, this is an exception notification and should be ignored!"); return "failed"; } //Find the order corresponding to the order number in the database and compare its amount with the amount in the database. If it doesn't match, it will also notify the exception of BaobiaoOrder order = baobiaoOrderService.findOrderByOuttradeno(outtradeno); if (order == null) { log.warn(outtradeno + "Check this order without checking! "); return "failed"; } if (order.getAmount() != Double.parseDouble(params.get("total_amount"))) { log.warn("Different from the amount at the time of payment, this is an exception notification and should be ignored!"); return "failed"; } if (order.getStatus() == BaobiaoOrder.TRADE_SUCCESS) return "success"; //If the order has been paid successfully, ignore this notification String status = params.get("trade_status"); if (status.equals("WAIT_BUYER_PAY")) { //If the status is waiting for user payment if (order.getStatus() != BaobiaoOrder.WAIT_BUYER_PAY) baobiaoOrderService.modifyTradeStatus(BaobiaoOrder.WAIT_BUYER_PAY, outtradeno); } else if (status.equals("TRADE_CLOSED")) { //If the status is unpaid transaction timeout closed, or the payment is fully refunded if (order.getStatus() != BaobiaoOrder.TRADE_CLOSED) baobiaoOrderService.modifyTradeStatus(BaobiaoOrder.TRADE_CLOSED, outtradeno); } else if (status.equals("TRADE_SUCCESS") || status.equals("TRADE_FINISHED")) { //If the status is paid successfully if (order.getStatus() != BaobiaoOrder.TRADE_SUCCESS) baobiaoOrderService.modifyTradeStatus(BaobiaoOrder.TRADE_SUCCESS, outtradeno); } else { baobiaoOrderService.modifyTradeStatus(BaobiaoOrder.UNKNOWN_STATE, outtradeno); } log.info(outtradeno + "The status of the order has been modified to " + status); } else { //If the verification signature does not pass return "failed"; } return "success"; }This is probably the case, but there are fewer notifications of successful payment to the client, and there are also some security issues.
Finally, let’s summarize the problems encountered in this process:
1. The QR code returned by Alipay cannot be opened directly in the browser, but must be used to convert QR codes to generate QR codes, or you can view them through the cli.im website.
2. The QR code generated by the Alipay sandbox environment can only be scanned using the sandbox version of Alipay mobile phone. If the normal version of Alipay scans, the QR code will expire and other errors will occur.
3. If you cannot receive the asynchronous notification sent by Alipay after payment, you can use postman and other tools to check whether the notify_url you filled in can be accessed using the public IP.
4. If you encounter the problem of insufficient isv permissions, it is because there is no contract signing or the application has not added corresponding functions, and the application cannot be used without online. You can choose a sandbox application during development.
5. When registering the sandbox version of Alipay mobile phone, you can contact customer service to ask for an account
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.