javaweb實(shí)現(xiàn)在線支付功能
1、在線支付概述
什么是在線支付呢?沒錯(cuò),就是在網(wǎng)上花錢!大家一定有過這樣的經(jīng)歷。但是你可能不太了解在線支付的“內(nèi)情”,下面我們來(lái)了解一下!
如果你現(xiàn)在開始經(jīng)營(yíng)一個(gè)電子商務(wù)網(wǎng)站,用戶買了東西一定要支付,你的網(wǎng)站一定要可以連接各大銀行了,然后在各大銀行支付完成后,再返回到你的網(wǎng)站上顯示“支付成功”!
這就是今天我們要做的事情,連接銀行的網(wǎng)銀系統(tǒng)完成支付。說(shuō)專業(yè)一點(diǎn),我們稱之為“開發(fā)在線支付的網(wǎng)關(guān)”
2、兩種在線支付的方式
在線支付一共有兩種方式:
*電商直接與銀行對(duì)接
*電商通過第三方支付平臺(tái)與銀行對(duì)接
電商直接與銀行對(duì)接,這也要銀行同意才行,但可惜的是,銀行很“牛”,不是誰(shuí)想與它對(duì)接都可以的。如果你的電商每日的資金流量夠大,那么銀行會(huì)和你對(duì)接,因?yàn)榭蛻糁Ц督o電商的錢都存到了銀行的帳戶中!但是如果資金流量小,銀行不會(huì)理你的!
當(dāng)小網(wǎng)站資金量不足時(shí),不能與銀行對(duì)接,那么它們會(huì)選擇與第三方支付公司合作。大家也都明白這是些什么公司,例如:支付寶、易寶、財(cái)富通、快錢等公司是國(guó)內(nèi)比較有名的。它們這些公司可以與銀行對(duì)接(因?yàn)橘Y金夠多),然后小電商與它們對(duì)接!但是第三方是要求收費(fèi)的!第三方一般會(huì)收取電商1%的費(fèi)用,不過不會(huì)收客戶的錢。

通過上圖大家可以了解到,在銀行的頁(yè)面上會(huì)顯示出商城名稱、RMB訂單號(hào)、訂單時(shí)間。。。,這些東西銀行是怎么知道的,當(dāng)然是電商傳遞給銀行的。當(dāng)電商與銀行對(duì)接后,電商要給銀行的頁(yè)面?zhèn)鬟f銀行頁(yè)面需要的參數(shù),所以銀行的頁(yè)面才能顯示這些數(shù)據(jù)!
但是,我們的商城不能只可以對(duì)接一家銀行吧!怎么也要對(duì)接BOC、CCB、ABC、ICBC四家吧!不同的銀行需要的對(duì)接參數(shù)是不相同的,這說(shuō)明我們?cè)陂_發(fā)時(shí)要為不同的銀行寫不同的對(duì)接代碼。這也是直接與銀行對(duì)接的缺點(diǎn)!當(dāng)然與銀行直接對(duì)接也有好處,就是安全,沒有手續(xù)費(fèi)!
為不同的銀行開發(fā)不同的代碼(缺點(diǎn));
安全(優(yōu)點(diǎn));
沒有手續(xù)費(fèi)(優(yōu)點(diǎn));
小電商銀行不讓對(duì)接(缺點(diǎn))。

上圖中已經(jīng)說(shuō)明,客戶在電商的網(wǎng)站上點(diǎn)擊確認(rèn)支付后,會(huì)定向到第三方的網(wǎng)站,然后再由第三方與銀行對(duì)接。這說(shuō)明電商要傳遞給第三方參數(shù)!再由第三方把參數(shù)傳遞給銀行。這種方式的好處是:只需要針對(duì)第三方開發(fā)即可,而不用再為每家銀行提供參數(shù)。為每家銀行提供參數(shù)的工作是第三方的任務(wù)了。但是,第三方不老可靠的,如果第三方倒閉了,人跑了,那你的錢就沒了。因?yàn)榭蛻糁Ц兜腻X沒有到你的銀行帳戶中,而是支付到了第三方的銀行帳戶中,而你是在第三方有一個(gè)帳戶。而且第三方還要收手續(xù)費(fèi),一般是1%,這可不是小數(shù)字啊(真黑)。
3、通過第三方在線支付規(guī)則
電商想在第三方注冊(cè)商戶,需要向第三方提供ICP認(rèn)證。ICP經(jīng)營(yíng)許可證是根據(jù)國(guó)家《互聯(lián)網(wǎng)管理辦法規(guī)定》,經(jīng)營(yíng)性網(wǎng)站必須辦理的網(wǎng)站經(jīng)營(yíng)許可證,沒有就屬于非法經(jīng)營(yíng)。
我們不可能因?yàn)榫毩?xí)就去辦理ICP!所以我們無(wú)法在第三方注冊(cè)商戶。不過我們已經(jīng)有現(xiàn)成的在易寶注冊(cè)的商戶,所以這一步就可以忽略了。
當(dāng)你在易寶注冊(cè)成功后,易寶會(huì)給你如下幾樣?xùn)|西:
在易寶的開戶賬號(hào)(即商戶編碼):10001126856
易寶接入規(guī)范:一個(gè)chm文件
對(duì)稱加密算法類:PaymentUtil.java
密鑰:69cl522AV6q613Ii4W6u8K6XuW8vM1N6bFgyv769220IuYe9u37N4y7rI4Pl
在易寶接入規(guī)范中,我們可以查找到易寶的支付網(wǎng)關(guān),其實(shí)就是一個(gè)URL,用來(lái)與易寶對(duì)接的一個(gè)網(wǎng)址:https://www.yeepay.com/app-merchant-proxy/node
在易寶接入規(guī)范中,還可以查找到易寶要求的參數(shù),在電商與易寶對(duì)接時(shí)需要給支付網(wǎng)關(guān)傳遞這些參數(shù):
正式請(qǐng)求地址:https://www.yeepay.com/app-merchant-proxy/node

這些參數(shù)需要追加到URL后面。
但是要注意,這些參數(shù)的值需要加密。加密的密鑰和加密算法易寶都會(huì)提供!
其中p8_Url表示當(dāng)支付成功后,返回到電商的哪個(gè)頁(yè)面。這說(shuō)明我們需要寫一個(gè)顯示結(jié)果的頁(yè)面。第三方在支付成功后,會(huì)重定向到我們指定的返回頁(yè)面,而且還會(huì)帶給我們一些參數(shù),我們的頁(yè)面需要獲取這些參數(shù),顯示在頁(yè)面中。下面是第三方返回的參數(shù):

4、開發(fā)第三方在線支付系統(tǒng)
步驟:
index.jsp頁(yè)面:一個(gè)表單,提交到BuyServlet,表單項(xiàng)有:訂單編號(hào)、付款金額、選擇銀行
BuyServlet:獲取表單數(shù)據(jù),準(zhǔn)備連接第三方網(wǎng)關(guān)。因?yàn)樵趇ndex.jsp頁(yè)面中只給出3個(gè)參數(shù),而第三方需要的參數(shù)有N多,頁(yè)面沒有給出的參數(shù)由BuyServlet補(bǔ)充。而且參數(shù)還需要加密,這也需要在BuyServlet中完成
BackServlet:當(dāng)用戶支付成功后,第三方會(huì)重定向到我們指定的返回頁(yè)面,我們使用BackServlet作為返回頁(yè)面,它用來(lái)接收第三方傳遞的參數(shù),顯示在頁(yè)面中
因?yàn)橐呀?jīng)有了在易寶的注冊(cè)商號(hào),所以我們就不用自己去注冊(cè)商號(hào)了。所以這里使用易寶做為第三方支付平臺(tái)來(lái)測(cè)試。因?yàn)槲冶救藳]有電商(必須通過ICP認(rèn)證的電商),所以也不能在第三方注冊(cè)商號(hào)。
我們現(xiàn)在使用的易寶商號(hào)是由傳智播客提供的,巴巴運(yùn)動(dòng)網(wǎng)在易寶注冊(cè)的商號(hào)。所以在測(cè)試時(shí)支付的錢都給了巴巴運(yùn)動(dòng)網(wǎng)在易寶注冊(cè)的商號(hào)了。
第一步:index.jsp
<form action="" method="post"> 訂單號(hào):<input type="text" name="p2_Order"/><br/> 金 額:<input type="text" name="p3_Amt"/><br/> 選擇銀行:<br/> <input type="radio" name="pd_FrpId" value="ICBC-NET-B2C"/>工商銀行 <img src="bank_img/icbc.bmp" align="middle"/> <input type="radio" name="pd_FrpId" value="BOC-NET-B2C"/>中國(guó)銀行 <img src="bank_img/bc.bmp" align="middle"/><br/><br/> <input type="radio" name="pd_FrpId" value="ABC-NET-B2C"/>農(nóng)業(yè)銀行 <img src="bank_img/abc.bmp" align="middle"/> <input type="radio" name="pd_FrpId" value="CCB-NET-B2C"/>建設(shè)銀行 <img src="bank_img/ccb.bmp" align="middle"/><br/><br/> <input type="radio" name="pd_FrpId" value="BOCO-NET-B2C"/>交通銀行 <img src="bank_img/bcc.bmp" align="middle"/><br/> <input type="submit" value="確認(rèn)支付"/> </form>

每個(gè)銀行對(duì)應(yīng)的值:

第二步:BuyServlet.java
public class BuyServlet extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
String p0_Cmd = "Buy";// 業(yè)務(wù)類型,固定值為buy,即“買”
String p1_MerId = "10001126856";// 在易寶注冊(cè)的商號(hào)
String p2_Order = request.getParameter("p2_Order");// 訂單編號(hào)
String p3_Amt = request.getParameter("p3_Amt");// 支付的金額
String p4_Cur = "CNY";// 交易種幣,固定值為CNY,表示人民幣
String p5_Pid = "";// 商品名稱
String p6_Pcat = "";// 商品各類
String p7_Pdesc = "";// 商品描述
String p8_Url = "http://localhost:8080/buy/BackServlet";// 電商的返回頁(yè)面,當(dāng)支付成功后,易寶會(huì)重定向到這個(gè)頁(yè)面
String p9_SAF = "";// 送貨地址
String pa_MP = "";// 商品擴(kuò)展信息
String pd_FrpId = request.getParameter("pd_FrpId");// 支付通道,即選擇銀行
String pr_NeedResponse = "1";// 應(yīng)答機(jī)制,固定值為1
// 密鑰,由易寶提供,只有商戶和易寶知道這個(gè)密鑰。
String keyValue = "69cl522AV6q613Ii4W6u8K6XuW8vM1N6bFgyv769220IuYe9u37N4y7rI4Pl";
// 通過上面的參數(shù)、密鑰、加密算法,生成hmac值
// 參數(shù)的順序是必須的,如果沒有值也不能給出null,而應(yīng)該給出空字符串。
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, keyValue);
// 把所有參數(shù)連接到網(wǎng)關(guān)地址后面
String url = "https://www.yeepay.com/app-merchant-proxy/node";
url += "?p0_Cmd=" + p0_Cmd +
"&p1_MerId=" + p1_MerId +
"&p2_Order=" + p2_Order +
"&p3_Amt=" + p3_Amt +
"&p4_Cur=" + p4_Cur +
"&p5_Pid=" + p5_Pid +
"&p6_Pcat=" + p6_Pcat +
"&p7_Pdesc=" + p7_Pdesc +
"&p8_Url=" + p8_Url +
"&p9_SAF=" + p9_SAF +
"&pa_MP=" + pa_MP +
"&pd_FrpId=" + pd_FrpId +
"&pr_NeedResponse=" + pr_NeedResponse +
"&hmac=" + hmac;
System.out.println(url);
// 重定向到網(wǎng)關(guān)
response.sendRedirect(url);
}
}
第三步:BackServlet
public class BackServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
/*
* 易寶會(huì)提供一系列的結(jié)果參數(shù),我們獲取其中需要的即可
* 獲取支付結(jié)果:r1_Code,1表示支付成功。
* 獲取支付金額:r3_Amt
* 獲取電商的訂單號(hào):r6_Order
* 獲取結(jié)果返回類型:r9_BType,1表示重定向返回,2表示點(diǎn)對(duì)點(diǎn)返回,
* 但點(diǎn)對(duì)點(diǎn)我們收不到,因?yàn)槲覀兊膇p都是局域網(wǎng)ip。
*/
String r1_Code = request.getParameter("r1_Code");
String r3_Amt = request.getParameter("r3_Amt");
String r6_Order = request.getParameter("r6_Order");
String r9_BType = request.getParameter("r9_BType");
if(r1_Code.equals("1")) {
if(r9_BType.equals("1")) {
response.getWriter().print("<h1>支付成功!</h1>");//其實(shí)支付不成功時(shí)根本易寶根本就不會(huì)返回到本Servlet
response.getWriter().print("支付金額為:" + r3_Amt + "<br/>");
response.getWriter().print("訂單號(hào)為:" + r6_Order + "<br/>");
}
}
}
}
易寶支付提供的獲取hmac的工具類
public class PaymentUtil {
private static String encodingCharset = "UTF-8";
/**
* 生成hmac方法
*
* @param p0_Cmd 業(yè)務(wù)類型
* @param p1_MerId 商戶編號(hào)
* @param p2_Order 商戶訂單號(hào)
* @param p3_Amt 支付金額
* @param p4_Cur 交易幣種
* @param p5_Pid 商品名稱
* @param p6_Pcat 商品種類
* @param p7_Pdesc 商品描述
* @param p8_Url 商戶接收支付成功數(shù)據(jù)的地址
* @param p9_SAF 送貨地址
* @param pa_MP 商戶擴(kuò)展信息
* @param pd_FrpId 銀行編碼
* @param pr_NeedResponse 應(yīng)答機(jī)制
* @param keyValue 商戶密鑰
* @return
*/
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) {
StringBuilder sValue = new StringBuilder();
// 業(yè)務(wù)類型
sValue.append(p0_Cmd);
// 商戶編號(hào)
sValue.append(p1_MerId);
// 商戶訂單號(hào)
sValue.append(p2_Order);
// 支付金額
sValue.append(p3_Amt);
// 交易幣種
sValue.append(p4_Cur);
// 商品名稱
sValue.append(p5_Pid);
// 商品種類
sValue.append(p6_Pcat);
// 商品描述
sValue.append(p7_Pdesc);
// 商戶接收支付成功數(shù)據(jù)的地址
sValue.append(p8_Url);
// 送貨地址
sValue.append(p9_SAF);
// 商戶擴(kuò)展信息
sValue.append(pa_MP);
// 銀行編碼
sValue.append(pd_FrpId);
// 應(yīng)答機(jī)制
sValue.append(pr_NeedResponse);
return PaymentUtil.hmacSign(sValue.toString(), keyValue);
}
/**
* 返回校驗(yàn)hmac方法
*
* @param hmac 支付網(wǎng)關(guān)發(fā)來(lái)的加密驗(yàn)證碼
* @param p1_MerId 商戶編號(hào)
* @param r0_Cmd 業(yè)務(wù)類型
* @param r1_Code 支付結(jié)果
* @param r2_TrxId 易寶支付交易流水號(hào)
* @param r3_Amt 支付金額
* @param r4_Cur 交易幣種
* @param r5_Pid 商品名稱
* @param r6_Order 商戶訂單號(hào)
* @param r7_Uid 易寶支付會(huì)員ID
* @param r8_MP 商戶擴(kuò)展信息
* @param r9_BType 交易結(jié)果返回類型
* @param keyValue 密鑰
* @return
*/
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) {
StringBuilder sValue = new StringBuilder();
// 商戶編號(hào)
sValue.append(p1_MerId);
// 業(yè)務(wù)類型
sValue.append(r0_Cmd);
// 支付結(jié)果
sValue.append(r1_Code);
// 易寶支付交易流水號(hào)
sValue.append(r2_TrxId);
// 支付金額
sValue.append(r3_Amt);
// 交易幣種
sValue.append(r4_Cur);
// 商品名稱
sValue.append(r5_Pid);
// 商戶訂單號(hào)
sValue.append(r6_Order);
// 易寶支付會(huì)員ID
sValue.append(r7_Uid);
// 商戶擴(kuò)展信息
sValue.append(r8_MP);
// 交易結(jié)果返回類型
sValue.append(r9_BType);
String sNewString = PaymentUtil.hmacSign(sValue.toString(), keyValue);
return sNewString.equals(hmac);
}
/**
* @param aValue
* @param aKey
* @return
*/
public static String hmacSign(String aValue, String aKey) {
byte k_ipad[] = new byte[64];
byte k_opad[] = new byte[64];
byte keyb[];
byte value[];
try {
keyb = aKey.getBytes(encodingCharset);
value = aValue.getBytes(encodingCharset);
} catch (UnsupportedEncodingException e) {
keyb = aKey.getBytes();
value = aValue.getBytes();
}
Arrays.fill(k_ipad, keyb.length, 64, (byte) 54);
Arrays.fill(k_opad, keyb.length, 64, (byte) 92);
for (int i = 0; i < keyb.length; i++) {
k_ipad[i] = (byte) (keyb[i] ^ 0x36);
k_opad[i] = (byte) (keyb[i] ^ 0x5c);
}
MessageDigest md = null;
try {
md = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
return null;
}
md.update(k_ipad);
md.update(value);
byte dg[] = md.digest();
md.reset();
md.update(k_opad);
md.update(dg, 0, 16);
dg = md.digest();
return toHex(dg);
}
public static String toHex(byte input[]) {
if (input == null)
return null;
StringBuffer output = new StringBuffer(input.length * 2);
for (int i = 0; i < input.length; i++) {
int current = input[i] & 0xff;
if (current < 16)
output.append("0");
output.append(Integer.toString(current, 16));
}
return output.toString();
}
/**
*
* @param args
* @param key
* @return
*/
public static String getHmac(String[] args, String key) {
if (args == null || args.length == 0) {
return (null);
}
StringBuffer str = new StringBuffer();
for (int i = 0; i < args.length; i++) {
str.append(args[i]);
}
return (hmacSign(str.toString(), key));
}
/**
* @param aValue
* @return
*/
public static String digest(String aValue) {
aValue = aValue.trim();
byte value[];
try {
value = aValue.getBytes(encodingCharset);
} catch (UnsupportedEncodingException e) {
value = aValue.getBytes();
}
MessageDigest md = null;
try {
md = MessageDigest.getInstance("SHA");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
return toHex(md.digest(value));
}
// public static void main(String[] args) {
// System.out.println(hmacSign("AnnulCard1000043252120080620160450.0http://localhost/SZXpro/callback.asp榪?4564868265473632445648682654736324511","8UPp0KE8sq73zVP370vko7C39403rtK1YwX40Td6irH216036H27Eb12792t"));
// }
}
易寶回調(diào)
點(diǎn)對(duì)點(diǎn):易寶直接訪問電商,這里沒有客戶端什么事了
這種方式是必須要使用的,我們這種方式是收不到的!因?yàn)槲覀儧]有固定IP
易寶有一個(gè)重發(fā)機(jī)制,如果它訪問你,你不給它回信息,它會(huì)一直重發(fā)!
電商需要返回一個(gè)以SUCCESS開頭的字符串即可!
引導(dǎo)客戶端瀏覽器重定向到電商。是讓客戶端訪問電商!
可以不使用的!
hmac:13參數(shù)值+keyValue(密鑰) + 算法(md5)
13參數(shù)值:自己設(shè)置的!
keyValue:易寶在我們注冊(cè)后發(fā)給我們的,這個(gè)東東只有我們和易寶知道!
底層為md5的算法:PaymentUtil.buildHmac(14個(gè)),它返回hmac
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Javaweb監(jiān)聽器實(shí)例之統(tǒng)計(jì)在線人數(shù)
- java web監(jiān)聽器統(tǒng)計(jì)在線用戶及人數(shù)
- Java中使用websocket實(shí)現(xiàn)在線聊天功能
- javaweb在線支付功能實(shí)現(xiàn)代碼
- Java web實(shí)現(xiàn)賬號(hào)單一登錄,防止同一賬號(hào)重復(fù)登錄(踢人效果)
- Linux服務(wù)器部署JavaWeb項(xiàng)目完整教程
- Java解析調(diào)用webservice服務(wù)的返回XML串詳解
- Javaweb實(shí)現(xiàn)在線人數(shù)統(tǒng)計(jì)代碼實(shí)例
相關(guān)文章
Mybatis動(dòng)態(tài)調(diào)用表名和字段名的解決方法
今天在項(xiàng)目開發(fā)中有個(gè)業(yè)務(wù)是需要限制各個(gè)用戶對(duì)某些表里的字段查詢以及某些字段是否顯示,這種情況下,就需要構(gòu)建sql來(lái)動(dòng)態(tài)傳入表名、字段名了,下面給大家介紹mybatis動(dòng)態(tài)調(diào)用表名和字段名的解決方法,一起看看吧2016-10-10
java定時(shí)任務(wù)Timer和TimerTask使用詳解
這篇文章主要為大家詳細(xì)介紹了java定時(shí)任務(wù)Timer和TimerTask使用方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-02-02
SpringCloud注冊(cè)中心之consul詳細(xì)講解使用方法
Consul是一款由HashiCorp公司開源的,用于服務(wù)治理的軟件,Spring Cloud Consul對(duì)其進(jìn)行了封裝,這篇文章主要介紹了springcloud組件consul服務(wù)治理,需要的朋友可以參考下2022-11-11
詳解Spring MVC/Boot 統(tǒng)一異常處理最佳實(shí)踐
在 Web 開發(fā)中, 我們經(jīng)常會(huì)需要處理各種異常,這篇文章主要介紹了詳解Spring MVC/Boot 統(tǒng)一異常處理最佳實(shí)踐,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01
Mybatis全局配置及映射關(guān)系的實(shí)現(xiàn)
本文主要介紹了Mybatis全局配置及映射關(guān)系的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03

