在线支付(易宝支付)

第三方支付方式:易宝支付。

支付过程图解:

在线支付(易宝支付)_第1张图片

相关资料:

易宝支付产品通用接口帮助文档 点击打开链接

使用步骤:

    ①src下面放入支付测试用的merchantInfo.properties(包含商家id【p1_MerId=10001126856】+加密解密用的keyValue【keyValue=69cl522AV6q613Ii4W6u8K6XuW8vM1N6bFgyv769220IuYe9u37N4y7rI4Pl】+支付成功后的重定向路径)
注意:下面的p8_Url是支付成功后供用户重定向返回网站或者服务器之间点对点通知支付成功用的。所以其ip是内网localhost时,只能通过用户重定向返回网站通知支付成功,易宝支付是无法通知网站支付成功的(除了用公网)。
1
p1_MerId=10001126856
2
keyValue=69cl522AV6q613Ii4W6u8K6XuW8vM1N6bFgyv769220IuYe9u37N4y7rI4Pl
3
p8_Url=http\://localhost\:8080/test/servlet/PaymentResponseServlet
    ②servlet准备  付款的金额totalMoney+订单id  数据转发给通用支付页面pay.jsp  (注意:页面中的单选框的值来自于易宝支付提供的“支付通道编码”,固定
1
<%@page language="java" import="java.util.*" contentType="text/html;charset=utf-8"%>
2
3
<html>
4
<head>
5
<title>在线支付title>
6
head>
7
8
<body>
9
    <form action="${pageContext.request.contextPath }/servlet/PayServlet" method="post">
10
        <table width="60%">
11
            <tr>
12
                <td bgcolor="#F7FEFF" colspan="4">
13
                
14
                订单号:<INPUT TYPE="text" NAME="orderId" value="20170815110723"> 
15
                支付金额:<INPUT TYPE="text" NAME="money" size="6" value="0.01">td>
16
            tr>
17
            <tr>
18
                <td>
19
                    <br/>
20
                td>
21
            tr>
22
            <tr>
23
                <td>请您选择在线支付银行td>
24
            tr>
25
            <tr>
26
                <td><INPUT TYPE="radio" NAME="pd_FrpId" value="ICBC-NET">工商银行td>
27
                <td><INPUT TYPE="radio" NAME="pd_FrpId" value="ABC-NET">农业银行td>
28
                <td><INPUT TYPE="radio" NAME="pd_FrpId" value="CCB-NET">建设银行td>
29
                <td><INPUT TYPE="radio" NAME="pd_FrpId" value="CMBCHINA-NET">招商银行td>
30
            tr>
31
            <tr>
32
                <td><INPUT TYPE="radio" NAME="pd_FrpId" value="CMBC-NET">中国民生银行总行td>
33
                <td><INPUT TYPE="radio" NAME="pd_FrpId" value="CEB-NET">光大银行td>
34
                <td><INPUT TYPE="radio" NAME="pd_FrpId" value="BOCO-NET">交通银行td>
35
                <td><INPUT TYPE="radio" NAME="pd_FrpId" value="SDB-NET">深圳发展银行td>
36
            tr>
37
            <tr>
38
                <td><INPUT TYPE="radio" NAME="pd_FrpId" value="BCCB-NET">北京银行td>
39
                <td><INPUT TYPE="radio" NAME="pd_FrpId" value="CIB-NET">兴业银行td>
40
                <td><INPUT TYPE="radio" NAME="pd_FrpId" value="SPDB-NET">上海浦东发展银行td>
41
                <td><INPUT TYPE="radio" NAME="pd_FrpId" value="ECITIC-NET">中信银行td>
42
            tr>
43
            <tr>
44
                <td><INPUT TYPE="radio" NAME="pd_FrpId" value="POST-NET-B2C">中国邮政td>
45
                <td><INPUT TYPE="radio" NAME="pd_FrpId" value="BOC-NET-B2C">中国银行td>
46
            tr>
47
            <tr>
48
                <td>
49
                    <br/>
50
                td>
51
            tr>
52
            <tr>
53
                <td><input type="submit" value="进入银行支付" />td>
54
            tr>
55
        table>
56
    form>
57
body>
58
html>
    ③pay.jsp页面选择支付银行后,进入servlet,组织第三方易宝支付需要的数据,最后重定向到第三方提供的支付链接 https://www.yeepay.com/app-merchant-proxy/node  上。 
1
package com.cn.pay;
2
3
import java.io.IOException;
4
5
import javax.servlet.ServletException;
6
import javax.servlet.http.HttpServlet;
7
import javax.servlet.http.HttpServletRequest;
8
import javax.servlet.http.HttpServletResponse;
9
10
import com.cn.pay.utils.PaymentUtil;
11
import com.cn.pay.utils.PropertiesUtils;
12
13
/**
14
 * 按照第三方接入规范的要求,组织数据
15
 * @author liuzhiyong
16
 *
17
 */
18
public class PayServlet extends HttpServlet {
19
20
    public void doGet(HttpServletRequest request, HttpServletResponse response)
21
            throws ServletException, IOException {
22
        
23
        String  p0_Cmd = "Buy"; //业务类型   固定值“Buy” .
24
        String  p1_MerId = PropertiesUtils.getPropertiesByKey("p1_MerId");//商户编号
25
        String  p2_Order = request.getParameter("orderId");// 商户订单号
26
        String  p3_Amt = request.getParameter("money");// 支付金额
27
        String  p4_Cur = "CNY"; // 固定值 ”CNY”.
28
        String  p5_Pid = "goodName"; // 商品名称
29
        String  p6_Pcat = ""; // 商品种类
30
        String  p7_Pdesc = ""; // 商品描述
31
        String  p8_Url = PropertiesUtils.getPropertiesByKey("p8_Url"); // 商户接收支付成功数据的地址
32
        String  p9_SAF = "1"; // 送货地址   为“1”: 需要用户将送货地址留在易宝支付系统;为“0”: 不需要,默认为 ”0”.
33
        String  pa_MP = ""; // 商户扩展信息
34
        String  pd_FrpId = request.getParameter("pd_FrpId"); // 支付通道编码
35
        String  pr_NeedResponse = "1"; //固定值为“1”: 需要应答机制; 收到易宝支付服务器点对点支付成功通知,必须回写以”success”(无关大小写)开头的字符串,即使您收到成功通知时发现该订单已经处理过,也要正确回写”success”,否则易宝支付将认为您的系统没有收到通知,启动重发机制,直到收到”success”为止。 
36
        String  hmac = PaymentUtil.buildHmac(p0_Cmd, p1_MerId, p2_Order, p3_Amt, p4_Cur, p5_Pid, p6_Pcat, p7_Pdesc, p8_Url, p9_SAF, pa_MP, pd_FrpId, pr_NeedResponse, PropertiesUtils.getPropertiesByKey("keyValue")); // 签名数据
37
        
38
        /**
39
         * 把组织好的数据重定向到正式请求地址:https://www.yeepay.com/app-merchant-proxy/node 
40
            商户:把交易信息明文加密--->密文    然后把明文和密文都交给发送给第三方易宝
41
                  第三方易宝拿到数据后,把传过来的明文和传过来密文比较,
42
                   如果数据相同,则说明没有被篡改 (易宝与商家加密时都用的商户注册时给的相同key)    
43
         */
44
        response.sendRedirect("https://www.yeepay.com/app-merchant-proxy/node?" +
45
                "p0_Cmd="+p0_Cmd+"&p1_MerId="+p1_MerId+"&p2_Order="+p2_Order+"&p3_Amt="+p3_Amt+"&p4_Cur="+p4_Cur+
46
                "&p5_Pid="+p5_Pid+"&p6_Pcat="+p6_Pcat+"&p7_Pdesc="+p7_Pdesc+"&p8_Url="+p8_Url+"&p9_SAF="+p9_SAF+
47
                "&pa_MP="+pa_MP+"&pd_FrpId="+pd_FrpId+"&pr_NeedResponse="+pr_NeedResponse+"&hmac="+hmac);
48
    }
49
50
    public void doPost(HttpServletRequest request, HttpServletResponse response)
51
            throws ServletException, IOException {
52
53
        this.doGet(request, response);
54
    }
55
56
}
    读取properties文件时用到的自定义工具PropertiesUtils.java
1
package com.cn.pay.utils;
2
3
import java.util.ResourceBundle;
4
5
public class PropertiesUtils {
6
7
    private static ResourceBundle bundle;
8
    
9
    //加载一次配置文件
10
    static{
11
        bundle = ResourceBundle.getBundle("merchantInfo");
12
    }
13
    
14
    public static String getPropertiesByKey(String key){
15
        
16
        return bundle.getString(key);
17
    }
18
}
19
     ③只有当用户付款成功后,第三方易宝支付会通知用户(浏览器重定向)和商户(服务器点对点通讯)。这时,系统再进行付款成功后的业务逻辑处理(重定向的url在merchantInfo.properties配置中)。
1
package com.cn.pay;
2
3
import java.io.IOException;
4
import java.io.PrintWriter;
5
6
import javax.servlet.ServletException;
7
import javax.servlet.http.HttpServlet;
8
import javax.servlet.http.HttpServletRequest;
9
import javax.servlet.http.HttpServletResponse;
10
11
import com.cn.pay.utils.PaymentUtil;
12
import com.cn.pay.utils.PropertiesUtils;
13
14
/**
15
 * 接受第三方的支付结果:处理自己的订单
16
 * @author liuzhiyong
17
 *
18
 */
19
public class PaymentResponseServlet extends HttpServlet {
20
21
    public void doGet(HttpServletRequest request, HttpServletResponse response)
22
            throws ServletException, IOException {
23
24
        response.setContentType("text/html;charset=utf-8");
25
        PrintWriter out = response.getWriter();
26
        
27
        String p1_MerId =  request.getParameter("p1_MerId");//商户编号
28
        String r0_Cmd =  request.getParameter("r0_Cmd");// 业务类型 返回固定值 "Buy"
29
        String r1_Code =  request.getParameter("r1_Code");// 支付结果 "1"代表成功
30
        String r2_TrxId =  request.getParameter("r2_TrxId");// 易宝支付交易流水号
31
        String r3_Amt =  request.getParameter("r3_Amt");// 支付金额
32
        String r4_Cur =  request.getParameter("r4_Cur");// 交易币种 返回时是"RMB"
33
        String r5_Pid =  request.getParameter("r5_Pid");// 商品名称
34
        String r6_Order =  request.getParameter("r6_Order");// 商户订单号
35
        String r7_Uid =  request.getParameter("r7_Uid");// 易宝支付会员ID
36
        String r8_MP =  request.getParameter("r8_MP");// 商户扩展信息
37
        String r9_BType =  request.getParameter("r9_BType");// 交易结果返回类型 为“1”: 浏览器重定向; 为“2”: 服务器点对点通讯.
38
        String hmac =  request.getParameter("hmac");//签名数据
39
        
40
        String rp_PayDate =  request.getParameter("r9_BType");//  支付成功时间  该返回参数不参与到hmac校验,范例中没有收录,可根据您的需要自行添加.
41
        
42
        /**
43
         * 数据校验是否正确
44
        易宝第三方:把交易信息明文加密--->密文    然后把明文和密文都交给发送给商户
45
              商户拿到数据后,把传过来的明文和传过来密文比较,
46
               如果数据相同,则说明没有被篡改 (商家与易宝加密时都用的商户注册时给的相同key)    
47
         */
48
        boolean flag = PaymentUtil.verifyCallback(hmac, p1_MerId, r0_Cmd, r1_Code, r2_TrxId, r3_Amt, r4_Cur, r5_Pid, r6_Order, r7_Uid, r8_MP, r9_BType, PropertiesUtils.getPropertiesByKey("keyValue"));
49
        
50
        if(!flag){//数据不一致
51
            out.write("交易失败!可能存在风险!");
52
            return;//结束
53
        }
54
        
55
        if("1".equals(r1_Code)){//说明支付成功
56
            //支付成功:找到订单,更改订单的支付状态。
57
            /**
58
             * 只有支付成功时易宝支付才会通知商户。支付成功回调有两种,都会以GET形式通知到在线支付请求参数中的p8_Url上:■ 浏览器重定向■ 服务器点对点通讯
59
                关于两种通知和业务处理说明:如果用户在支付成功后,并没有通知商家而是直接关闭了重定向的窗口,那么重定向就不会通知到商户,不管用户是否重定向通知到商户,
60
                服务器点对点通知都会通知到商户,所以在callback页中r9_btype=1和r9_btype=2的两种通知类型中都要进行业务处理。
61
                并注意处理重复订单的问题,以防两次通知都处理了相同的业务造成损失。 
62
                应答机制是指当贵公司系统收到易宝支付的支付成功数据通知(服务器点对点通讯形式)时,必须回写以“success”开头的stream,易宝支付收到该stream,便认为贵公司已收到;否则将继续发送通知,直至收到。
63
             */
64
            if("1".equals(r9_BType)){//服务器点对点通讯.
65
                System.out.println("#################交易成功");
66
                out.write("<h2>订单号:<span style='color:red;'>"+r6_Order+"span>,合计:<span style='color:red;'>"+r3_Amt+"span>元,交易成功!<h2>");
67
                /**
68
                 * 以下是处理交易成功后的业务逻辑,注意处理重复订单的问题,以防两次通知都处理了相同的业务造成损失。
69
                 */
70
            }
71
            if("2".equals(r9_BType)){//服务器点对点通讯.
72
                out.write("success");//回写以“success”开头的stream,易宝支付收到该stream,便认为贵公司已收到;否则将继续发送通知,直至收到。
73
                /**
74
                 * 以下是处理交易成功后的业务逻辑,注意处理重复订单的问题,以防两次通知都处理了相同的业务造成损失。
75
                 */
76
            }
77
        }
78
    }
79
80
    public void doPost(HttpServletRequest request, HttpServletResponse response)
81
            throws ServletException, IOException {
82
83
        this.doGet(request, response);
84
    }
85
86
}
    
    第三方易宝支付自己的支付工具(加密+验证)PaymentUtil.java
1
package com.cn.utils;
2
3
4
import java.io.UnsupportedEncodingException;
5
import java.security.MessageDigest;
6
import java.security.NoSuchAlgorithmException;
7
import java.util.Arrays;
8
9
public class PaymentUtil {
10
11
    private static String encodingCharset = "UTF-8";
12
    
13
    /**
14
     * 生成hmac方法
15
     * 
16
     * @param p0_Cmd 业务类型
17
     * @param p1_MerId 商户编号
18
     * @param p2_Order 商户订单号
19
     * @param p3_Amt 支付金额
20
     * @param p4_Cur 交易币种
21
     * @param p5_Pid 商品名称
22
     * @param p6_Pcat 商品种类
23
     * @param p7_Pdesc 商品描述
24
     * @param p8_Url 商户接收支付成功数据的地址
25
     * @param p9_SAF 送货地址
26
     * @param pa_MP 商户扩展信息
27
     * @param pd_FrpId 银行编码
28
     * @param pr_NeedResponse 应答机制
29
     * @param keyValue 商户密钥
30
     * @return
31
     */
32
    public static String buildHmac(String p0_Cmd,String p1_MerId,
33
            String p2_Order, String p3_Amt, String p4_Cur,String p5_Pid, String p6_Pcat,
34
            String p7_Pdesc,String p8_Url, String p9_SAF,String pa_MP,String pd_FrpId,
35
            String pr_NeedResponse,String keyValue) {
36
        StringBuilder sValue = new StringBuilder();
37
        // 业务类型
38
        sValue.append(p0_Cmd);
39
        // 商户编号
40
        sValue.append(p1_MerId);
41
        // 商户订单号
42
        sValue.append(p2_Order);
43
        // 支付金额
44
        sValue.append(p3_Amt);
45
        // 交易币种
46
        sValue.append(p4_Cur);
47
        // 商品名称
48
        sValue.append(p5_Pid);
49
        // 商品种类
50
        sValue.append(p6_Pcat);
51
        // 商品描述
52
        sValue.append(p7_Pdesc);
53
        // 商户接收支付成功数据的地址
54
        sValue.append(p8_Url);
55
        // 送货地址
56
        sValue.append(p9_SAF);
57
        // 商户扩展信息
58
        sValue.append(pa_MP);
59
        // 银行编码
60
        sValue.append(pd_FrpId);
61
        // 应答机制
62
        sValue.append(pr_NeedResponse);
63
        
64
        return PaymentUtil.hmacSign(sValue.toString(), keyValue);
65
    }
66
    
67
    /**
68
     * 返回校验hmac方法
69
     * 
70
     * @param hmac 支付网关发来的加密验证码
71
     * @param p1_MerId 商户编号
72
     * @param r0_Cmd 业务类型
73
     * @param r1_Code 支付结果
74
     * @param r2_TrxId 易宝支付交易流水号
75
     * @param r3_Amt 支付金额
76
     * @param r4_Cur 交易币种
77
     * @param r5_Pid 商品名称
78
     * @param r6_Order 商户订单号
79
     * @param r7_Uid 易宝支付会员ID
80
     * @param r8_MP 商户扩展信息
81
     * @param r9_BType 交易结果返回类型
82
     * @param keyValue 密钥
83
     * @return
84
     */
85
    public static boolean verifyCallback(String hmac, String p1_MerId,
86
            String r0_Cmd, String r1_Code, String r2_TrxId, String r3_Amt,
87
            String r4_Cur, String r5_Pid, String r6_Order, String r7_Uid,
88
            String r8_MP, String r9_BType, String keyValue) {
89
        StringBuilder sValue = new StringBuilder();
90
        // 商户编号
91
        sValue.append(p1_MerId);
92
        // 业务类型
93
        sValue.append(r0_Cmd);
94
        // 支付结果
95
        sValue.append(r1_Code);
96
        // 易宝支付交易流水号
97
        sValue.append(r2_TrxId);
98
        // 支付金额
99
        sValue.append(r3_Amt);
100
        // 交易币种
101
        sValue.append(r4_Cur);
102
        // 商品名称
103
        sValue.append(r5_Pid);
104
        // 商户订单号
105
        sValue.append(r6_Order);
106
        // 易宝支付会员ID
107
        sValue.append(r7_Uid);
108
        // 商户扩展信息
109
        sValue.append(r8_MP);
110
        // 交易结果返回类型
111
        sValue.append(r9_BType);
112
        String sNewString = PaymentUtil.hmacSign(sValue.toString(), keyValue);
113
        return sNewString.equals(hmac);
114
    }
115
    
116
    /**
117
     * @param aValue
118
     * @param aKey
119
     * @return
120
     */
121
    public static String hmacSign(String aValue, String aKey) {
122
        byte k_ipad[] = new byte[64];
123
        byte k_opad[] = new byte[64];
124
        byte keyb[];
125
        byte value[];
126
        try {
127
            keyb = aKey.getBytes(encodingCharset);
128
            value = aValue.getBytes(encodingCharset);
129
        } catch (UnsupportedEncodingException e) {
130
            keyb = aKey.getBytes();
131
            value = aValue.getBytes();
132
        }
133
134
        Arrays.fill(k_ipad, keyb.length, 64, (byte) 54);
135
        Arrays.fill(k_opad, keyb.length, 64, (byte) 92);
136
        for (int i = 0; i < keyb.length; i++) {
137
            k_ipad[i] = (byte) (keyb[i] ^ 0x36);
138
            k_opad[i] = (byte) (keyb[i] ^ 0x5c);
139
        }
140
141
        MessageDigest md = null;
142
        try {
143
            md = MessageDigest.getInstance("MD5");
144
        } catch (NoSuchAlgorithmException e) {
145
146
            return null;
147
        }
148
        md.update(k_ipad);
149
        md.update(value);
150
        byte dg[] = md.digest();
151
        md.reset();
152
        md.update(k_opad);
153
        md.update(dg, 0, 16);
154
        dg = md.digest();
155
        return toHex(dg);
156
    }
157
158
    public static String toHex(byte input[]) {
159
        if (input == null)
160
            return null;
161
        StringBuffer output = new StringBuffer(input.length * 2);
162
        for (int i = 0; i < input.length; i++) {
163
            int current = input[i] & 0xff;
164
            if (current < 16)
165
                output.append("0");
166
            output.append(Integer.toString(current, 16));
167
        }
168
169
        return output.toString();
170
    }
171
172
    /**
173
     * 
174
     * @param args
175
     * @param key
176
     * @return
177
     */
178
    public static String getHmac(String[] args, String key) {
179
        if (args == null || args.length == 0) {
180
            return (null);
181
        }
182
        StringBuffer str = new StringBuffer();
183
        for (int i = 0; i < args.length; i++) {
184
            str.append(args[i]);
185
        }
186
        return (hmacSign(str.toString(), key));
187
    }
188
189
    /**
190
     * @param aValue
191
     * @return
192
     */
193
    public static String digest(String aValue) {
194
        aValue = aValue.trim();
195
        byte value[];
196
        try {
197
            value = aValue.getBytes(encodingCharset);
198
        } catch (UnsupportedEncodingException e) {
199
            value = aValue.getBytes();
200
        }
201
        MessageDigest md = null;
202
        try {
203
            md = MessageDigest.getInstance("SHA");
204
        } catch (NoSuchAlgorithmException e) {
205
            e.printStackTrace();
206
            return null;
207
        }
208
        return toHex(md.digest(value));
209
210
    }
211
}   

支付演示

pay.jsp支付页面,选择支付银行
在线支付(易宝支付)_第2张图片
进入相应银行网站
   在线支付(易宝支付)_第3张图片
输入相应短信验证(不同银行过程不同)
在线支付(易宝支付)_第4张图片
银行引导用户访问第三方易宝支付,携带相应支付完成信息,跳转到电商网站,提示信息( 完成支付成功后的逻辑业务)
 

你可能感兴趣的:(在线支付(易宝支付))