銀聯支付(chinapay)java接入避坑指南[親測有效]銀聯無卡支付java接入避坑指南,從代碼實現上進行總結說明。
一、背景
銀聯支付能給滿足絕大部分銀行支付渠道,所以接入銀聯無卡支付,是很多系統應用需要做的事情。銀聯支付的類型分很多種,網關支付(帶token請求實現,下次有空再分享)、無卡支付(帶證書請求實現,本次講的就是這個)分商戶和機構入網,具體請去這里查看中國銀聯開放平臺
二、效果
本次講解實現的銀聯無卡支付,實現的效果圖即提交訂單后進入支付頁面的效果圖如下
三、開發前準備
當你需要接入銀聯無卡支付的時候,肯定是經過了需求調研,所以會有對接人給你們申請,所以會給你們發郵件,提供相應開發所需的文件,如下
1、開發文檔ChinaPay_新一代_商戶接入手冊_20210412.pdf
2、證書cp.cer
3、私鑰xxxxxxxx.pfx和密碼
4、插件包,里面提供了Java、.net、C和PHP的插件包,java的就是chinapaysecure1_5.jar
5、測試賬號,請從如下地址獲取FAQ列表- 中國銀聯開放平臺
6、讓銀聯方配置測試ip白名單,如果自己本地開發,出口ip需要固定,查詢自己的出口ip地址如下用戶檢測分析工具
注意:如果需要代碼參考,可以讓銀聯方提供demo進行參考。這個demo因為是很久之前的,是jsp實現的eclipse項目,所以需要跑起來這個項目需要提前準備好eclipse和tomcat,當然了你會用idea跑eclipse也行。但是有時候稍微不注意,idea跑起來就會有莫名其妙的問題。這種問題經歷過的都懂,就不說了。這里要特意說明一點就是,如果想要自己折騰獲取xxx.pfx私鑰的話,得配置好ip白名單后,登陸他們提供的商戶服務管理系統https://newpayment-test.chinapay.com/BIZSS/admin/loginpage.htm后臺去申請測試的私鑰,即交易證書,這個系統最好用ie去登陸,否則你會因為各種莫名其妙的原因導致下載失敗。
四、B2C、B2B、無卡支付交易流程(文檔里面有)
五、代碼
看到到這里了,證明前面的你已經準備好了,下面就開始看代碼層面了,這里先給你們截幾張demo的圖給你們看看
1、跑完demo就會跳轉到這個頁面。
2、點擊B2C會跳轉到組交易報文頁面,這里需要填寫你的商戶號和支付機構號700000000000017(pdf文檔里面有)
3、這是組裝好的交易報文
4、提交訂單后
好了,看完demo的截圖,就到我們自己動手,引用到springboot項目中了。
1、新建springboot項目或者直接用你的工作項目,將上面提前準備的xxx.cer、xxx.pfx證書放到項目中指定位置,如在resources下面新建一個文件夾放置這兩個證書,在新建一個security.properties放到resources下,后續下單等操作需要簽名的時候要獲取到這些證書。security.properties的內容如下圖。
這里的路徑自己定義就好了,security.properties就是為了獲取到證書,所以xxx.cer、xxx.pfx證書的路徑寫在了security.properties文件中。其實這個security.properties文件也可以不放在項目中,可以放在服務器上面,然后需要換證書的時候,直接換服務器文件上的security.properties就好了,不用重啟項目,這樣就可以做到動態切換證書了。
2、導入chinapaysecure1_5.jar
idea可以用命令導入,如下圖
命令如下:
install:install-file
-Dfile=E:\study\chinapaysecure1_5.jar
-DgroupId=com.chinapay.secure
-DartifactId=chinapay-sdk
-Dversion=1.5.0
-Dpackaging=jar
pom 文件引入:
<dependency>
<groupId>com.chinapay.sdk</groupId>
<artifactId>chinapay-sdk</artifactId>
<version>1.5.0</version>
</dependency>
這里需要注意一點就是,如果你的maven倉庫是私服的話,上傳了這個jar后,如果是下不下來的活,就要檢查已經倉庫的更新策略了,具體請看這里,添加這個就好了<updatePolicy>always</updatePolicy>https://blog.csdn.net/frank1998819/article/details/84813840
3、好了,廢話了那么多,開始放下單支付代碼
3.1、交易證書、驗簽證書初始化(因為我這里的正式是放到服務器上面的,所以需要通過url獲?。?/p>
String securityUrl = upLoadPath + Constant.CHINA_PAY_SECURITY + chinaPayParameters.getMerchantId() + ".properties";secssUtil = new SecssUtil();File file = new File(securityUrl);boolean bool = secssUtil.init(file.getPath());if (bool) { log.info("ChinaPay交易證書、驗簽證書初始化成功!");} else { log.error("ChinaPay交易證書、驗簽證書初始化失?。?+secssUtil.getErrCode() + "=" + secssUtil.getErrMsg());}是否還在為Ide開發工具頻繁失效而煩惱,來吧關注以下公眾號獲取最新激活方式。親測可用!
為防止網絡爬蟲,請關注公眾號回復”口令”
激活idea 激活CLion DataGrip DataSpell dotCover dotMemory dotTrace GoLand PhpStorm PyCharm ReSharper ReShaC++ Rider RubyMine WebStorm 全家桶 刷新【正版授權,激活自己賬號】:Jetbrains全家桶Ide使用,1年售后保障,每天僅需1毛
【官方授權 正版激活】:官方授權 正版激活 自己使用,支持Jetbrains家族下所有IDE…
3.2、構建請求報文及簽名
Map<String, Object> paramMap = new TreeMap<>();paramMap.put("Version", "20140728");paramMap.put("AccessType","0"); //接入類型 0:商戶身份接入(默認)1:機構身份接入paramMap.put("MerId", "123456"); // 商戶號paramMap.put("MerOrderNo", "abc123465"); // 商戶訂單號(由字母和數字組成,不要包含下劃線)paramMap.put("TranDate", "20220723"); // YYYYMMDDparamMap.put("TranTime", "103300"); // HHMMSSparamMap.put("OrderAmt", "1"); // 單位:分paramMap.put("TranType", "0001");//交易類型,固定值paramMap.put("BusiType", "0001");//業務類型,固定值paramMap.put("BankInstNo", "700000000000017"); // 支付機構號-銀聯在線支付(這個參數必填,如果是無卡支付前端請求,否則會失敗)paramMap.put("CommodityMsg", "芒果");paramMap.put("RemoteAddr", ipAddr); // ip地址paramMap.put("CurryNo", "CNY");paramMap.put("MerBgUrl", ""); // 后臺通知地址paramMap.put("MerPageUrl", ""); // 前端跳轉地址//簽名secssUtil.sign(paramMap);if (!SecssConstants.SUCCESS.equals(secssUtil.getErrCode())) { return PayUtil.errorMessage("500", "500", secssUtil.getErrMsg());}String signature = secssUtil.getSign();paramMap.put("Signature", signature);
3.3、構建from表單System.out.println("####################請求總參數####################");System.out.println(paramMap);//必須構建成【自動提交form表單】html,返回商城前端自動跳轉到網銀支付頁面String buildRequest = MerchantApiUtil.buildRequest(paramMap,frontPayUrl, "post", "確定");System.out.println("####################構建的表單####################");System.out.println(buildRequest);request.setAttribute("result",buildRequest);
3.4、構建from表單代碼
public static String buildRequest(Map<String, Object> sParaTemp, String action, String strMethod, String strButtonName) { //待請求參數數組 List<String> keys = new ArrayList<String>(sParaTemp.keySet()); StringBuffer sbHtml = new StringBuffer(); sbHtml.append("<form id=\"rppaysubmit\" name=\"rppaysubmit\" action=\"" + action + "\" method=\"" + strMethod + "\">"); for (int i = 0; i < keys.size(); i++) { String name = (String) keys.get(i); Object object = sParaTemp.get(name); String value = ""; if (object != null) { value = String.valueOf(sParaTemp.get(name)); } sbHtml.append("<input type=\"hidden\" name=\"" + name + "\" value=\"" + value + "\"/>"); } //submit按鈕控件請不要含有name屬性 sbHtml.append("<input type=\"submit\" value=\"" + strButtonName + "\" style=\"display:none;\"></form>"); return sbHtml.toString();}
3.5、vue前端調用下單form表單代碼
4、回調接口代碼
public String chinaPayNotifyUrl(HttpServletRequest request, HttpServletResponse response) { //獲取請求頭參數到paramsMap String notifyType = request.getParameter(Constant.SPEC_NOTIFY_TYPE); if(StringUtil.isempty(notifyType)) { notifyType = Constant.NOTIFY_TYPE_BACK; } Map<String, String> payNotifyUrlParamsMap = new TreeMap<String, String>(); Enumeration<String> paraNames = request.getParameterNames(); while (paraNames.hasMoreElements()) { String key = paraNames.nextElement(); // 跳過自定義字段 if (key.startsWith(Constant.SPEC_PRIFEX)) { continue; } // 跳過空字段 String value = request.getParameter(key); if (StringUtil.isEmpty(value)) { continue; } // 后臺通知需要解碼,正式使用建議前后臺接收通知地址分開 if(Constant.NOTIFY_TYPE_BACK.equals(notifyType)) { try { value = URLDecoder.decode(value, Constant.ENCODING); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } payNotifyUrlParamsMap.put(key, value); } log.info("當前時間:" + DateUtils.getCurrentTime() + "銀聯支付回調原始參數:" + payNotifyUrlParamsMap.toString()); String outTradeNo = payNotifyUrlParamsMap.get("MerOrderNo") == null ? "" : payNotifyUrlParamsMap.get("MerOrderNo"); // 渠道訂單號 //返回數據驗簽 boolean verifyFlag = verifyNotify(payNotifyUrlParamsMap); if (!verifyFlag) { System.out.println("ChinaPay支付回調--返回數據驗簽失??!"); throw new JeecgBootException("ChinaPay支付回調返回數據驗簽失敗,支付明細編號為:" + outTradeNo); }// 這里就寫你的業務了
4.1、常量說明
/** * 請求參數-通知類型 0前臺 1后臺 默認是后臺. */public static final String SPEC_NOTIFY_TYPE = "__notifyType";/** * 通知類型-后臺. */public static final String NOTIFY_TYPE_BACK = "1";/** * 特殊字段前綴. */public static final String SPEC_PRIFEX = "__";/** * 默認編碼. */public static final String ENCODING = "UTF-8";
5、驗簽
public boolean verifyNotify(Map<String, String> notifyMap) { String securityUrl = upLoadPath + Constant.CHINA_PAY_SECURITY + notifyMap.get("MerId") + ".properties"; secssUtil = new SecssUtil(); File file = new File(securityUrl); boolean bool = secssUtil.init(file.getPath()); if (bool) { System.out.println("ChinaPay交易證書、驗簽證書初始化成功!"); } else { System.out.println("ChinaPay交易證書、驗簽證書初始化失?。?+secssUtil.getErrCode() + "=" + secssUtil.getErrMsg()); } try { //驗簽 String sign = notifyMap.get("Signature"); if (StringUtil.isNotEmpty(sign)) { secssUtil.verify(notifyMap);//入參:返回商戶報文中的所有參數 } if (!SecssConstants.SUCCESS.equals(secssUtil.getErrCode())) { System.out.println(secssUtil.getErrCode() + "=" + secssUtil.getErrMsg()); System.out.println("ChinaPay返回的應答數據【驗簽】失敗:" + secssUtil.getErrMsg()); return false; } return true; } catch (Exception e) { e.printStackTrace(); } return false;}
能給下單獲取簽名和回調進行驗簽,那么訂單查詢、訂單退款也就沒什么大問題了,以上就是本次分享的銀聯支付的代碼,如有問題,請評論去指出,互相學習,共同進步。
六、總結
現在進行總結一下。
1、進行銀聯接入,需要提前了解接入后的效果。
2、開發前提前準備好需要的相應參數,否則溝通效率低下,問一個參數就一天了,文檔上說不是必填,實際上又是需要必填,導致找不到原因,讓銀聯配合,但是他們效率低下,導致你們接入進度延遲,比如文檔上的支付機構號,可能有些情況下不是必填的,但是有些情況下是必填的,但是文檔上沒有說明,導致踩坑了。
3、form表單提交下單,這里的請求,如果是前端跳轉,那么這時的跳轉地址是你本地瀏覽器的地址,無需配置你測試環境的地址,只需要你本地的出口地址在銀聯的白名單即可。
4、正式環境無需配置白名單,測試環境才需要配置,否則開發的時候聯調不了。
5、以上就是接入銀聯支付的所有,希望后人在接入的時候能給到一些參考,進而避免一些坑,從而提高接入效率。
本文由 貴州做網站公司 整理發布,部分圖文來源于互聯網,如有侵權,請聯系我們刪除,謝謝!
c語言中正確的字符常量是用一對單引號將一個字符括起表示合法的字符常量。例如‘a’。數值包括整型、浮點型。整型可用十進制,八進制,十六進制。八進制前面要加0,后面...
2022年天津專場考試原定于3月19日舉行,受疫情影響確定延期,但目前延期后的考試時間推遲。 符合報名條件的考生,須在規定時間登錄招考資訊網(www.zha...
:喜歡聽,樂意看。指很受歡迎?!巴卣官Y料”喜聞樂見:[ xǐ wén lè jiàn ]詳細解釋1. 【解釋】:喜歡聽,樂意看。指很受歡迎。2. 【示例】:這是...
為什么九月份的工資千萬別亂花?隨著9月份的快要結束,我們即將迎來大家所期待的國慶長假,然而,對于很多人來說,這個假期也意味著著額外的開銷。因此,我想提醒大家,不要揮霍自己的9月份工資,因為下個月的花費可能更加喜人。自國慶長假的第一天開始,人們的錢包就開始不停地削減,結婚禮金、旅游探親、消費開銷等等,每-個需要花費錢的活動都會讓我們的錢包縮水。盡管人們會一邊享受開銷的快感,又一邊擔心假期過后的貧困生...
#標題創作挑戰#從2009年開始,安徽衛視引進了《天使之爭》、《愛在路上》、《一個承諾》、《丘比特的陷阱》、《鉆石之戰》、《愛的漣漪》、《愛的被告》、《旋轉的愛》、《真愛無價》等經典泰劇。,在國內引起了追劇熱潮,培養了大批忠實的泰劇粉絲。近年來,泰國腐劇發展迅速,但傳統泰劇在中國的影響力卻大不如前。不過最近有一部泰劇,是《虎玫瑰先生》?!痘⒚倒逑壬分约t,不是憑借精良的制作和精彩的劇情,而是先...
文化建設的重要性有哪些?文化建設是發展文學藝術、科學、教育、圖書館、廣播電視、新聞出版、衛生體育、博物館等各項文化事業的活動。它不僅是建設物質文明的重要條件,也是提高人們思想覺悟和道德水平的重要條件。文化建設的基本任務是用最新的科技成果提高人民的知識水平,通過合理進步的教育制度培養社會主義新一代,用健康的文藝和最能體現時代精神的生動活潑的群眾文化活動陶冶人們的情操,豐富人們的精神生活。文化是一個民...