最近在做中国电信的翼支付网关接口的接入,正好拿Java练练手。到目前为止,唯一不太适应的就是自己的Java积累几乎为0,什么都要重头写起,不像C#有这么多年的沉淀,可以随手拿来用。
废话先不多说。这个支付接口就和支付宝差不多,无非就是把一些必要的数据参数,POST到指定的接口地址,然后接收它返回的支付结果。接口没有什么复杂的逻辑处理,所以可以直接采用JSP+Servlet+JDBC来做简单处理。对于WEB支付请求的发起,可以从JSP把用户输入或选择的相关数据传到Servlet,然后在Servlet里把商户的基本信息以及用户数据封装下,再统一POST到网关接口地址:
1 StringBuffer stb = new StringBuffer(); 2 stb.append("<html>"); 3 stb.append("<head><title>你的Title</title></head>"); 4 stb.append("<body onload="document.form1.submit()">"); 5 stb.append("<form name="form1" method="post" action="https://webpaywg.bestpay.com.cn/payWeb.do" >"); 6 stb.append(String.format("<input name="MERCHANTID" type="hidden" value="%s">", merchantId)); //商戶号 7 stb.append(String.format("<input name="ORDERSEQ" type="hidden" value="%s">", orderSeq)); //订单号 8 stb.append(String.format("<input name="ORDERREQTRANSEQ" type="hidden" value="%s">", orderSeq)); //订单请求交易流水号 9 stb.append(String.format("<input name="ORDERDATE" type="hidden" value="%s">", orderDate)); //订单日期 10 stb.append(String.format("<input name="ORDERAMOUNT" type="hidden" value="%s">", orderAmount)); //订单总金额 11 stb.append(String.format("<input name="PRODUCTAMOUNT" type="hidden" value="%s">", orderAmount)); //产品金额 12 stb.append("<input name="ATTACHAMOUNT" type="hidden" value="0">"); //附加金额 13 stb.append("<input name="CURTYPE" type="hidden" value="RMB">"); //币种 14 stb.append("<input name="ENCODETYPE" type="hidden" value="1">"); //加密方式 MD5 15 stb.append(String.format("<input name="MERCHANTURL" type="hidden" value="%s">", merchantUrl)); //前台返回地址 16 stb.append(String.format("<input name="BACKMERCHANTURL" type="hidden" value="%s">", backMerchantUrl)); //后台返回地址 17 stb.append(String.format("<input name="ATTACH" type="hidden" value="%s">", attach)); //商户附加信息 18 stb.append("<input name="BUSICODE" type="hidden" value="0001">"); //业务类型 19 stb.append("<input name="PRODUCTID" type="hidden" value="08">"); // 业务标识 20 stb.append(String.format("<input name="TMNUM" type="hidden" value="%s">", tmNum)); //终端号码 21 stb.append(String.format("<input name="CUSTOMERID" type="hidden" value="%s">", customerId)); //客户标识 22 stb.append(String.format("<input name="PRODUCTDESC" type="hidden" value="%s">", productDes)); //产品描述 23 stb.append(String.format("<input name="MAC" type="hidden" value="%s">", mac)); //MAC校验域 24 stb.append(String.format("<input name="CLIENTIP" type="hidden" value="%s">", clientIp)); //客户端IP 25 stb.append("</form></body>"); 26 stb.append("</html>"); 27 //入库、记录日志等 28 response.setContentType("text/html"); 29 response.setCharacterEncoding("UTF-8"); 30 PrintWriter out = response.getWriter(); 31 out.write(stb.toString());
这里需要注意的是MAC这个值,翼支付网关会对这个值做校验;接口文档中提供了这个值的加密和MD5摘要算法样例,所以只要按照文档描述的规则来,一般不会有没有什么问题。上面的参数中,有一个前台返回地址和后台返回地址,当用户通过网银完成支付后,翼支付网关会把用户此次的支付结果POST到这2个地址,所以前台地址可以把支付结果展示给用户,后台地址的话就用来处理商户的业务逻辑吧。毕竟前台地址可能不会达到用户侧,或者用户在支付完成后就直接关了当前窗口。另外后台地址在接收到支付结果数据后,一定要原路响应网关,不然网关那边会不定时的持续发送重复的支付结果过来:
1 request.setCharacterEncoding("UTF-8"); 2 String uptranSeq = request.getParameter("UPTRANSEQ"); //翼支付网关平台交易流水号 3 String tranDate = request.getParameter("TRANDATE"); //翼支付网关平台交易日期 4 String returnCode = request.getParameter("RETNCODE"); //处理结果码 “0000” 表示支付成功,其他值则表示支付失败 5 String retuInfo = request.getParameter("RETNINFO"); //处理结果解释码 6 if(retuInfo != null && !retuInfo.isEmpty()) { 7 retuInfo = URLDecoder.decode(retuInfo, "UTF-8"); 8 } 9 String orderReqTranseq = request.getParameter("ORDERREQTRANSEQ"); //订单请求交易流水号 10 String orderReq = request.getParameter("ORDERSEQ"); //订单号 11 String orderAmount = request.getParameter("ORDERAMOUNT"); //订单总金额 12 String productAmount = request.getParameter("PRODUCTAMOUNT"); //产品金额 13 String attachMount = request.getParameter("ATTACHAMOUNT"); //附加金额 14 String curType = request.getParameter("CURTYPE"); //币种 15 String encodeType = request.getParameter("ENCODETYPE"); //加密方式 16 String bankId = request.getParameter("BANKID"); //银行编码 17 String attach = request.getParameter("ATTACH"); //商户附加信息 18 String upreqTranseq = request.getParameter("UPREQTRANSEQ"); //网关平台请求银行流水号 19 String upbankTranseq = request.getParameter("UPBANKTRANSEQ"); //银行流水号 20 String productNo = request.getParameter("PRODUCTNO"); //产品号码 21 String sign = request.getParameter("SIGN"); //数字签名 22 //对sign做数字签名校验(信息没有被篡改) 23 //商户业务逻辑处理、入库、日志等 24 String returnContent = "UPTRANSEQ_" + uptranSeq; 25 PrintWriter out = response.getWriter(); 26 out.write(returnContent); //回写响应数据
WEB支付的处理主要就是这块,很好理解吧!
至于退款接口,则是需要调用网关提供的WebService接口,如下所示,refundResult就是返回的退款结果了:
1 //Axis 2 refundV2.webservice.ideal.com.RefundServiceFenImplProxy teStub = new RefundServiceFenImplProxy(); 3 String refundResult = teStub.refund(commCode, "", commPwd, oldOrderId, oldOrderPayId, orderRefundId, transamt, reqTime, mac);
最后再记录下,在写一个简单的日志记录类时,本机开发环境的路径中又有空格又有中文。。。这样的话,采用 .getResource("").toURI().getPath() 方法来获取路径,就不怕任何奇特格式的路径了~~~