在线支付模块小结
一、概述
在所有的电子商务网站中都提供了在线支付功能,用户可以将在网上选购的商品生成订单后通过网站提供的在线支付功能进行结算。网站开发者可以直接使用银行提供的接口实现在线支付,也可以使用第三方支付平台来实现。使用银行接口需要自行开发程序,而第三方支付平台帮助网站开发者开发了这样的程序,网站开发者只需应用该平台提供的接口进行很少的编码即可实现。
使用支付宝平台提供的接口非常简单,只需准备一些参数,然后调用提供的方法对这些参数进行签名并处理,最后通过超链接传递处理后的数据到支付宝平台接口即可,至于支付宝端如何与银行进行连接与网站开发者已没有关系。所以整个实现过程只需在JSP页面中完成即可;而对于应用银行提供的接口实现的在线支付则比较复杂,因为银行并没有提供一个完整的程序将参数进行签名并处理,所以需要开发者自行编写,这个过程本系统是在一个Servlet中完成的。
二、支付宝接口介绍
通过支付宝网站注册帐号后,会获取相关接口、示例程序、和使用帮助文档。在文档中对支付宝的服务接口和通知接口进行了概述及使用接口时需要的参数进行了说明。服务接口用来接收网站开链接到支付宝进行的交易请求等,通知接口则是支付宝用来向网站发送通知信息。
商品可分为实物商品和虚拟商品(如IP电话卡),支付宝也提供针对虚拟商品的在线支付示例程序,这里主要讲解的是针对实物商品的在线支付。下面对支付宝“实物商品交易服务”接口时需要的参数进行介绍。
表1 支付宝服务接口参数介绍
参数名 |
值 |
说明 |
可否为空 |
|
协议参数 |
||||
paygateway |
https://www.alipay.com/cooperate/gateway.do? |
支付接口 |
否 |
|
service |
trade_create_by_buyer |
通过该参数确定用户请求的操作。表中的值表示订单交易 |
否 |
|
partner |
从用户帐户内提取 |
用户在支付宝的ID |
否 |
|
notify_url |
商户自定义 |
接收支付宝通知的URL |
是 |
|
return_url |
商户自定义 |
支付宝返回的URL |
是 |
|
input_charset |
默认为GBK |
参数编码字符集 |
是 |
|
sign |
HTTP请求中传递的所有参数(除sign和sign_type以外)按照参数名称字符升序的顺序拼接起来的值 |
待签名数据 |
否 |
业务参数 |
||||
subject |
商户自定义 |
商品名称 |
否 |
|
body |
商户自定义 |
商品描述 |
是 |
|
out_trade_no |
商户自定义 |
商户网站产生的一个唯一订单号 |
否 |
|
price |
商品单价(订单总价) |
商品单价(订单总价) |
否 |
|
discount |
-10000000.00~10000000.00 |
折扣 |
是 |
|
show_url |
商户自定义 |
商品展示网址 |
是 |
|
quantity |
大于0 |
购买数量 |
否 |
|
payment_type |
1~6的数字。1表示商品购买 |
支付类型 |
是 |
物流信息 |
||||
logistics_type |
VIRTUAL(虚拟物品);POST(平邮);EMS;EXPRESS(其他快递公司) |
物流类型 |
否 |
|
logistics_fee |
0.00~10000000.00,默认为0 |
物流费用 |
否 |
|
logistics_payment |
SELLER_PAY(由卖家支付物流费用); BUYER_PAY(由买家支付物流费用) |
物流支付类型 |
否 |
|
买卖双方信息 |
||||
seller_email |
卖家Email |
卖家在支付宝注册的Email或ID,两者任何一个 |
否 |
三、银行接口介绍
银行通过接口名称和版本号来通知用户使用的接口,下面介绍其中一个接口的定义
参数名 |
值 |
说明 |
可否为空 |
interfaceName |
ICBC_PERBANK_B2C |
接口名称 |
否 |
interfaceVersion |
1.0.0.0 |
接口版本号 |
否 |
orderid |
商户自定义 |
商户网站产生的一个唯一订单号 |
否 |
amount |
商户自定义 |
订单金额,以分为单位,不可以为零,必需符合金额标准 |
否 |
curType |
001 |
支付币种,目前工行只支持使用人民币(001)支付 |
否 |
merID |
由商户在工行开户时,由工行告知商户 |
商户代码 |
否 |
merAcct |
商城收费入账账号 |
商城账号 |
否 |
verifyJoinFlag |
1或0 |
检验联名标志 |
否 |
notifyType |
“HS”或“AG” |
通知类型,取值“HS”表示在交易完成后实时将通知信息发送给merURL参数指定的URL;取值“AG”表示在交易完成后不通知商户 |
否 |
merURL |
商户自定义 |
接收支付结果信息通知程序地址 |
是 |
resultType |
0或1 |
结果发送类型,取值“0”表示无论支付成功或者失败,银行都向商户发送交易通知信息;取值“1”表示只向商户发送交易成功的通知信息。只有通知方式为“HS”时此值有效 |
是 |
goodsID |
商户自定义 |
商品编号 |
是 |
表中明确指定的参数值是不可修改的,例如接口名称和接口版本号,其他一些参数值需要银行提供或由提供的API接口程序自己来生成。例如订单签名数据参数merSignMsg,就是由商户网站开发者根据银行提供的指定格式和API接口程序生成的,生成merSignMsg参数的步骤如下:
(1)按照以下格式拼接各参数。
接口名称的值+接口版本号的值+商城代码的值+商城账号的值+通知地址的值+结果发送类型的值+订单号的值+订单金额的值+支付币种的值+通知类型的值+交易日期时间的值+校验联名标志的值
(2)通过商户证书私钥(user.key)对编码后的值进行签名。
(3)对拼接后的值进行BASE64编码。
四、应用支付宝实现在线支付
1.创建链接支付宝平台的支付页面
在生成了订单编号和订单总价格后,就可直接通过创建一个页面完成应用支付宝实现的在线支付。在该页面将获取订单编号和订单总价格参数,并生成支付宝接口需要的其他参数,例如支付宝合作伙伴id、支付宝安全校验码等,然后调用支付宝提供的方法对这些参数进行签名并处理,最后通过图片超链接传递处理后的数据。
关键代码如下:
<%@ page import=”com.alipay.util.*”%> <!– 导入支付宝提供的工具类 –>
<%
//******账户信息*******************************************************************
String paygateway = “https://www.alipay.com/cooperate/gateway.do?”; //支付接口
String service = “trade_create_by_buyer”;
String sign_type = “MD5”;
String out_trade_no = request.getParameter(“orderid”); //商户网站订单编号
String input_charset = “GBK”;
String partner = “”; //支付宝合作伙伴id (账户内提取)
String key = “”; //支付宝安全校验码(账户内提取)
String seller_email = “”; //卖家支付宝帐户
//******商品信息*******************************************************************
String body = “结算商品来自聚宝商城”; //商品描述
String subject = “聚宝商城提供商品”; //商品名称
String price = request.getParameter(“amount”); //订单总价
String quantity = “1”;
String show_url = “www.sina.com.cn”;
String payment_type = “1”;
String discount = “0”;
//******以下是物流信息和支付宝通知。一般商城不需要通知,则删除此参数(notify_url),并且在Payment.java里面相应删除该参数********//
String logistics_type = “EMS”;
String logistics_fee = “0.01”;
String logistics_payment = “SELLER_PAY”;
//支付完成后跳转返回的网址URL
String return_url = “http://localhost:8080/onLinePayfor01/alipay_return.jsp”;
//接收通知的URL,需要的话可取消对该行的注释
//String notify_url = “http://localhost:8081/jsp_shi_gbk/alipay_notify.jsp”;
String ItemUrl = Payment.CreateUrl( paygateway,service,sign_type,out_trade_no,
input_charset,partner,key,seller_email,body,
subject,price,quantity,show_url,payment_type,
discount,logistics_type,logistics_fee,
logistics_payment,return_url); //如果需要接收通知的话,可传递notify_url参数,并在Payment.java的CreateUrl()方法的参数中加入notify_url参数。
%>
订单号: ${param.orderid},您需要支付:¥${param.amount}<br><br>
你选择的是通过支付宝支付平台进行网上支付,只有在网上支付成功后,我们才会为您发货。<br>
请立即支付:<a href=”<%=ItemUrl%>”><img src=”images/alipay_bwrx.gif” border=”0″></a>
在获取支付宝接口的同时支付宝会提供示例程序,开发者只需修改程序中index.jsp页面的一些参数即可使用。
2.创建支付完成后跳转返回的页面
因为在代码中设置了return_url参数,所以在支付成功后,请求会从支付宝那边转发到return_url参数指定的页面。在该页面中要验证请求是否由支付宝发起,并且验证订单信息的正确性,这个过程需要按照支付宝协议来操作,好在支付宝提供的示例程序中也提供了该页面的实现。下面给出该页的关键代码:
<%@ page import=”com.alipay.util.*”%> <!– 导入支付宝提供的工具类 –>
<%
String partner = “”; //partner合作伙伴id(必须填写)
String privateKey = “”; //partner 的对应交易安全校验码(必须填写)
String alipayNotifyURL = “http://notify.alipay.com/trade/notify_query.do?partner=”
+ partner+ “¬ify_id=”+ request.getParameter(“notify_id”);
String sign=request.getParameter(“sign”);
//获取支付宝ATN返回结果,“true”是正确的订单信息,“false” 是无效的
String responseTxt = CheckURL.check(alipayNotifyURL);
Map params = new HashMap();
//获得由支付宝POST 过来的参数并设置到新的params中
Map requestParams = request.getParameterMap();
for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
String name = (String) iter.next();
String[] values = (String[]) requestParams.get(name);
String valueStr = “”;
for (int i = 0; i < values.length; i++){
valueStr = (i == values.length – 1) ? valueStr + values[i]: valueStr + values[i] + “,”;
params.put(name, valueStr);
}
//对由支付宝POST 过来的参数(不包括sign参数)进行签名并处理
String mysign = com.alipay.util.SignatureHelper_return.sign(params, privateKey);
//验证处理后的数据与sign参数值是否相同,并验证订单信息的正确性
if (mysign.equals(request.getParameter(“sign”)) && responseTxt.equals(“true”) ){
out.println(“success”);
out.println(params.get(“body”)); //测试时候用,可以删除
out.println(“显示订单信息”);
out.println(responseTxt);
}
else
out.println(“fail”);
%>