支付流程
通过http请求方式向易宝支付网关发起一个支付请求,简单地说就是向https://www.yeepay.com/app-merchant-proxy/node发起请求,请求可以是get或post方式提交,页面应采用GBK/GB2312编码。下面使用表单以post方式向易宝支付网关发起一个支付请求:
<form name="yeepay" action="https://www.yeepay.com/app-merchant-proxy/node" method='post'>
这里省略一些请求参数
<input type='hidden' name='p8_Url' value=“http://www.babasport.com/payment/response">
<input type='hidden' name='hmac' value="2a8de8147356d97c364d1874410528dd">
form>
易宝支付网关对企业发来的数据使用用户的密钥生成MD5-hmac码,然后跟企业发来的MD5-hmac码(即上面表单由hmac字段提供的值)比较是否相同,如果相同即把请求转发到银行网关,当用户支付完成后,银行网关会引导用户的浏览器重定向到易宝支付网关,然后易宝支付网关再引导用户的浏览器重定向到企业提供的url(即上面表单由p8_Url提供的地址)
对支付请求的数据加密生成md5-hmac
buildHmac()方法用于生成md5-hmac
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) {
StringBuffer sValue = new StringBuffer();
sValue.append(p0_Cmd); // 业务类型,buy
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); // 应答机制0 ,1
String sNewString = DigestUtil.hmacSign(sValue.toString(), keyValue);
return sNewString;
}
String merchantID = ConfigInfo.getValue("p1_MerId"); // 商家ID
String keyValue = ConfigInfo.getValue("keyValue"); // 商家密钥
String merchantCallbackURL = ConfigInfo.getValue("merchantCallbackURL"); // 交易结果通知地址
String orderId = request.getParameter("orderid"); // 商家的交易定单号
String amount = request.getParameter("amount"); // 订单金额
String frpId = request.getParameter("pd_FrpId"); // 银行ID
String messageType = "Buy"; // 请求命令,在线支付固定为Buy
String currency = "CNY"; // 货币单位
String productDesc = ""; // 商品描述
String productCat = ""; // 商品种类
String productId = ""; // 商品ID
String addressFlag = "0"; // 需要填写送货信息 0:不需要 1:需要
String sMctProperties = ""; // 商家扩展信息
String hmac = buildHmac(messageType, merchantID, orderId, amount, currency, productId,productCat, productDesc, merchantCallbackURL, addressFlag, sMctProperties, frpId, "0", keyValue);// 获得MD5-HMAC签名
buildHmac()方法在前面已提供。ConfigInfo从类路径下的属性文件读取商家的ID、密钥和交易结果通知地址。
发起支付请求
<form name="yeepay" action="https://www.yeepay.com/app-merchant-proxy/node" method='post'>
<input type='hidden' name='p0_Cmd' value="${messageType}">
<input type='hidden' name='p1_MerId' value="${merchantID}">
<input type="hidden" name="p2_Order" value="${orderId}">
<input type='hidden' name='p3_Amt' value="${amount}">
<input type='hidden' name='p4_Cur' value="${currency}">
<input type='hidden' name='p5_Pid' value="${productId}">
<input type='hidden' name='p6_Pcat' value="${productCat}">
<input type='hidden' name='p7_Pdesc' value="${productDesc}">
<input type='hidden' name='p8_Url' value="${merchantCallbackURL}">
<input type='hidden' name='p9_SAF' value="${addressFlag}">
<input type='hidden' name='pa_MP' value="${sMctProperties}">
<input type='hidden' name='pd_FrpId' value="${frpId}">
<input type="hidden" name="pr_NeedResponse" value="0">
<!– MD5-hmac验证码 -->
<input type='hidden' name='hmac' value="${hmac}">
form>
对支付结果返回的数据加密生成md5-hmac
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) {
StringBuffer sValue = new StringBuffer();
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);// 商户订单号
sValue.append(r7_Uid);// 易宝支付会员ID
sValue.append(r8_MP);// 商户扩展信息
sValue.append(r9_BType);// 交易结果返回类型
String sNewString = null;
sNewString = DigestUtil.hmacSign(sValue.toString(), keyValue);
if (hmac.equals(sNewString)) {
return true;
}
return false;
}
String merchantID = ConfigInfo.getValue("p1_MerId"); // 商家ID
String keyValue = ConfigInfo.getValue("keyValue"); // 商家密钥
String sCmd = request.getParameter("r0_Cmd"); //业务类型
String sResultCode = request.getParameter("r1_Code"); //扣款结果,该字段值为1时表示扣款成功.
String sTrxId = request.getParameter("r2_TrxId"); //YeePay易宝交易订单号
String amount = request.getParameter("r3_Amt");//扣款金额,交易结束后,YeePay易宝交易系统将实际扣款金额返回给商户
String currency = request.getParameter("r4_Cur");//交易币种,人民币为CNY
String productId = request.getParameter("r5_Pid");//商品ID
String orderId = request.getParameter("r6_Order");//商户订单号
String userId = request.getParameter("r7_Uid");//YeePay易宝会员ID
String mp = request.getParameter("r8_MP");//商户扩展信息,可以任意填写1K 的字符串,交易返回时将原样返回
String bType = request.getParameter("r9_BType");//交易结果返回类型,1: 交易成功回调(浏览器重定向)2: 交易成功主动通知(服务器点对点通讯)
String rb_BankId = request.getParameter("rb_BankId");//支付银行
String rp_PayDate = request.getParameter("rp_PayDate");//在银行支付时的时间
String hmac = request.getParameter("hmac");//MD5交易签名
boolean isOK = verifyCallback(hmac, merchantID, sCmd, sResultCode, sTrxId, amount,currency, productId, orderId, userId, mp, bType, keyValue);
处理支付结果
boolean isOK = verifyCallback(hmac, merchantID, sCmd, sResultCode, sTrxId, amount,currency, productId, orderId, userId, mp, bType, keyValue);
对isOK 的结果进行判断:
if(isOK) {
if("1".equals(sResultCode)) {//扣款结果,该字段值为1时表示扣款成功.
String msg = "";
if("1".equals(bType)) {
msg = "在线支付_客户浏览器重定向";
} else if("2".equals(bType)) {
msg = "在线支付_yeepay服务器程序通知";
} else if("3".equals(bType)) {
msg = "电话支付_yeepay服务器程序通知";
}
//在这里应该对数据库中订单号为orderId 的订单的支付状态设为已支付
request.setAttribute("message" ,"交易成功!订单号:" + orderId + " 交易金额:" + amount + "元 YeePay易宝交易流水号:" + sTrxId+ " 消息通知类型:" + msg);
}
} else {
request.setAttribute("message" ,"交易签名被篡改.");
}