1、在线支付概述

什么是在线支付呢?没错,就是在网上花钱!大家一定有过这样的经历。但是你可能不太了解在线支付的“内情”,下面我们来了解一下!

如果你现在开始经营一个电子商务网站,用户买了东西一定要支付,你的网站一定要可以连接各大银行了,然后在各大银行支付完成后,再返回到你的网站上显示“支付成功”!

这就是今天我们要做的事情,连接银行的网银系统完成支付。说专业一点,我们称之为“开发在线支付的网关”

2、两种在线支付的方式

在线支付一共有两种方式:

*电商直接与银行对接
*电商通过第三方支付平台与银行对接

电商直接与银行对接,这也要银行同意才行,但可惜的是,银行很“牛”,不是谁想与它对接都可以的。如果你的电商每日的资金流量够大,那么银行会和你对接,因为客户支付给电商的钱都存到了银行的帐户中!但是如果资金流量小,银行不会理你的!

当小网站资金量不足时,不能与银行对接,那么它们会选择与第三方支付公司合作。大家也都明白这是些什么公司,例如:支付宝、易宝、财富通、快钱等公司是国内比较有名的。它们这些公司可以与银行对接(因为资金够多),然后小电商与它们对接!但是第三方是要求收费的!第三方一般会收取电商1%的费用,不过不会收客户的钱。

通过上图大家可以了解到,在银行的页面上会显示出商城名称、RMB订单号、订单时间。。。,这些东西银行是怎么知道的,当然是电商传递给银行的。当电商与银行对接后,电商要给银行的页面传递银行页面需要的参数,所以银行的页面才能显示这些数据!

但是,我们的商城不能只可以对接一家银行吧!怎么也要对接BOC、CCB、ABC、ICBC四家吧!不同的银行需要的对接参数是不相同的,这说明我们在开发时要为不同的银行写不同的对接代码。这也是直接与银行对接的缺点!当然与银行直接对接也有好处,就是安全,没有手续费!

为不同的银行开发不同的代码(缺点);
安全(优点);
没有手续费(优点);
小电商银行不让对接(缺点)。

上图中已经说明,客户在电商的网站上点击确认支付后,会定向到第三方的网站,然后再由第三方与银行对接。这说明电商要传递给第三方参数!再由第三方把参数传递给银行。这种方式的好处是:只需要针对第三方开发即可,而不用再为每家银行提供参数。为每家银行提供参数的工作是第三方的任务了。但是,第三方不老可靠的,如果第三方倒闭了,人跑了,那你的钱就没了。因为客户支付的钱没有到你的银行帐户中,而是支付到了第三方的银行帐户中,而你是在第三方有一个帐户。而且第三方还要收手续费,一般是1%,这可不是小数字啊(真黑)。

3、通过第三方在线支付规则

电商想在第三方注册商户,需要向第三方提供ICP认证。ICP经营许可证是根据国家《互联网管理办法规定》,经营性网站必须办理的网站经营许可证,没有就属于非法经营。

我们不可能因为练习就去办理ICP!所以我们无法在第三方注册商户。不过我们已经有现成的在易宝注册的商户,所以这一步就可以忽略了。

当你在易宝注册成功后,易宝会给你如下几样东西:

在易宝的开户账号(即商户编码):10001126856
   易宝接入规范:一个chm文件
   对称加密算法类:PaymentUtil.java
   密钥:69cl522AV6q613Ii4W6u8K6XuW8vM1N6bFgyv769220IuYe9u37N4y7rI4Pl
在易宝接入规范中,我们可以查找到易宝的支付网关,其实就是一个URL,用来与易宝对接的一个网址:https://www.yeepay.com/app-merchant-proxy/node

在易宝接入规范中,还可以查找到易宝要求的参数,在电商与易宝对接时需要给支付网关传递这些参数:

正式请求地址:https://www.yeepay.com/app-merchant-proxy/node

这些参数需要追加到URL后面。

但是要注意,这些参数的值需要加密。加密的密钥和加密算法易宝都会提供!

其中p8_Url表示当支付成功后,返回到电商的哪个页面。这说明我们需要写一个显示结果的页面。第三方在支付成功后,会重定向到我们指定的返回页面,而且还会带给我们一些参数,我们的页面需要获取这些参数,显示在页面中。下面是第三方返回的参数:

4、开发第三方在线支付系统

步骤:

index.jsp页面:一个表单,提交到BuyServlet,表单项有:订单编号、付款金额、选择银行
BuyServlet:获取表单数据,准备连接第三方网关。因为在index.jsp页面中只给出3个参数,而第三方需要的参数有N多,页面没有给出的参数由BuyServlet补充。而且参数还需要加密,这也需要在BuyServlet中完成
BackServlet:当用户支付成功后,第三方会重定向到我们指定的返回页面,我们使用BackServlet作为返回页面,它用来接收第三方传递的参数,显示在页面中

因为已经有了在易宝的注册商号,所以我们就不用自己去注册商号了。所以这里使用易宝做为第三方支付平台来测试。因为我本人没有电商(必须通过ICP认证的电商),所以也不能在第三方注册商号。

我们现在使用的易宝商号是由传智播客提供的,巴巴运动网在易宝注册的商号。所以在测试时支付的钱都给了巴巴运动网在易宝注册的商号了。

第一步:index.jsp

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<form action="" method="post">
 订单号:<input type="text" name="p2_Order"/><br/>
 金 额:<input type="text" name="p3_Amt"/><br/>
 选择银行:<br/>
 <input type="radio" name="pd_FrpId" value="ICBC-NET-B2C"/>工商银行
 <img src="bank_img/icbc.bmp" align="middle"/>
 <input type="radio" name="pd_FrpId" value="BOC-NET-B2C"/>中国银行
 <img src="bank_img/bc.bmp" align="middle"/><br/><br/>
 <input type="radio" name="pd_FrpId" value="ABC-NET-B2C"/>农业银行
 <img src="bank_img/abc.bmp" align="middle"/>
 <input type="radio" name="pd_FrpId" value="CCB-NET-B2C"/>建设银行
 <img src="bank_img/ccb.bmp" align="middle"/><br/><br/>
 <input type="radio" name="pd_FrpId" value="BOCO-NET-B2C"/>交通银行
 <img src="bank_img/bcc.bmp" align="middle"/><br/>
 <input type="submit" value="确认支付"/>
</form>

每个银行对应的值:

第二步:BuyServlet.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public class BuyServlet extends HttpServlet {
 public void doPost(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException {
  request.setCharacterEncoding("utf-8");
  response.setContentType("text/html;charset=utf-8");
  String p0_Cmd = "Buy";// 业务类型,固定值为buy,即“买”
  String p1_MerId = "10001126856";// 在易宝注册的商号
  String p2_Order = request.getParameter("p2_Order");// 订单编号
  String p3_Amt = request.getParameter("p3_Amt");// 支付的金额
  String p4_Cur = "CNY";// 交易种币,固定值为CNY,表示人民币
  String p5_Pid = "";// 商品名称
  String p6_Pcat = "";// 商品各类
  String p7_Pdesc = "";// 商品描述
  String p8_Url = "http://localhost:8080/buy/BackServlet";// 电商的返回页面,当支付成功后,易宝会重定向到这个页面
  String p9_SAF = "";// 送货地址
  String pa_MP = "";// 商品扩展信息
  String pd_FrpId = request.getParameter("pd_FrpId");// 支付通道,即选择银行
  String pr_NeedResponse = "1";// 应答机制,固定值为1
  // 密钥,由易宝提供,只有商户和易宝知道这个密钥。
  String keyValue = "69cl522AV6q613Ii4W6u8K6XuW8vM1N6bFgyv769220IuYe9u37N4y7rI4Pl";
  // 通过上面的参数、密钥、加密算法,生成hmac值
  // 参数的顺序是必须的,如果没有值也不能给出null,而应该给出空字符串。
  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, keyValue);
  // 把所有参数连接到网关地址后面
  String url = "https://www.yeepay.com/app-merchant-proxy/node";
  url += "?p0_Cmd=" + p0_Cmd +
    "&p1_MerId=" + p1_MerId +
    "&p2_Order=" + p2_Order +
    "&p3_Amt=" + p3_Amt +
    "&p4_Cur=" + p4_Cur +
    "&p5_Pid=" + p5_Pid +
    "&p6_Pcat=" + p6_Pcat +
    "&p7_Pdesc=" + p7_Pdesc +
    "&p8_Url=" + p8_Url +
    "&p9_SAF=" + p9_SAF +
    "&pa_MP=" + pa_MP +
    "&pd_FrpId=" + pd_FrpId +
    "&pr_NeedResponse=" + pr_NeedResponse +
    "&hmac=" + hmac;
  System.out.println(url);
  // 重定向到网关
  response.sendRedirect(url);
 }
}

第三步:BackServlet

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class BackServlet extends HttpServlet {
 public void doGet(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException {
  response.setContentType("text/html;charset=utf-8");
  /*
   * 易宝会提供一系列的结果参数,我们获取其中需要的即可
   * 获取支付结果:r1_Code,1表示支付成功。
   * 获取支付金额:r3_Amt
   * 获取电商的订单号:r6_Order
   * 获取结果返回类型:r9_BType,1表示重定向返回,2表示点对点返回,
   *  但点对点我们收不到,因为我们的ip都是局域网ip。
   */
  String r1_Code = request.getParameter("r1_Code");
  String r3_Amt = request.getParameter("r3_Amt");
  String r6_Order = request.getParameter("r6_Order");
  String r9_BType = request.getParameter("r9_BType");
  if(r1_Code.equals("1")) {
   if(r9_BType.equals("1")) {
    response.getWriter().print("<h1>支付成功!</h1>");//其实支付不成功时根本易宝根本就不会返回到本Servlet
    response.getWriter().print("支付金额为:" + r3_Amt + "<br/>");
    response.getWriter().print("订单号为:" + r6_Order + "<br/>");
   }
  }
 }
}

易宝支付提供的获取hmac的工具类

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
public class PaymentUtil {
 private static String encodingCharset = "UTF-8";
 /**
  * 生成hmac方法
  *
  * @param p0_Cmd 业务类型
  * @param p1_MerId 商户编号
  * @param p2_Order 商户订单号
  * @param p3_Amt 支付金额
  * @param p4_Cur 交易币种
  * @param p5_Pid 商品名称
  * @param p6_Pcat 商品种类
  * @param p7_Pdesc 商品描述
  * @param p8_Url 商户接收支付成功数据的地址
  * @param p9_SAF 送货地址
  * @param pa_MP 商户扩展信息
  * @param pd_FrpId 银行编码
  * @param pr_NeedResponse 应答机制
  * @param keyValue 商户密钥
  * @return
  */
 public static String buildHmac(String p0_Cmd,String p1_MerId,
   String p2_Order, String p3_Amt, String p4_Cur,String p5_Pid, String p6_Pcat,
   String p7_Pdesc,String p8_Url, String p9_SAF,String pa_MP,String pd_FrpId,
   String pr_NeedResponse,String keyValue) {
  StringBuilder sValue = new StringBuilder();
  // 业务类型
  sValue.append(p0_Cmd);
  // 商户编号
  sValue.append(p1_MerId);
  // 商户订单号
  sValue.append(p2_Order);
  // 支付金额
  sValue.append(p3_Amt);
  // 交易币种
  sValue.append(p4_Cur);
  // 商品名称
  sValue.append(p5_Pid);
  // 商品种类
  sValue.append(p6_Pcat);
  // 商品描述
  sValue.append(p7_Pdesc);
  // 商户接收支付成功数据的地址
  sValue.append(p8_Url);
  // 送货地址
  sValue.append(p9_SAF);
  // 商户扩展信息
  sValue.append(pa_MP);
  // 银行编码
  sValue.append(pd_FrpId);
  // 应答机制
  sValue.append(pr_NeedResponse);
  return PaymentUtil.hmacSign(sValue.toString(), keyValue);
 }
 /**
  * 返回校验hmac方法
  *
  * @param hmac 支付网关发来的加密验证码
  * @param p1_MerId 商户编号
  * @param r0_Cmd 业务类型
  * @param r1_Code 支付结果
  * @param r2_TrxId 易宝支付交易流水号
  * @param r3_Amt 支付金额
  * @param r4_Cur 交易币种
  * @param r5_Pid 商品名称
  * @param r6_Order 商户订单号
  * @param r7_Uid 易宝支付会员ID
  * @param r8_MP 商户扩展信息
  * @param r9_BType 交易结果返回类型
  * @param keyValue 密钥
  * @return
  */
 public static boolean verifyCallback(String hmac, String p1_MerId,
   String r0_Cmd, String r1_Code, String r2_TrxId, String r3_Amt,
   String r4_Cur, String r5_Pid, String r6_Order, String r7_Uid,
   String r8_MP, String r9_BType, String keyValue) {
  StringBuilder sValue = new StringBuilder();
  // 商户编号
  sValue.append(p1_MerId);
  // 业务类型
  sValue.append(r0_Cmd);
  // 支付结果
  sValue.append(r1_Code);
  // 易宝支付交易流水号
  sValue.append(r2_TrxId);
  // 支付金额
  sValue.append(r3_Amt);
  // 交易币种
  sValue.append(r4_Cur);
  // 商品名称
  sValue.append(r5_Pid);
  // 商户订单号
  sValue.append(r6_Order);
  // 易宝支付会员ID
  sValue.append(r7_Uid);
  // 商户扩展信息
  sValue.append(r8_MP);
  // 交易结果返回类型
  sValue.append(r9_BType);
  String sNewString = PaymentUtil.hmacSign(sValue.toString(), keyValue);
  return sNewString.equals(hmac);
 }
 /**
  * @param aValue
  * @param aKey
  * @return
  */
 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();
 }
 /**
  *
  * @param args
  * @param key
  * @return
  */
 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) {
//  System.out.println(hmacSign("AnnulCard1000043252120080620160450.0http://localhost/SZXpro/callback.asp杩?4564868265473632445648682654736324511","8UPp0KE8sq73zVP370vko7C39403rtK1YwX40Td6irH216036H27Eb12792t"));
// }
}

易宝回调

点对点:易宝直接访问电商,这里没有客户端什么事了

这种方式是必须要使用的,我们这种方式是收不到的!因为我们没有固定IP
    易宝有一个重发机制,如果它访问你,你不给它回信息,它会一直重发!
    电商需要返回一个以SUCCESS开头的字符串即可!

引导客户端浏览器重定向到电商。是让客户端访问电商!

可以不使用的!

hmac:13参数值+keyValue(密钥) + 算法(md5)

13参数值:自己设置的!
    keyValue:易宝在我们注册后发给我们的,这个东东只有我们和易宝知道!
    底层为md5的算法:PaymentUtil.buildHmac(14个),它返回hmac

javaweb实现在线支付功能相关推荐

  1. 小白也能看懂的教程:微信小程序在线支付功能开通详细流程(图文介绍)

    微信小程序不仅是一个展示平台,更多会用到小程序的电商功能,当然了,支付目前而言需要接入微信支付,那么具体而言,微信小程序要怎么开通支付功能呢?最近需要在微信小程序中用到在线支付功能,于是看了一下官方的 ...

  2. ZLMS教学管理平台系统V1.2.0最新版本发布,支持纯Web视频直播点播,还带运营在线支付功能!完全免费提供!...

    ZLMS教学管理平台系统V1.2.0最新版本发布,支持纯Web视频直播,点播!还带在线支付功能! ZLMS 开发团队在综合参考了各方面的合理建议之后,经过两个多月的紧张开发及测试,终于发布V1.2.0 ...

  3. java在线支付---01_在线支付功能的演示与概述

    2013/5/30 ----------------- 01_在线支付功能的演示与概述 Java技术qq交流群:JavaDream:251572072 ------------------------ ...

  4. 【Node.js】实现微信小程序在线支付功能

    实战项目名称:微信小程序实现在线支付功能 - 文章结尾附上微信小程序码,扫码登录后即可体验!! 文章目录 一.实战步骤 1. 前期准备 2. 添加`wechatpay-node-v3`和`fs`插件 ...

  5. 在线支付功能-含银联在线和支付宝

    银联在线支付官方资料 银联商家技术服务 什么叫网关支付:自己的理解,直接和银行进行对接的支付 参考资料 支付宝集成过程详解--运行DEMO 在网站里集成支付宝支付方式(支付宝自己已经集成了和网银的支付 ...

  6. 让你的微信小程序具有在线支付功能

    最近需要在微信小程序中用到在线支付功能,于是看了一下官方的文档,发现要在小程序里实现微信支付还是很方便的,如果你以前开发过服务号下的微信支付,那么你会发现其实小程序里的微信支付和服务号里的开发过程如出 ...

  7. 个人站长福音:接入支付宝接口,实现在线支付功能

    相信有很多个人站长跟我一样,喜欢自己开发一些小功能小程序,然后放到 web 上,就拿最简单的来说,做了个博客网站,然后看访问人气还不错.然后想想每个月服务器的开销几百块,就心疼.然后就想多个打赏功能, ...

  8. 为电子商务网站添加在线支付功能

    2019独角兽企业重金招聘Python工程师标准>>> 网页制作Webjx文章简介:为了方便买家们在网站购物时能够在线支付货款并有效提升网站档次,作为购物网站的站长有必要给网站增添在 ...

  9. 【SSH网上商城项目实战23】完成在线支付功能

    转自:https://blog.csdn.net/eson_15/article/details/51464415 上一节我们做好了支付页面的显示,从上一节支付页面显示的jsp代码中可以看出,当用户点 ...

  10. linux购物系统源码,2021.4月LooShop购物商城网站PHP源码运营打包版 PC+手机+微信三站合一 带支付宝微信等第三方在线支付功能...

    一.系统简介 1. 产品简介 系统采用PHP+MySQL进行开发,它具有操作简单.功能强大.稳定性好.易扩展.安全性强.后期维护方便等特点,可以帮您迅速.轻松地构建起一个强大专业的企业网站.系统支持多 ...

最新文章

  1. JPEG算法概述及实现
  2. 「图像分割模型」全景分割是什么?
  3. python下载word文件-Python用python-docx读写word文档
  4. 【Windows 逆向】CE 地址遍历工具 ( CE 结构剖析工具 | 遍历查找后坐力数据 | 尝试修改后坐力数据 )
  5. 【转】请尊重测试:测试从业五年有感
  6. java 构建者模式_Java不可变类–构建器模式
  7. 台达服务器AB和B2系列区别,台达A2与B2伺服的区别
  8. 牛课-跳跃游戏1,2,3
  9. application.yml文件
  10. 实物补贴和货币补贴的权衡
  11. 人工智能阿发狗技术都包含哪些内容
  12. CentOS 7.9 安装NVIDIA 显卡驱动
  13. 怎样将PDF转成EXCEL
  14. typename的起源与用法
  15. C++多态的原理(虚函数指针和虚函数表)
  16. 腾达f3虚拟服务器设置,高手指南win7系统腾达F3路由器设置WIFI定时开关的法子
  17. 华大单片机HC32L130F8UA 串口烧录程序
  18. Git的简单使用教程(上)
  19. 网站下载工具httrack Mac使用方法
  20. 数学笔记(持续更新)

热门文章

  1. IE条件注释意义及用法
  2. 免费申请树葬、草坪葬、花坛葬!东胜区殡仪馆发布2019年清明节祭奠服务安排!...
  3. Uphone开发心得
  4. 数据传输 | 利用 DTLE 将 MySQL 数据同步到 DBLE
  5. 不开机win7计算机还原,win7忘记开机密码一键还原操作不了怎么办
  6. 智能家居Series
  7. 阿里巴巴达摩院发布2019十大科技趋势:语音AI在特定领域通过图灵测试...
  8. 万字长文!浏览器是如何工作的:Chrome V8让你更懂JavaScript
  9. 计算机用户名和初始密码,电脑默认的用户名和密码是多少
  10. python登录判断用户名和密码_第一个python程序-判断登陆用户名和密码是否正确...