SSH框架網(wǎng)上商城項(xiàng)目第21戰(zhàn)之詳解易寶支付的流程
這一節(jié)我們先寫(xiě)一個(gè)簡(jiǎn)單點(diǎn)的Demo來(lái)測(cè)試易寶支付的流程,熟悉這個(gè)流程后,再做實(shí)際的開(kāi)發(fā),因?yàn)槭且粋€(gè)Demo,所以我沒(méi)有考慮一些設(shè)計(jì)模式的東西,就是直接實(shí)現(xiàn)支付功能。實(shí)現(xiàn)支付功能需要易寶給我們提供的API。那么問(wèn)題來(lái)了,使用第三方支付平臺(tái)最主要的一件事就是獲取該平臺(tái)的API,我們首先得獲取他們的API以及開(kāi)發(fā)文檔,然后才可以做進(jìn)一步的開(kāi)發(fā)。
1. 獲取易寶的API
獲取API的第一步,要在易寶上注冊(cè)一個(gè)賬號(hào),這個(gè)賬號(hào)是商家的賬號(hào),后面買(mǎi)家付款后,會(huì)將錢(qián)款存入該賬號(hào)中,然后商家自己提取到銀行卡,易寶在提取過(guò)程中收取一定的手續(xù)費(fèi)。這就是易寶的盈利模式。但是注冊(cè)成功需要前提,那就是自己得有一個(gè)網(wǎng)站,或者是一個(gè)公司,吧啦吧啦等東西,反正就是你得有資格申請(qǐng),這點(diǎn)易寶會(huì)審核的,滿足了才會(huì)允許你注冊(cè),才會(huì)給你提供他們的接口,不是所有人都可以注冊(cè)的。我用的也是別人注冊(cè)好的,我自己啥也沒(méi)有……也沒(méi)法注冊(cè)……屌絲一個(gè),大家懂的~但是一般在公司里開(kāi)發(fā)的話,就不會(huì)存在這個(gè)問(wèn)題,賬號(hào)肯定都是有的,最重要的是要掌握開(kāi)發(fā)流程和相關(guān)技術(shù)~
2. 測(cè)試支付流程
有了官方提供的API和技術(shù)文檔后,就可以著手開(kāi)發(fā)了,在這里主要寫(xiě)一個(gè)簡(jiǎn)單的demo來(lái)測(cè)試一下易寶支付的流程,demo的結(jié)構(gòu)很簡(jiǎn)單,一個(gè)servlet,一個(gè)filter,兩個(gè)jsp頁(yè)面和一個(gè)加密的工具類(lèi)。servlet與易寶服務(wù)器端打交道,我們做一些跟易寶接口相關(guān)的處理,filter是用來(lái)處理可能出現(xiàn)的中文亂碼問(wèn)題,兩個(gè)jsp中一個(gè)是前臺(tái)頁(yè)面。
我們先來(lái)分析一下支付請(qǐng)求的過(guò)程,如下所示:
好了,下面我們具體分析一下demo中的相關(guān)代碼:
2.1 前臺(tái)測(cè)試頁(yè)面
首先看一下前臺(tái)頁(yè)面index.jsp的具體代碼
<%@ page language="java" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>前臺(tái)首頁(yè)</title> </head> <body> <h1>在線支付演示</h1> <form action="${pageContext.request.contextPath }/servlet/PayServlet" method="post"> 此次購(gòu)物訂單編號(hào)<input type="text" name="p2_Order" /><br> money<input type="text" name="p3_Amt" value="0.01"/><br> 工商銀行<input type="radio" value="ICBC-NET" name="pd_FrpId"> 建設(shè)銀行<input type="radio" value="CCB-NET" name="pd_FrpId"><br> <input type="submit" value="submit" /> <input type="hidden" value="pay" name="status"/> </form> </body> </html>
從上面的jsp頁(yè)面中可以看出,這些input標(biāo)簽中的name屬性值都很奇怪,pi_功能(i=0,1,2,…,9),當(dāng)然i還有其他的值,這得參照易寶的官方文檔,這些name表示相對(duì)應(yīng)的屬性,到時(shí)候會(huì)傳到sevlet處理,關(guān)于這些屬性值,我截了個(gè)圖,如下:
這些參數(shù)名有些在實(shí)際項(xiàng)目中是前臺(tái)傳進(jìn)來(lái)的,比如上面寫(xiě)的訂單號(hào),要付多少錢(qián),這些在訂單確認(rèn)的時(shí)候都會(huì)帶過(guò)去,那么其他參數(shù),必填的話,需要在servlet里指定好,非必填字段的話,就可以為空,這里的空不是null,而是”“,后面servlet中會(huì)提到。
再看看兩個(gè)銀行中對(duì)應(yīng)的value值也是固定的,易寶會(huì)提供它所支持的所有銀行的value值,這些都是固定的,不能修改的。這里就寫(xiě)兩個(gè)銀行測(cè)試一下效果。
最后那個(gè)隱藏字段是用來(lái)在servlet中做判斷的,是支付還是支付成功后的返回,下面在sevlet中會(huì)說(shuō)明。
2.2 Servlet處理請(qǐng)求
servlet主要處理與易寶的相關(guān)請(qǐng)求,里面有兩個(gè)部分的內(nèi)容,一部分是向易寶發(fā)送明文和密文,另一部分是判斷易寶發(fā)過(guò)來(lái)的明文和密文,我們看看demo中具體的實(shí)現(xiàn)代碼:
public class PayServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String status = request.getParameter("status"); if (status.equals("pay")) { //index.jsp中隱藏字段傳來(lái)的是pay,所以處理支付這部分 // 加密的密鑰,用在加密算法中,由支付中介提供,每個(gè)商家獨(dú)一無(wú)二的 String keyValue = "w0P75wMZ203fr46r5i70V556WHFa94j14yW5J6vuh4yo3nRl5jsqF3c41677"; // 1: 給參數(shù)賦值,這些參數(shù)(即明文)都是易寶官方提供的文檔中所定義的,名字我們不能改 String p0_Cmd = formatString("Buy"); String p1_MerId = formatString("10000940764"); String p2_Order = formatString(request.getParameter("p2_Order")); String p3_Amt = formatString(request.getParameter("p3_Amt")); String p4_Cur = formatString("CNY"); String p5_Pid = ""; String p6_Pcat = ""; String p7_Pdesc = ""; String p8_Url = "http://www.#edu.cn";//這是支付成功后跳轉(zhuǎn)到的頁(yè)面,可以設(shè)為商城首頁(yè),這個(gè)demo就用同濟(jì)大學(xué)主頁(yè)好了…… String p9_SAF = "0"; String pa_MP = ""; String pd_FrpId = formatString(request.getParameter("pd_FrpId")); pd_FrpId = pd_FrpId.toUpperCase(); String pr_NeedResponse = "0"; String hmac = formatString("");//hmac是用來(lái)存儲(chǔ)密文的 /*上面所有的明文都用都用formatString方法包裝了一下,該方法在下面,主要是將null轉(zhuǎn)換成"" *因?yàn)閚ull是無(wú)法轉(zhuǎn)換成密文的*/ // 解決數(shù)據(jù)安全性問(wèn)題: 把明文加密--->密文 然后把明文和密文都交給易寶 // 易寶拿到數(shù)據(jù)后,把傳過(guò)來(lái)的明文加密, 和傳過(guò)來(lái)密文比較, // 如果相等數(shù)據(jù)沒(méi)有被篡改 (商家與易寶加密時(shí)都用的是相同key) // 把明文數(shù)據(jù)追加到StringBuffer,注意追加順序不能改,否則生成的密文會(huì)不同的, // 要嚴(yán)格按照易寶的官方文檔說(shuō)名來(lái)寫(xiě)才行,因?yàn)橐讓毮沁吘褪歉鶕?jù)文檔中的順序追加的 StringBuffer infoBuffer = new StringBuffer(); infoBuffer.append(p0_Cmd); infoBuffer.append(p1_MerId); infoBuffer.append(p2_Order); infoBuffer.append(p3_Amt); infoBuffer.append(p4_Cur); infoBuffer.append(p5_Pid); infoBuffer.append(p6_Pcat); infoBuffer.append(p7_Pdesc); infoBuffer.append(p8_Url); infoBuffer.append(p9_SAF); infoBuffer.append(pa_MP); infoBuffer.append(pd_FrpId); infoBuffer.append(pr_NeedResponse); // 加密后的密文存儲(chǔ)到了hmac中,加密算法易寶會(huì)提供的,因?yàn)樗沁呉驳糜孟嗤乃惴? hmac = DigestUtil.hmacSign(infoBuffer.toString(), keyValue); // 把明文和密文都存儲(chǔ)到request.setAttribute中 request.setAttribute("p0_Cmd", p0_Cmd); request.setAttribute("p1_MerId", p1_MerId); request.setAttribute("p2_Order", p2_Order); request.setAttribute("p3_Amt", p3_Amt); request.setAttribute("p4_Cur", p4_Cur); request.setAttribute("p5_Pid", p5_Pid); request.setAttribute("p6_Pcat", p6_Pcat); request.setAttribute("p7_Pdesc", p7_Pdesc); request.setAttribute("p8_Url", p8_Url); request.setAttribute("p9_SAF", p9_SAF); request.setAttribute("pa_MP", pa_MP); request.setAttribute("pd_FrpId", pd_FrpId); request.setAttribute("pr_NeedResponse", pr_NeedResponse); request.setAttribute("hmac", hmac); System.out.println("hmac-->" + hmac); //跳轉(zhuǎn)到reqpay.jsp中,將這些信息提交到易寶 request.getRequestDispatcher("/reqpay.jsp").forward(request, response); } else if (status.equals("success")) {//易寶那邊傳來(lái)的是success,處理返回驗(yàn)證部分 PrintWriter out = response.getWriter(); String keyValue = "w0P75wMZ203fr46r5i70V556WHFa94j14yW5J6vuh4yo3nRl5jsqF3c41677"; // 獲取所有的明文 String r0_Cmd = formatString(request.getParameter("r0_Cmd")); String p1_MerId = request.getParameter("p1_MerId"); String r1_Code = formatString(request.getParameter("r1_Code")); String r2_TrxId = formatString(request.getParameter("r2_TrxId")); String r3_Amt = formatString(request.getParameter("r3_Amt")); String r4_Cur = formatString(request.getParameter("r4_Cur")); String r5_Pid = new String(formatString( request.getParameter("r5_Pid")).getBytes("iso-8859-1"), "UTF-8"); String r6_Order = formatString(request.getParameter("r6_Order")); String r7_Uid = formatString(request.getParameter("r7_Uid")); String r8_MP = new String(formatString( request.getParameter("r8_MP")).getBytes("iso-8859-1"), "UTF-8"); String r9_BType = formatString(request.getParameter("r9_BType")); // 對(duì)明文進(jìn)行數(shù)據(jù)追加 String hmac = formatString(request.getParameter("hmac")); StringBuffer infoBuffer = new StringBuffer(); infoBuffer.append(p1_MerId); infoBuffer.append(r0_Cmd); infoBuffer.append(r1_Code); infoBuffer.append(r2_TrxId); infoBuffer.append(r3_Amt); infoBuffer.append(r4_Cur); infoBuffer.append(r5_Pid); infoBuffer.append(r6_Order); infoBuffer.append(r7_Uid); infoBuffer.append(r8_MP); infoBuffer.append(r9_BType); // 對(duì)返回的明文進(jìn)行加密 String md5 = DigestUtil.hmacSign(infoBuffer.toString(), keyValue); // 判斷加密的密文與傳過(guò)來(lái)的數(shù)據(jù)簽名是否相等 boolean isOK = md5.equals(hmac); if (isOK && r1_Code.equals("1")) {//r1_Code為1表示成功 //把支付成功的訂單狀態(tài)改成已支付,并個(gè)給用戶顯示支付成功信息 //調(diào)用郵件服務(wù)接口,短信發(fā)送服務(wù)等 //這里就打印一句話唄~ out.println("訂單編號(hào)為:" + r6_Order + "支付金額為:" + r3_Amt); } else { out.println("fail !!!!"); } } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } String formatString(String text) { if (text == null) { return ""; } return text; } }
2.3 加密算法
明文轉(zhuǎn)密文所用到的加密算法由易寶提供,我們只需要用它將明文轉(zhuǎn)為密文即可,算法如下:
public class DigestUtil { private static String encodingCharset = "UTF-8"; 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(); } 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)); } //我自己用來(lái)測(cè)試的 public static void main(String[] args) { // 參數(shù)1: 明文(要加密的數(shù)據(jù)) 參數(shù)2: 密鑰 System.out.println(DigestUtil.hmacSign("11111", "abc")); System.out.println(DigestUtil.hmacSign("11111", "abd")); // 解決數(shù)據(jù)安全性問(wèn)題: 把明文加密--->密文 然后把明文和密文都交給易寶 // 易寶拿到數(shù)據(jù)后,把傳過(guò)來(lái)的明文加密, 和傳過(guò)來(lái)密文比較,如果相等數(shù)據(jù)沒(méi)有被篡改 (商家與易寶加密時(shí)都用的是相同key) } }
加密算法也不去過(guò)多的研究了,好像是md5二代加密算法,反正把明文扔進(jìn)去,肯定加密成密文就行了。下面再看一下reqpay.jsp頁(yè)面:
<%@page language="java" contentType="text/html;charset=gbk"%> <html> <head> <title>To YeePay Page </title> </head> <body> <form name="yeepay" action='https://www.yeepay.com/app-merchant-proxy/node' method='POST' target="_blank"> <input type='hidden' name='p0_Cmd' value='${requestScope.p0_Cmd}'> <input type='hidden' name='p1_MerId' value='${requestScope.p1_MerId}'> <input type='hidden' name='p2_Order' value='${requestScope.p2_Order}'> <input type='hidden' name='p3_Amt' value='${requestScope.p3_Amt}'> <input type='hidden' name='p4_Cur' value='${requestScope.p4_Cur}'> <input type='hidden' name='p5_Pid' value='${requestScope.p5_Pid}'> <input type='hidden' name='p6_Pcat' value='${requestScope.p6_Pcat}'> <input type='hidden' name='p7_Pdesc' value='${requestScope.p7_Pdesc}'> <input type='hidden' name='p8_Url' value='${requestScope.p8_Url}'> <input type='hidden' name='p9_SAF' value='${requestScope.p9_SAF}'> <input type='hidden' name='pa_MP' value='${requestScope.pa_MP}'> <input type='hidden' name='pd_FrpId' value='${requestScope.pd_FrpId}'> <input type="hidden" name="pr_NeedResponse" value="${requestScope.pr_NeedResponse}"> <input type='hidden' name='hmac' value='${requestScope.hmac}'> <input type='submit' /> </form> </body> </html>
其實(shí)該頁(yè)面很簡(jiǎn)單,就是將明文和密文一起通過(guò)<form>
表單傳到易寶,易寶的接收url為https://www.yeepay.com/app-merchant-proxy/node
,這也是易寶官方提供的,我們寫(xiě)成這個(gè)就可以了。其實(shí)就一個(gè)submit
按鈕,點(diǎn)擊submit
按鈕就能將明文和密文提交過(guò)去了。我們看一下測(cè)試結(jié)果:
3. 測(cè)試支付結(jié)果
簡(jiǎn)陋的測(cè)試前臺(tái)index.jsp~~~:
提交后會(huì)到reqpay,jsp,點(diǎn)擊提交按鈕后的效果如下,我們將工行和建行都測(cè)一下:
支付流程都沒(méi)啥問(wèn)題,本來(lái)準(zhǔn)備去工行交個(gè)1分錢(qián)看一下支付完成后的結(jié)果,結(jié)果發(fā)現(xiàn)U盾過(guò)期了,因?yàn)楝F(xiàn)在用支付寶比較方便嘛……就沒(méi)去更新U盾了,但是我開(kāi)通過(guò)工行的e支付,所以上面那個(gè)界面中也可以使用e支付,于是我就很大方的付了1分錢(qián)~~結(jié)果如下:
然后會(huì)跳轉(zhuǎn)到我們之前指定的頁(yè)面,也就是同濟(jì)大學(xué)咯……好了,測(cè)試完成了,整個(gè)支付流程結(jié)束!
這一節(jié)主要是通過(guò)一個(gè)簡(jiǎn)單的demo測(cè)試一下,看能否和銀行的支付界面接上,現(xiàn)在測(cè)試是沒(méi)問(wèn)題的,已經(jīng)接上了,后面只要照常支付即可。簡(jiǎn)單的demo就介紹到這吧,后面就真正繼續(xù)我們之前的網(wǎng)上商城項(xiàng)目的在線支付模塊的開(kāi)發(fā)了。
原文地址:http://blog.csdn.net/eson_15/article/details/51447492
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- php網(wǎng)上商城購(gòu)物車(chē)設(shè)計(jì)代碼分享
- php 網(wǎng)上商城促銷(xiāo)設(shè)計(jì)實(shí)例代碼
- SSH框架的常見(jiàn)問(wèn)題和解決方法
- SSH+Jquery+Ajax框架整合
- Java的web開(kāi)發(fā)中SSH框架的協(xié)作處理應(yīng)用筆記
- java網(wǎng)上商城開(kāi)發(fā)之郵件發(fā)送功能(全)
- SSH框架網(wǎng)上商城項(xiàng)目第1戰(zhàn)之整合Struts2、Hibernate4.3和Spring4.2
- SSH框架網(wǎng)上商城項(xiàng)目第4戰(zhàn)之EasyUI菜單的實(shí)現(xiàn)
- SSH框架網(wǎng)上商城項(xiàng)目第20戰(zhàn)之在線支付平臺(tái)
- SSH框架網(wǎng)上商城項(xiàng)目第22戰(zhàn)之銀行圖標(biāo)以及支付頁(yè)面顯示
相關(guān)文章
Spring Cloud Gateway重試機(jī)制的實(shí)現(xiàn)
這篇文章主要介紹了Spring Cloud Gateway重試機(jī)制的實(shí)現(xiàn),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-03-03Lombok的詳細(xì)使用及優(yōu)缺點(diǎn)總結(jié)
最近在學(xué)Mybatis,接觸到了Lombok的使用,所以寫(xiě)一篇文章記錄一下,包括lombok的安裝及使用優(yōu)缺點(diǎn),感興趣的朋友跟隨小編一起看看吧2021-07-07java接口用戶上下文的設(shè)計(jì)與實(shí)現(xiàn)
這篇文章主要為大家介紹了接口用戶上下文的設(shè)計(jì)與實(shí)現(xiàn)實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11詳解MyBatisPlus如何實(shí)現(xiàn)分頁(yè)和查詢操作
這篇文章主要為大家詳細(xì)介紹了MyBatisPlus是如何實(shí)現(xiàn)分頁(yè)和查詢操作的,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)有一定的幫助,需要的可以參考一下2022-05-05Springboot項(xiàng)目全局異常統(tǒng)一處理案例代碼
最近在做項(xiàng)目時(shí)需要對(duì)異常進(jìn)行全局統(tǒng)一處理,主要是一些分類(lèi)入庫(kù)以及記錄日志等,因?yàn)轫?xiàng)目是基于Springboot的,所以去網(wǎng)絡(luò)上找了一些博客文檔,然后再結(jié)合項(xiàng)目本身的一些特殊需求做了些許改造,現(xiàn)在記錄下來(lái)便于以后查看2023-01-01java實(shí)現(xiàn)簡(jiǎn)單聊天室單人版
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)簡(jiǎn)單聊天室的單人版,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-07-07Mybatis分頁(yè)的實(shí)現(xiàn)及使用注解開(kāi)發(fā)操作
這篇文章主要介紹了Mybatis分頁(yè)的實(shí)現(xiàn)及使用注解開(kāi)發(fā)操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06