1、在线支付的两种解决方案
1)与银行直连
这种方式网站需要针对不同的银行开发不同的支付程序,编程工作量很大,并且银行接入规范一旦发生变动,网站程序也要跟着改,维护工作量极大。
2)接入第三方支付
优点:系统只需要与第三方支付公司打交道,第三方支付公司根据用户选择的支付银行,引导用户与银行对接,从而实现支付。此种方案最大的优点,系统只需要与第三方支付公司交互,开发工作量极低。
缺点:由于通过第三方支付公司引导用户支付,所以用户支付的钱会支付给第三方支付公司,网站再与第三方支付公司定期进行资金结算。所以如果金额较大,资金安全是个大问题。此种支付方案比较适合月金额在百万以下的公司。
常见的第三方支付工具有支付宝、财付通、易宝、快钱等,接入过程基本类似。本文采用易宝支付接入,开发语言为Java。
2、接入前准备
1)下载易宝支付接入的帮助文档及官方提供的工具类(用于生成签名、校验签名)。点此去下载>>
2)去易宝支付官网(www.yeepay.com)注册,获得商户编号(p1_MerId)和密钥(keyValue)(详见帮助文档 — 常见问题及注意事项)
//测试用的商户编号和密钥
p1_MerId=10001126856
keyValue=69cl522AV6q613Ii4W6u8K6XuW8vM1N6bFgyv769220IuYe9u37N4y7rI4Pl
3、支付流程图解(☆)
上面几个页面的说明(红色字体):
① /pay.jsp,当用户点击页面中的去付款时跳转到该页面,让用户选择付款银行。
② /servlet/ClientServlet?op=pay,完成支付请求参数的封装(要符合第三方提供的接口规范),并通过表单(/send_data.jsp)以post的方式提交。
③ /servlet/PaymentResponse(☆),根据支付结果参数完成后续处理。需要注意的是,当用户完成支付时,第三方会同时向客户端发出重定向,并向服务器发出支付结果的通知,所以在PaymentResponse中除了要响应客户端重定向请求(并完成订单处理逻辑),还要向第三方支付发送带”success”的标记。
4、开发实战
提示:有些银行的网银只支持IE浏览器,测试时需注意。
1)/pay.jsp
<!-- 仅列出核心代码 --> <form action="${pageContext.request.contextPath}/servlet/ClientServlet?op=pay" method="post"> <!-- 由于没有列出“去付款”页面,下面的订单号和金额均为模拟 --> 订单号:<INPUT TYPE="text" NAME="orderNum" value="201409052920708199392"> 支付金额:<INPUT TYPE="text" NAME="sum" size="6" value="0.01">元 <!-- …………………………………… --> <tr> <td><INPUT TYPE="radio" NAME="pd_FrpId" value="CMBCHINA-NET">招商银行 </td> <td><INPUT TYPE="radio" NAME="pd_FrpId" value="ICBC-NET">工商银行</td> <td><INPUT TYPE="radio" NAME="pd_FrpId" value="ABC-NET">农业银行</td> <td><INPUT TYPE="radio" NAME="pd_FrpId" value="CCB-NET">建设银行 </td> </tr> <tr> <td><INPUT TYPE="radio" NAME="pd_FrpId" value="CMBC-NET">中国民生银行总行</td> <td><INPUT TYPE="radio" NAME="pd_FrpId" value="CEB-NET" >光大银行 </td> <td><INPUT TYPE="radio" NAME="pd_FrpId" value="BOCO-NET">交通银行</td> <td><INPUT TYPE="radio" NAME="pd_FrpId" value="SDB-NET">深圳发展银行</td> </tr> <tr> <td><INPUT TYPE="radio" NAME="pd_FrpId" value="BCCB-NET">北京银行</td> <td><INPUT TYPE="radio" NAME="pd_FrpId" value="CIB-NET">兴业银行 </td> <td><INPUT TYPE="radio" NAME="pd_FrpId" value="SPDB-NET">上海浦东发展银行 </td> <td><INPUT TYPE="radio" NAME="pd_FrpId" value="ECITIC-NET">中信银行</td> </tr> <tr><td><br/></td></tr> <tr> <td><INPUT TYPE="submit" value="确定支付"></td> </tr> <!-- …………………………………… --> </form>
2)/servlet/ClientServlet?op=pay
//获取页面数据(订单号、订单金额、用户选择的银行) String orderNum = request.getParameter("orderNum"); String sum = request.getParameter("sum"); String pd_FrpId = request.getParameter("pd_FrpId");//选择的银行 //按易宝的接口规范组织数据(支付请求参数) String p0_Cmd = "Buy"; String p1_MerId = "10001126856"; String p2_Order = orderNum; String p3_Amt = sum; String p4_Cur = "CNY"; String p5_Pid = "unknown"; String p6_Pcat = "unknown"; String p7_Pdesc = "unknown"; String p8_Url = "http://localhost:8080/bookstore/servlet/PaymentResponse"; String p9_SAF = "1"; String pa_MP = "no"; String pr_NeedResponse = "1"; 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, "69cl522AV6q613Ii4W6u8K6XuW8vM1N6bFgyv769220IuYe9u37N4y7rI4Pl"); //以Post方式提交易宝需要的数据:需要封装到一个表单中 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("pr_NeedResponse",pr_NeedResponse ); request.setAttribute("pd_FrpId",pd_FrpId ); request.setAttribute("hmac",hmac ); request.getRequestDispatcher("/send_data.jsp").forward(request, response);
/send_data.jsp
<form action="https://www.yeepay.com/app-merchant-proxy/node" method="post"> <input type="hidden" name="p0_Cmd" value="${p0_Cmd}"> <input type="hidden" name="p1_MerId" value="${p1_MerId}"> <input type="hidden" name="p2_Order" value="${p2_Order}"> <input type="hidden" name="p3_Amt" value="${p3_Amt}"> <input type="hidden" name="p4_Cur" value="${p4_Cur}"> <input type="hidden" name="p5_Pid" value="${p5_Pid}"> <input type="hidden" name="p6_Pcat" value="${p6_Pcat}"> <input type="hidden" name="p7_Pdesc" value="${p7_Pdesc}"> <input type="hidden" name="p8_Url" value="${p8_Url}"> <input type="hidden" name="p9_SAF" value="${p9_SAF}"> <input type="hidden" name="pa_MP" value="${pa_MP}"> <input type="hidden" name="pr_NeedResponse" value="${pr_NeedResponse}"> <input type="hidden" name="pd_FrpId" value="${pd_FrpId}"> <input type="hidden" name="hmac" value="${hmac}"> </form> <script type="text/javascript"> document.forms[0].submit(); </script>
3)/servlet/PaymentResponse(☆)
<form action="https://www.yeepay.com/app-merchant-proxy/node" method="post"> <input type="hidden" name="p0_Cmd" value="${p0_Cmd}"> <input type="hidden" name="p1_MerId" value="${p1_MerId}"> <input type="hidden" name="p2_Order" value="${p2_Order}"> <input type="hidden" name="p3_Amt" value="${p3_Amt}"> <input type="hidden" name="p4_Cur" value="${p4_Cur}"> <input type="hidden" name="p5_Pid" value="${p5_Pid}"> <input type="hidden" name="p6_Pcat" value="${p6_Pcat}"> <input type="hidden" name="p7_Pdesc" value="${p7_Pdesc}"> <input type="hidden" name="p8_Url" value="${p8_Url}"> <input type="hidden" name="p9_SAF" value="${p9_SAF}"> <input type="hidden" name="pa_MP" value="${pa_MP}"> <input type="hidden" name="pr_NeedResponse" value="${pr_NeedResponse}"> <input type="hidden" name="pd_FrpId" value="${pd_FrpId}"> <input type="hidden" name="hmac" value="${hmac}"> </form> <script type="text/javascript"> document.forms[0].submit(); </script>
- 本文固定链接: http://www.flyne.org/article/673
- 转载请注明: 东风化宇 2014年09月06日 于 Flyne 发表
000000000000