在J2EE项目中集成快钱支付接口

在J2EE项目中集成快钱支付接口

103人收藏此文章,我要收藏 发表于1个月前(2012-09-12 17:52) , 已有 3239次阅读 共 22个评论

前段时间我们的壹个小型电子商务网站集成的快钱支付接口突然出错了,具体表现如下:用户选择了快钱支付方式后,提交订单并进入快钱支付渠道,在完成支付之后无法回调请求,导致用户即使成功付费,订单的状态也不会更新,问题似乎还挺严重。于是乎我开始了解快钱的支付接口与相关内容,最终在快钱客服人员与我们公司几个技术人员的通力合作下,问题得到了圆满解决,现在将解决问题后的经验总结如下。

由于快钱支付接口是上壹批人马做的,但是相关人等都已经离职或联系不上,我们只好找了快钱的技术支持部门并找到了壹个支付的样例。为了自己以后参考时方便,我把它们记录在这里。

首先是发送快钱支付请求的页面send.jsp,内容如下:

001<%@ page contentType="text/html; charset=gb2312" language="java"%>
002<%@ page import="encrypt.MD5Util"%>
003<%
004/**
005 * @Description: 快钱人民币支付网关接口范例
006 * @Copyright (c) 上海快钱信息服务有限公司
007 * @version 2.0
008 */
009 
010//人民币网关账户号
011///请登录快钱系统获取用户编号,用户编号后加01即为人民币网关账户号。
012String merchantAcctId="";
013 
014//人民币网关密钥
015///区分大小写.请与快钱联系索取
016String key="";
017 
018//字符集.固定选择值。可为空。
019///只能选择1、2、3.
020///1代表UTF-8; 2代表GBK; 3代表GB2312
021///默认值为1
022String inputCharset="3";
023 
024 
025//服务器接受支付结果的后台地址.与[pageUrl]不能同时为空。必须是绝对地址。
026///快钱通过服务器连接的方式将交易结果发送到[bgUrl]对应的页面地址,在商户处理完成后输出的<result>如果为1,页面会转向到<redirecturl>对应的地址。
027///如果快钱未接收到<redirecturl>对应的地址,快钱将把支付结果GET到[pageUrl]对应的页面。
028String bgUrl="http://www.yoursite.com/receive.jsp";
029     
030//网关版本.固定值
031///快钱会根据版本号来调用对应的接口处理程序。
032///本代码版本号固定为v2.0
033String version="v2.0";
034 
035//语言种类.固定选择值。
036///只能选择1、2、3
037///1代表中文;2代表英文
038///默认值为1
039String language="1";
040 
041//签名类型.固定值
042///1代表MD5签名
043///当前版本固定为1
044String signType="1";
045    
046//支付人姓名
047///可为中文或英文字符
048String payerName="payerName";
049 
050//支付人联系方式类型.固定选择值
051///只能选择1
052///1代表Email
053String payerContactType="1";
054 
055//支付人联系方式
056///只能选择Email或手机号
057String payerContact="";
058 
059//商户订单号
060///由字母、数字、或[-][_]组成
061String orderId=new java.text.SimpleDateFormat("yyyyMMddHHmmss").format(new java.util.Date());
062 
063//订单金额,以分为单位,必须是整型数字,比方2,代表0.02元
064String orderAmount="2";
065     
066//订单提交时间如;20080101010101
067///14位数字。年[4位]月[2位]日[2位]时[2位]分[2位]秒[2位]
068///如;20080101010101
069String orderTime=new java.text.SimpleDateFormat("yyyyMMddHHmmss").format(new java.util.Date());
070 
071//商品名称,可为中文或英文字符
072String productName="productName";
073 
074//商品数量,可为空,非空时必须为数字
075String productNum="1";
076 
077//商品代码,可为字符或者数字
078String productId="";
079 
080//商品描述
081String productDesc="";
082     
083//扩展字段1
084///在支付结束后原样返回给商户
085String ext1="";
086 
087//扩展字段2
088///在支付结束后原样返回给商户
089String ext2="";
090     
091//支付方式.固定选择值
092///只能选择00、10、11、12、13、14
093///00:组合支付(网关支付页面显示快钱支持的各种支付方式,推荐使用)10:银行卡支付(网关支付页面只显示银行卡支付).11:电话银行支付(网关支付页面只显示电话支付).12:快钱账户支付(网关支付页面只显示快钱账户支付).13:线下支付(网关支付页面只显示线下支付方式)
094String payType="00";
095 
096//同一订单禁止重复提交标志
097///固定选择值: 1、0
098///1代表同一订单号只允许提交1次;0表示同一订单号在没有支付成功的前提下可重复提交多次。默认为0建议实物购物车结算类商户采用0;虚拟产品类商户采用1
099String redoFlag="1";
100 
101//快钱的合作伙伴的账户号
102///如未和快钱签订代理合作协议,不需要填写本参数
103String pid="";
104    //生成加密签名串
105    ///请务必按照如下顺序和规则组成加密串!
106    String signMsgVal="";
107    signMsgVal=appendParam(signMsgVal,"inputCharset",inputCharset);//字符集设置
108    signMsgVal=appendParam(signMsgVal,"bgUrl",bgUrl);//服务器接受支付结果的后台地址,必须是绝对地址
109    signMsgVal=appendParam(signMsgVal,"version",version);//服务器版本号
110    signMsgVal=appendParam(signMsgVal,"language",language);//语言版本
111    signMsgVal=appendParam(signMsgVal,"signType",signType);//签名类型,固定值1
112    signMsgVal=appendParam(signMsgVal,"merchantAcctId",merchantAcctId);//人民币网关账户号
113    signMsgVal=appendParam(signMsgVal,"payerName",payerName);//支付人姓名,允许为中文或者英文
114    signMsgVal=appendParam(signMsgVal,"payerContactType",payerContactType);//支付人联系方式的类型,固定值1
115    signMsgVal=appendParam(signMsgVal,"payerContact",payerContact);//支付人联系方式,只能选择手机号或者Email
116    signMsgVal=appendParam(signMsgVal,"orderId",orderId);//商户订单号,是一个包含时间格式的字符串
117    signMsgVal=appendParam(signMsgVal,"orderAmount",orderAmount);//订单金额,以分为单位,必须是整型数字,比如数字2代表0.02元
118    signMsgVal=appendParam(signMsgVal,"orderTime",orderTime);订单提交时间,如;20120801010101
119    signMsgVal=appendParam(signMsgVal,"productName",productName);//商品名称,可为中文或英文字符
120    signMsgVal=appendParam(signMsgVal,"productNum",productNum);//商品数量,可为空,非空时必须为壹个可以转化成整型数字的字符串
121    signMsgVal=appendParam(signMsgVal,"productId",productId);//商品代码,可为字符或者数字
122    signMsgVal=appendParam(signMsgVal,"productDesc",productDesc);//商品描述信息
123    signMsgVal=appendParam(signMsgVal,"ext1",ext1);//扩展字段1,在支付结束后原样返回给商户
124    signMsgVal=appendParam(signMsgVal,"ext2",ext2);//扩展字段2,在支付结束后原样返回给商户
125    signMsgVal=appendParam(signMsgVal,"payType",payType);//支付方式,推荐组合支付(网关支付页面显示快钱支持的各种支付方式),取值"00"
126    signMsgVal=appendParam(signMsgVal,"redoFlag",redoFlag);//是否允许同一订单重复提交,为1不允许,为0允许
127    signMsgVal=appendParam(signMsgVal,"pid",pid);//快钱的合作伙伴的账户号,可选项
128    signMsgVal=appendParam(signMsgVal,"key",key);
129    //下面这壹行中字符编码"UTF-8"实际与上面参数中的inputCharset没有任何关系,不过我们当时在理解这段代码时费了不少劲,前者只与JSP文件的编码格式有关
130    String signMsg=MD5Util.md5Hex(signMsgVal.getBytes("UTF-8")).toUpperCase();
131%>
132<%!
133    //功能函数。将变量值不为空的参数组成字符串
134    public String appendParam(String returnStr,String paramId,String paramValue)
135    {
136            if(!returnStr.equals(""))
137            {
138                if(!paramValue.equals(""))
139                {
140                    returnStr=returnStr+"&"+paramId+"="+paramValue;
141                }
142            }
143            else
144            {
145                if(!paramValue.equals(""))
146                {
147                returnStr=paramId+"="+paramValue;
148                }
149            }  
150            return returnStr;
151    }
152    //功能函数。将变量值不为空的参数组成字符串。结束
153%>
154<!doctype html public "-//w3c//dtd html 4.0 transitional//en" >
155<html>
156    <head>
157        <title>使用快钱支付</title>
158        <meta http-equiv="content-type" content="text/html; charset=gb2312" >
159    </head>
160<body>
161    <div align="center">
162        <table width="259" border="0" cellpadding="1" cellspacing="1" bgcolor="#CCCCCC" >
163            <tr bgcolor="#FFFFFF">
164                <td width="80">支付方式:</td>
165                <td >快钱[99bill]</td>
166            </tr>
167            <tr bgcolor="#FFFFFF">
168                <td >订单编号:</td>
169                <td ><%=orderId %></td>
170            </tr>
171            <tr bgcolor="#FFFFFF">
172                <td>订单金额:</td>
173                <td><%=orderAmount %></td>
174            </tr>
175            <tr bgcolor="#FFFFFF">
176                <td>支付人:</td>
177                <td><%=payerName %></td>
178            </tr>
179            <tr bgcolor="#FFFFFF">
180                <td>商品名称:</td>
181                <td><%=productName %></td>
182            </tr>
183            <tr>
184                <td></td>
185                <td></td>
186            </tr>
187      </table>
188    </div>
189 
190    <div align="center" style="font-size=12px;font-weight: bold;color=red;">
191        <form name="kqPay" action="https://www.99bill.com/gateway/recvMerchantInfoAction.htm" method="post">
192            <input type="hidden" name="inputCharset" value="<%=inputCharset %>"/>
193            <input type="hidden" name="bgUrl" value="<%=bgUrl %>"/>
194            <input type="hidden" name="version" value="<%=version %>"/>
195            <input type="hidden" name="language" value="<%=language %>"/>
196            <input type="hidden" name="signType" value="<%=signType %>"/>
197            <input type="hidden" name="signMsg" value="<%=signMsg %>"/>
198            <input type="hidden" name="merchantAcctId" value="<%=merchantAcctId %>"/>
199            <input type="hidden" name="payerName" value="<%=payerName %>"/>
200            <input type="hidden" name="payerContactType" value="<%=payerContactType %>"/>
201            <input type="hidden" name="payerContact" value="<%=payerContact %>"/>
202            <input type="hidden" name="orderId" value="<%=orderId %>"/>
203            <input type="hidden" name="orderAmount" value="<%=orderAmount %>"/>
204            <input type="hidden" name="orderTime" value="<%=orderTime %>"/>
205            <input type="hidden" name="productName" value="<%=productName %>"/>
206            <input type="hidden" name="productNum" value="<%=productNum %>"/>
207            <input type="hidden" name="productId" value="<%=productId %>"/>
208            <input type="hidden" name="productDesc" value="<%=productDesc %>"/>
209            <input type="hidden" name="ext1" value="<%=ext1 %>"/>
210            <input type="hidden" name="ext2" value="<%=ext2 %>"/>
211            <input type="hidden" name="payType" value="<%=payType %>"/>
212            <input type="hidden" name="redoFlag" value="<%=redoFlag %>"/>
213            <input type="hidden" name="pid" value="<%=pid %>"/>            
214            <input type="submit" name="submit" value="提交到快钱">        
215        </form>      
216    </div>   
217</body>
218</html>

上面这个文件中,有几个需要注意的地方:(1)组装之后的变量 signMsgVal 需要将其加密,加密时的字符集与我们的参数列表中的inputCharset没有任何关系的,如果壹定要讲,它只与页面的编码格式有关,目前我们的页面中使用的是UTF-8,所以这里我也将其字符格式设置成了UTF-8;(2)本页面提交之后应该跳转至receive.jsp,而不是响应我们的应用,当时我们的代码中就是这个地方完全弄错了,所以无论我们怎么尝试,都无法回调我们的应用请求。据客户方反馈的信息,说这个功能当初测试的时候是通过的,我颇表怀疑,因为这个流程根本就不通,如何能够测试通过呢;(3)对SignMsgVal进行加密的方法MD5Util.md5Hex(),其定义是由快钱技术部门直接提供的,其功能就是加密字符串并生成对应的KEY,用于快钱系统完成支付之后将回调信息返回给我们的系统;因此,这个加密的过程是与支付的流程完全独立的,也就是说我们完全可以用自己实现的加密方案来替换这部分代码,或者也可以选用其它市场上已经成熟的加密方案;(4)特别需要注意的是,此时我们不将加密之后生成的KEY值发送到快钱系统,而是将它保留,用于快钱返回之后验证某次支付请求是否与我们的订单明细信息相匹配。(5)变量中merchantAccId也是壹个需要注意的地方,它是快钱方提供给我们应用的壹个类似收款帐号样的东西,具体可以咨询快钱技术部或者你的应用提供商。

001<%@page contentType="text/html; charset=UTF-8" language="java"%>
002<%@ page import="encrypt.MD5Util"%>
003<%
004/**
005 * @Description: 快钱人民币支付网关接口范例
006 * @Copyright (c) 上海快钱信息服务有限公司
007 * @version 2.0
008 */
009 
010//获取人民币网关账户号
011String merchantAcctId=(String)request.getParameter("merchantAcctId").trim();
012 
013//设置人民币网关密钥
014///区分大小写
015String key="";
016 
017//获取网关版本.固定值
018///快钱会根据版本号来调用对应的接口处理程序。
019///本代码版本号固定为v2.0
020String version=(String)request.getParameter("version").trim();
021 
022//获取语言种类.固定选择值。
023///只能选择1、2、3
024///1代表中文;2代表英文
025///默认值为1
026String language=(String)request.getParameter("language").trim();
027 
028//签名类型.固定值
029///1代表MD5签名
030///当前版本固定为1
031String signType=(String)request.getParameter("signType").trim();
032 
033//获取支付方式
034///值为:10、11、12、13、14
035///00:组合支付(网关支付页面显示快钱支持的各种支付方式,推荐使用)10:银行卡支付(网关支付页面只显示银行卡支付).11:电话银行支付(网关支付页面只显示电话支付).12:快钱账户支付(网关支付页面只显示快钱账户支付).13:线下支付(网关支付页面只显示线下支付方式).14:B2B支付(网关支付页面只显示B2B支付,但需要向快钱申请开通才能使用)
036String payType=(String)request.getParameter("payType").trim();
037 
038//获取银行代码
039///参见银行代码列表
040String bankId=(String)request.getParameter("bankId").trim();
041 
042//获取商户订单号
043String orderId=(String)request.getParameter("orderId").trim();
044 
045//获取订单提交时间
046///获取商户提交订单时的时间.14位数字。年[4位]月[2位]日[2位]时[2位]分[2位]秒[2位]
047///如:20080101010101
048String orderTime=(String)request.getParameter("orderTime").trim();
049 
050//获取原始订单金额
051///订单提交到快钱时的金额,单位为分。
052///比方2 ,代表0.02元
053String orderAmount=(String)request.getParameter("orderAmount").trim();
054 
055//获取快钱交易号
056///获取该交易在快钱的交易号
057String dealId=(String)request.getParameter("dealId").trim();
058 
059//获取银行交易号
060///如果使用银行卡支付时,在银行的交易号。如不是通过银行支付,则为空
061String bankDealId=(String)request.getParameter("bankDealId").trim();
062 
063//获取在快钱交易时间
064///14位数字。年[4位]月[2位]日[2位]时[2位]分[2位]秒[2位]
065///如;20080101010101
066String dealTime=(String)request.getParameter("dealTime").trim();
067 
068//获取实际支付金额
069///单位为分
070///比方 2 ,代表0.02元
071String payAmount=(String)request.getParameter("payAmount").trim();
072 
073//获取交易手续费
074///单位为分
075///比方 2 ,代表0.02元
076String fee=(String)request.getParameter("fee").trim();
077 
078//获取扩展字段1
079String ext1=(String)request.getParameter("ext1").trim();
080 
081//获取扩展字段2
082String ext2=(String)request.getParameter("ext2").trim();
083 
084//获取处理结果
085///10代表 成功11代表 失败
086///00代表 下订单成功(仅对电话银行支付订单返回);01代表 下订单失败(仅对电话银行支付订单返回)
087String payResult=(String)request.getParameter("payResult").trim();
088 
089//获取错误代码
090///详细见文档错误代码列表
091String errCode=(String)request.getParameter("errCode").trim();
092 
093//获取加密签名串
094String signMsg=(String)request.getParameter("signMsg").trim();
095 
096//生成加密串。必须保持如下顺序。
097    String merchantSignMsgVal="";
098    merchantSignMsgVal=appendParam(merchantSignMsgVal,"merchantAcctId",merchantAcctId);
099    merchantSignMsgVal=appendParam(merchantSignMsgVal,"version",version);
100    merchantSignMsgVal=appendParam(merchantSignMsgVal,"language",language);
101    merchantSignMsgVal=appendParam(merchantSignMsgVal,"signType",signType);
102    merchantSignMsgVal=appendParam(merchantSignMsgVal,"payType",payType);
103    merchantSignMsgVal=appendParam(merchantSignMsgVal,"bankId",bankId);
104    merchantSignMsgVal=appendParam(merchantSignMsgVal,"orderId",orderId);
105    merchantSignMsgVal=appendParam(merchantSignMsgVal,"orderTime",orderTime);
106    merchantSignMsgVal=appendParam(merchantSignMsgVal,"orderAmount",orderAmount);
107    merchantSignMsgVal=appendParam(merchantSignMsgVal,"dealId",dealId);
108    merchantSignMsgVal=appendParam(merchantSignMsgVal,"bankDealId",bankDealId);
109    merchantSignMsgVal=appendParam(merchantSignMsgVal,"dealTime",dealTime);
110    merchantSignMsgVal=appendParam(merchantSignMsgVal,"payAmount",payAmount);
111    merchantSignMsgVal=appendParam(merchantSignMsgVal,"fee",fee);
112    merchantSignMsgVal=appendParam(merchantSignMsgVal,"ext1",ext1);
113    merchantSignMsgVal=appendParam(merchantSignMsgVal,"ext2",ext2);
114    merchantSignMsgVal=appendParam(merchantSignMsgVal,"payResult",payResult);
115    merchantSignMsgVal=appendParam(merchantSignMsgVal,"errCode",errCode);
116    merchantSignMsgVal=appendParam(merchantSignMsgVal,"key",key);
117 
118    String merchantSignMsg=MD5Util.md5Hex(merchantSignMsgVal.getBytes("UTF-8")).toUpperCase();
119//初始化结果及地址
120int rtnOk=0;
121String rtnUrl="";
122 
123//商家进行数据处理,并跳转回商家显示支付结果的页面
124///首先进行签名字符串验证
125if(signMsg.toUpperCase().equals(merchantSignMsg.toUpperCase())){
126    ///接着进行支付结果判断
127    switch(Integer.parseInt(payResult)){   
128      case 10:
129        // 商户网站逻辑处理,比方更新订单支付状态为成功
130        // 特别注意:只有signMsg.toUpperCase().equals(merchantSignMsg.toUpperCase()),且payResult=10,才表示支付成功
131        //报告给快钱处理结果,并提供将要重定向的地址。
132        rtnOk=1;
133        rtnUrl="http://www.yoursite.com/show.jsp?msg=success!";
134        break;       
135     default:
136        rtnOk=1;
137        rtnUrl="http://www.yoursite.com/show.jsp?msg=false!";
138        break;
139    }
140}else{
141    rtnOk=1;
142    rtnUrl="http://www.yoursite.com/show.jsp?msg=error!";
143}
144 
145%>
146<%!
147    //功能函数。将变量值不为空的参数组成字符串
148    public String appendParam(String returnStr,String paramId,String paramValue) {
149        if(!returnStr.equals("")) {
150            if(!paramValue.equals(""))
151            {
152                returnStr=returnStr+"&"+paramId+"="+paramValue;
153            }
154        } else {
155            if(!paramValue.equals(""))
156            {
157            returnStr=paramId+"="+paramValue;
158            }
159        }  
160        return returnStr;
161    }
162    //功能函数。将变量值不为空的参数组成字符串。结束
163//以下报告给快钱处理结果,并提供将要重定向的地址
164%>
165<result><%=rtnOk %></result><redirecturl><%=rtnUrl %></redirecturl>

上壹页的代码是receive.jsp,它是快钱完成它的任务之后返回我们的信息接收页面,返回时会携带所有我们刚才提交的参数以及完成支付时用到的壹些信息,如交易号、银行标识号、商户号、支付成功或者失败时的标识码等。这个页面有壹个特别的地方在于它底部的那个字符串,通过与快钱技术部门沟通之后得知,它是用于再壹次发送到快钱时必须的内容,用于告诉快钱本次提交是成功还是失败,其中的参数rtnOk是状态标识码,rtnUrl则是快钱系统回调我们的应用时要用到的请求地址,这个地址必须是公网地址,也就是说,它必须能够通过公共网络被快钱访问到,不可以是局域网地址如http://127.0.0.1:8080/之类,而应该是类似于http://www.google.com.sg/这种。

在这个页面的请求发送之后,接下来就是我们自己的应用的页面了,快钱也提供了壹个简单的样例页面来展示它,内容如下:

01<%@page contentType="text/html; charset=UTF-8" language="java"%>
02<%
03/*
04* @Description: 快钱人民币支付网关接口范例
05* @Copyright (c) 上海快钱信息服务有限公司
06* @version 2.0
07*/
08 
09/*
10在本文件中,商家应从数据库中,查询到订单的状态信息以及订单的处理结果。给出支付人响应的提示。
11本范例采用最简单的模式,直接从receive页面获取支付状态提示给用户。
12*/
13String orderId=(String)request.getParameter("orderId").trim();
14String orderAmount=(String)request.getParameter("orderAmount").trim();
15String msg=(String)request.getParameter("msg").trim();
16%>
17<!doctype html public "-//w3c//dtd html 4.0 transitional//en" >
18<html>
19    <head>
20        <title>快钱支付结果</title>
21        <meta http-equiv="content-type" content="text/html; charset=UTF-8" >
22    </head>  
23<body>
24    <div align="center">
25        <table width="259" border="0" cellpadding="1" cellspacing="1" bgcolor="#CCCCCC" >
26            <tr bgcolor="#FFFFFF">
27                <td width="80">支付方式:</td>
28                <td >快钱[99bill]</td>
29            </tr>
30            <tr bgcolor="#FFFFFF">
31                <td >订单编号:</td>
32                <td ><%=orderId %></td>
33            </tr>
34            <tr bgcolor="#FFFFFF">
35                <td>订单金额:</td>
36                <td><%=(orderAmount)+"分" %></td>
37            </tr>
38            <tr bgcolor="#FFFFFF">
39                <td>支付结果:</td>
40                <td><%=msg %></td>
41            </tr>
42            <tr>
43                <td></td>
44                <td></td>
45            </tr>
46      </table>
47    </div>
48</body>
49</html>

上面这个页面中的内容,其实我们可以随便的自定义,这里只是提供个样例,没有什么特别的内容,照着做就行了。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值