In this section, we will first write a simple demo to test the Yibao payment process. After familiarizing with this process, we will do actual development. Because it is a demo, I did not consider some design patterns, but just directly implement the payment function. To implement payment functions, Yibao requires the API provided to us. So the question is, the most important thing when using a third-party payment platform is to obtain the platform's API. We must first obtain their API and development documents, and then we can do further development.
1. Obtain Yibao's API
The first step to obtaining the API is to register an account on Yibao. This account is the merchant’s account. After the buyer pays, he will deposit the money into the account, and the merchant will withdraw it to the bank card by himself. Yibao will charge a certain handling fee during the withdrawal process. This is Yibao's profit model. However, the prerequisite for successful registration is that you have to have a website, or a company, bara, bara, etc. Anyway, you have to be qualified to apply. Yibao will review this point. Only when you meet it will allow you to register and provide you with their interface. Not everyone can register. I used it as well as others registered, but I didn't have anything myself... I couldn't register... I know this, but generally when developing in a company, there wouldn't be this problem. There must be an account. The most important thing is to master the development process and related technologies.
2. Test the payment process
With the official API and technical documents, you can start developing. Here we mainly write a simple demo to test the process of Yibao payment. The structure of the demo is very simple, a servlet, a filter, two jsp pages and an encrypted tool class. servlet deals with Yibao server side. We do some processing related to Yibao interface. Filter is used to deal with possible Chinese garbled problems. One of the two jsp is the front-end page.
Let’s first analyze the payment request process, as shown below:
OK, let's analyze the relevant code in the demo in detail:
2.1 Front Desk Test Page
First, let’s take a look at the specific code of the front desk page index.jsp
<%@ page language="java" pageEncoding="UTF-8"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html> <head> <title>Front Office Home</title> </head> <body> <h1>Online Payment Demo</h1> <form action="${pageContext.request.contextPath }/servlet/PayServlet" method="post"> The order number for this shopping<input type="text" name="p2_Order" /><br> money<input type="text" name="p3_Amt" value="0.01"/><br> Industrial and Commercial Bank of China<input type="radio" value="ICBC-NET" name="pd_FrpId"> Construction Bank<input type="radio" value="CCB-NET" name="pd_FrpId"><br> <input type="submit" value="submit" /> <input type="hidden" value="pay" name="status"/> </form> </body></html>From the above jsp page, we can see that the name attribute values in these input tags are very strange, pi_function (i=0,1,2,…,9), and of course i have other values. This requires referring to Yibao's official document. These names represent corresponding attributes and will be passed to the sevlet for processing. Regarding these attribute values, I have a picture as follows:
Some of these parameter names are transmitted from the front desk in actual projects, such as the order number written above, how much does it cost to pay, and these will be taken over when the order is confirmed. If other parameters are required, they need to be specified in the servlet. If the fields are not required, they can be empty. The empty here is not null, but "", which will be mentioned in the servlet later.
Let’s take a look at the corresponding value values in the two banks. Yibao will provide the value values of all banks it supports. These are fixed and cannot be modified. Here are two banks to test the effect.
The last hidden field is used to make a judgment in the servlet. Whether it is a payment or a return after the payment is successful, it will be explained in the sevlet below.
2.2 Servlet handles requests
The servlet mainly handles related requests to Yibao. There are two parts of the content. One part is to send plain text and cipher text to Yibao, and the other part is to judge the plain text and cipher text sent by Yibao. Let's take a look at the specific implementation code in the demo:
public class PayServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String status = request.getParameter("status"); if (status.equals("pay")) { // The hidden field in index.jsp is paid, so the payment part is processed // The encryption key is used in the encryption algorithm and provided by the payment intermediary. Each merchant has a unique String keyValue = "w0P75wMZ203fr46r5i70V556WHFa94j14yW5J6vuh4yo3nRl5jsqF3c41677"; // 1: Assign values to parameters. These parameters (i.e. plain text) are defined in the document provided by Yibao. We cannot change the name String p0_Cmd = formatString("Buy"); String p1_MerId = formatString("10000940764"); String p2_Order = formatString(request.getParameter("p2_Order")); String p3_Amt = formatString(request.getParameter("p3_Amt")); String p4_Cur = formatString("CNY"); String p5_Pid = ""; String p6_Pcat = ""; String p7_Pdesc = ""; String p8_Url = "http://www.tongji.edu.cn";//This is the page you jump to after payment is successful. You can set it as the homepage of the mall. This demo is enough to use the Tongji University homepage... String p9_SAF = "0"; String pa_MP = ""; String pd_FrpId = formatString(request.getParameter("pd_FrpId")); pd_FrpId = pd_FrpId.toUpperCase(); String pr_NeedResponse = "0"; String hmac = formatString(""); //hmac is used to store ciphertext/*All the plaintext above are wrapped with the formatString method. The method is below, mainly converting null to "" *Because null cannot be converted into ciphertext*// Solve data security issues: Encrypt the plaintext ---> ciphertext and then hand over both the plaintext and the ciphertext to Yibao// After Yibao gets the data, encrypt the transmitted plaintext and compare it with the transmitted ciphertext, // If the equal data has not been tampered with (the merchant and Yibao both use the same key when encrypting) // Append plaintext data to StringBuffer, note that the order of appending cannot be changed, otherwise the generated ciphertext will be different. // You must write strictly according to the name of Yibao's official document, because Yibao is added according to the order in the document. InfoBuffer = new StringBuffer(); infoBuffer.append(p0_Cmd); infoBuffer.append(p1_MerId); infoBuffer.append(p2_Order); infoBuffer.append(p3_Amt); infoBuffer.append(p4_Cur); infoBuffer.append(p5_Pid); infoBuffer.append(p6_Pcat); infoBuffer.append(p7_Pdesc); infoBuffer.append(p8_Url); infoBuffer.append(p9_SAF); infoBuffer.append(pa_MP); infoBuffer.append(pd_FrpId); infoBuffer.append(pr_NeedResponse); // The encrypted ciphertext is stored in hmac, and the encryption algorithm Yibao will provide it, because it also has to use the same algorithm hmac = DigestUtil.hmacSign(infoBuffer.toString(), keyValue); // Store both plain text and cipher text in request.setAttribute request.setAttribute("p0_Cmd", p0_Cmd); request.setAttribute("p1_MerId", p1_MerId); request.setAttribute("p2_Order", p2_Order); request.setAttribute("p3_Amt", p3_Amt); request.setAttribute("p4_Cur", p4_Cur); request.setAttribute("p5_Pid", p5_Pid); request.setAttribute("p6_Pcat", p6_Pcat); request.setAttribute("p7_Pdesc", p7_Pdesc); request.setAttribute("p8_Url", p8_Url); request.setAttribute("p9_SAF", p9_SAF); request.setAttribute("pa_MP", pa_MP); request.setAttribute("pd_FrpId", pd_FrpId); request.setAttribute("pr_NeedResponse", pr_NeedResponse); request.setAttribute("hmac", hmac); System.out.println("hmac-->" + hmac); //Skip to reqpay.jsp and submit this information to Yibao request.getRequestDispatcher("/reqpay.jsp").forward(request, response); } else if (status.equals("success")) {//What is coming from Yibao is success, processing returns verification part PrintWriter out = response.getWriter(); String keyValue = "w0P75wMZ203fr46r5i70V556WHFa94j14yW5J6vuh4yo3nRl5jsqF3c41677"; // Get all plaintext String r0_Cmd = formatString(request.getParameter("r0_Cmd")); String p1_MerId = request.getParameter("p1_MerId"); String r1_Code = formatString(request.getParameter("r1_Code")); String r2_TrxId = formatString(request.getParameter("r2_TrxId")); String r3_Amt = formatString(request.getParameter("r3_Amt")); String r4_Cur = formatString(request.getParameter("r4_Cur")); String r5_Pid = new String(formatString(request.getParameter("r5_Pid")).getBytes("iso-8859-1"), "UTF-8"); String r6_Order = formatString(request.getParameter("r6_Order")); String r7_Uid = formatString(request.getParameter("r7_Uid")); String r8_MP = new String(formatString( request.getParameter("r8_MP")).getBytes("iso-8859-1"), "UTF-8"); String r9_BType = formatString(request.getParameter("r9_BType")); // Append data to plaintext String hmac = formatString(request.getParameter("hmac")); StringBuffer infoBuffer = new StringBuffer(); infoBuffer.append(p1_MerId); infoBuffer.append(r0_Cmd); infoBuffer.append(r1_Code); infoBuffer.append(r2_TrxId); infoBuffer.append(r3_Amt); infoBuffer.append(r4_Cur); infoBuffer.append(r5_Pid); infoBuffer.append(r6_Order); infoBuffer.append(r7_Uid); infoBuffer.append(r8_MP); infoBuffer.append(r9_BType); // Encrypt the returned plaintext String md5 = DigestUtil.hmacSign(infoBuffer.toString(), keyValue); // Determine whether the encrypted ciphertext is equal to the transmitted data signature boolean isOK = md5.equals(hmac); if (isOK && r1_Code.equals("1")) {//r1_Code is 1 to indicate success//Change the successful order status to paid, and display the payment success information to the user//Call the email service interface, SMS sending service, etc.//Print here~ out.println("Order number is:" + r6_Order + "Payment amount is:" + r3_Amt); } else { out.println("fail !!!"); } } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } String formatString(String text) { if (text == null) { return ""; } return text; }}2.3 Encryption Algorithm
The encryption algorithm used to convert plain text to ciphertext is provided by Yibao. We only need to use it to convert plain text to ciphertext. The algorithm is as follows:
public class DigestUtil { private static String encodingCharset = "UTF-8"; public static String hmacSign(String aValue, String aKey) { byte k_ipad[] = new byte[64]; byte k_opad[] = new byte[64]; byte keyb[]; byte value[]; try { keyb = aKey.getBytes(encodingCharset); value = aValue.getBytes(encodingCharset); } catch (UnsupportedEncodingException e) { keyb = aKey.getBytes(); value = aValue.getBytes(); } Arrays.fill(k_ipad, keyb.length, 64, (byte) 54); Arrays.fill(k_opad, keyb.length, 64, (byte) 92); for (int i = 0; i < keyb.length; i++) { k_ipad[i] = (byte) (keyb[i] ^ 0x36); k_opad[i] = (byte) (keyb[i] ^ 0x5c); } MessageDigest md = null; try { md = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { return null; } md.update(k_ipad); md.update(value); byte dg[] = md.digest(); md.reset(); md.update(k_opad); md.update(dg, 0, 16); dg = md.digest(); return toHex(dg); } public static String toHex(byte input[]) { if (input == null) return null; StringBuffer output = new StringBuffer(input.length * 2); for (int i = 0; i < input.length; i++) { int current = input[i] & 0xff; if (current < 16) output.append("0"); output.append(Integer.toString(current, 16)); } return output.toString(); } public static String getHmac(String[] args, String key) { if (args == null || args.length == 0) { return (null); } StringBuffer str = new StringBuffer(); for (int i = 0; i < args.length; i++) { str.append(args[i]); } return (hmacSign(str.toString(), key)); } /** * @param aValue * @return */ public static String digest(String aValue) { aValue = aValue.trim(); byte value[]; try { value = aValue.getBytes(encodingCharset); } catch (UnsupportedEncodingException e) { value = aValue.getBytes(); } MessageDigest md = null; try { md = MessageDigest.getInstance("SHA"); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return null; } return toHex(md.digest(value)); } // public static void main(String[] args) { // Parameter 1: plaintext (data to be encrypted) Parameter 2: key System.out.println(DigestUtil.hmacSign("11111", "abc")); System.out.println(DigestUtil.hmacSign("11111", "abd")); // Solve data security issues: Encrypt the plain text --->Secret text and the plain text to Yibao// After Yibao gets the data, encrypt the transmitted plain text and compare it with the transmitted cipher text. If the equal data has not been tampered with (the merchant and Yibao both use the same key when encrypting) }}I have not studied the encryption algorithm too much. It seems to be the second-generation md5 encryption algorithm. Anyway, just throw the plain text in it and it will definitely be encrypted into a ciphertext. Let’s take a look at the reqpay.jsp page:
<%@page language="java" contentType="text/html;charset=gbk"%><html> <head> <title>To YeePay Page </title> </head> <body> <form name="yeepay" action='https://www.yeepay.com/app-merchant-proxy/node' method='POST' target="_blank"> <input type='hidden' name='p0_Cmd' value='${requestScope.p0_Cmd}'> <input type='hidden' name='p1_MerId' value='${requestScope.p1_MerId}'> <input type='hidden' name='p2_Order' value='${requestScope.p2_Order}'> <input type='hidden' name='p3_Amt' value='${requestScope.p3_Amt}'> <input type='hidden' name='p4_Cur' value='${requestScope.p4_Cur}'> <input type='hidden' name='p5_Pid' value='${requestScope.p5_Pid}'> <input type='hidden' name='p6_Pcat' value='${requestScope.p6_Pcat}'> <input type='hidden' name='p7_Pdesc' value='${requestScope.p7_Pdesc}'> <input type='hidden' name='p8_Url' value='${requestScope.p8_Url}'> <input type='hidden' name='p9_SAF' value='${requestScope.p9_SAF}'> <input type='hidden' name='pa_MP' value='${requestScope.pa_MP}'> <input type='hidden' name='pa_MP' value='${requestScope.pa_MP}'> <input type='hidden' name='pa_MP' value='${requestScope.pa_MP}'> <input type='hidden' name='pd_FrpId' value='${requestScope.pd_FrpId}'> <input type="hidden" name="pr_NeedResponse" value="${requestScope.pr_NeedResponse}"> <input type='hidden' name='hmac' value='${requestScope.hmac}'> <input type='submit' /> </form> </body></html> In fact, this page is very simple. It is to pass the plain text and the cipher text to Yibao through the <form> form. Yibao's receiving url is https://www.yeepay.com/app-merchant-proxy/node . This is also provided by Yibao official, and we can write this one. In fact, there is only a submit button. Click the submit button to submit the plain text and cipher text. Let's take a look at the test results:
3. Test payment results
Simple test front desk index.jsp~~~:
After submitting, you will go to reqpay and jsp. The effect after clicking the submit button is as follows. We will test both ICBC and CCB:
There is no problem with the payment process. I originally planned to pay 1 cent to ICBC to see the results after the payment was completed, but I found that the U-Shield has expired because it is more convenient to use Alipay now... I didn't update the U-Shield, but I opened the e-Payment through ICBC, so I can also use e-Payment in the above interface, so I paid 1 cent generously~ The result is as follows:
Then it will jump to the page we specified before, that is, Tongji University... Okay, the test is completed, and the entire payment process is over!
This section mainly tests through a simple demo to see if it can be connected to the bank's payment interface. Now the test is fine, it has been connected, and you can just pay as usual later. Let’s introduce the simple demo. Then we will continue to develop the online payment module of our previous online mall project.
Original address: http://blog.csdn.net/eson_15/article/details/51447492
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.