銀聯無跳轉介面除錯程式碼
阿新 • • 發佈:2019-01-23
自定義銀聯工具類
package util; import com.unionpay.acp.sdk.SDKConstants; import java.util.Iterator; import java.util.Map; import java.util.TreeMap; public class UnionPayConstantUtil { /** * 版本 5.1.0 */ public static final String VERSION = "5.1.0"; /** * 預設編碼 UTF-8 */ public static finalString ENCODING = "UTF-8"; /** * 商戶號 */ public static final String MER_ID = "777290058156102"; /** * 商戶名稱 */ public static final String MER_NAME = ""; /** * 商戶簡稱 */ public static final String MER_ABBR = ""; /** * 交易型別 01-消費 */ public static final String TXN_TYPE_CONSUMER= "01"; /** * 交易型別 04-退貨 */ public static final String TXN_TYPE_REFUND = "04"; /** * 交易型別 31-消費撤銷 */ public static final String TXN_TYPE_CONSUMER_UNDO = "31"; /** * 交易型別 77-傳送簡訊 */ public static final String TXN_TYPE_SMS = "77"; /** * 交易型別 78-交易查詢 */ public static finalString TXN_TYPE_QUERY = "78"; /** * 首次開通 */ public static final String TXN_TYPE_OPEN_CARD = "79"; /** * 交易型別 95 - 銀聯加密公鑰更新查詢 */ public static final String TXN_TYPE_ENCRYPTCER_UPDATE_QUERY = "95"; /** * 交易子型別 00-預設 */ public static final String TXN_SUBTYPE_DEFAULT = "00"; /** * 交易子型別 01-消費 */ public static final String TXN_SUBTYPE_CONSUMER = "01"; /** * 交易子型別 02-消費簡訊 */ public static final String TXN_SUBTYPE_CONSUMER_SMS = "02"; /** * 交易子型別 03-分期 */ public static final String TXN_SUBTYPE_FQ = "03"; /** * 業務型別 000000-預設 */ public static final String BIZ_TYPE_DEFAULT = "000000"; /** * 業務型別 000201-B2C閘道器支付 */ public static final String BIZ_TYPE_B2C = "000201"; /** * 業務型別 000301-認證支付2.0 */ public static final String BIZ_TYPE_AUTH = "000301"; /** * 業務型別 000902-TOKEN支付 */ public static final String BIZ_TYPE_TOKEN = "000902"; /** * 渠道型別 07-網際網路 */ public static final String CHANNEL_TYPE_PC = "07"; /** * 渠道型別 08-移動 */ public static final String CHANNEL_TYPE_MOBILE = "08"; /** * 商戶接入型別 0-商戶直接接入 預設為0 1-機構接入 2-平臺接入 */ public static final String ACCESS_TYPE_DEFAULT = "0"; /** * 交易幣種 預設人民幣 */ public static final String CURRENCY_CODE = "156"; /** * 賬號型別 01-銀行卡 */ public static final String ACC_TYPE_BANK_CARD = "01"; /** * 賬號類 03:IC卡 */ public static final String ACC_TYPE_IC_CARD = "03"; /** * 敏感資訊加密公鑰 01 */ public static final String CERT_TYPE = "01"; /** * 封裝資料拆解 * @param data * @return */ public static String genHtmlResult(Map<String, String> data){ TreeMap<String, String> tree = new TreeMap<String, String>(); Iterator<Map.Entry<String, String>> it = data.entrySet().iterator(); while (it.hasNext()) { Map.Entry<String, String> en = it.next(); tree.put(en.getKey(), en.getValue()); } it = tree.entrySet().iterator(); StringBuffer sf = new StringBuffer(); while (it.hasNext()) { Map.Entry<String, String> en = it.next(); String key = en.getKey(); String value = en.getValue(); if("respCode".equals(key)){ sf.append("<b>"+key + SDKConstants.EQUAL + value+"</br></b>"); }else sf.append(key + SDKConstants.EQUAL + value+"</br>"); } return sf.toString(); } }
銀聯介面實現
package web; import com.unionpay.acp.sdk.AcpService; import com.unionpay.acp.sdk.LogUtil; import com.unionpay.acp.sdk.SDKConfig; import com.unionpay.acp.sdk.SDKConstants; import org.apache.commons.io.IOUtils; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import util.UnionPayConstantUtil; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; @Controller @RequestMapping("/api/commons/pay") public class UnionPayController { /** * 交易查詢 * * @param sessionId * @param accNo * @param orderId * @param txnTime * @param response * @return */ @RequestMapping("/unionPayQuery.do") public @ResponseBody Map<String, Object> unionPay(String sessionId, String accNo, String orderId, String txnTime, HttpServletResponse response) { //判斷引數 //判斷是否符合條件 Map<String, String> contentData = new HashMap<String, String>(); //配置銀聯全渠道資訊 contentData.put(SDKConstants.param_version, UnionPayConstantUtil.VERSION); //版本號 contentData.put(SDKConstants.param_encoding, UnionPayConstantUtil.ENCODING); //字符集編碼 可以使用UTF-8,GBK兩種方式 contentData.put(SDKConstants.param_signMethod, SDKConfig.getConfig().getSignMethod()); //簽名方法 contentData.put(SDKConstants.param_txnType, UnionPayConstantUtil.TXN_TYPE_QUERY); //交易型別 78-開通查詢 contentData.put(SDKConstants.param_txnSubType, UnionPayConstantUtil.TXN_SUBTYPE_DEFAULT); //交易子型別 00-根據賬號accNo查詢(預設) contentData.put(SDKConstants.param_bizType, UnionPayConstantUtil.BIZ_TYPE_AUTH); //業務型別 認證支付2.0 contentData.put(SDKConstants.param_channelType, UnionPayConstantUtil.CHANNEL_TYPE_PC); //渠道型別07-PC //商戶資訊 contentData.put(SDKConstants.param_merId, UnionPayConstantUtil.MER_ID); contentData.put(SDKConstants.param_orderId, orderId); contentData.put(SDKConstants.param_txnTime, txnTime); contentData.put(SDKConstants.param_accessType, UnionPayConstantUtil.ACCESS_TYPE_DEFAULT); //買家賬戶資訊 ////////////如果商戶號開通了【商戶對敏感資訊加密】的許可權那麼需要對 accNo,phoneNo加密使用: String accNo1 = AcpService.encryptData(accNo, UnionPayConstantUtil.ENCODING); //這裡測試的時候使用的是測試卡號,正式環境請使用真實卡號 contentData.put(SDKConstants.param_accNo, accNo1); contentData.put(SDKConstants.param_encryptCertId, AcpService.getEncryptCertId()); //加密證書的certId,配置在acp_sdk.properties檔案 acpsdk.encryptCert.path屬性下 //與銀聯通訊 try { Map<String, String> reqData = AcpService.sign(contentData, UnionPayConstantUtil.ENCODING); //報文中certId,signature的值是在signData方法中獲取並自動賦值的,只要證書配置正確即可。 String requestBackUrl = SDKConfig.getConfig().getBackRequestUrl(); //交易請求url從配置檔案讀取對應屬性檔案acp_sdk.properties中的 acpsdk.backTransUrl Map<String, String> rspData = AcpService.post(reqData, requestBackUrl, UnionPayConstantUtil.ENCODING); //傳送請求報文並接受同步應答(預設連線超時時間30秒,讀取返回結果超時時間30秒);這裡呼叫signData之後,呼叫submitUrl之前不能對submitFromData中的鍵值對做任何修改,如果修改會導致驗籤不通過 StringBuffer parseStr = new StringBuffer(""); if (!rspData.isEmpty()) { if (AcpService.validate(rspData, UnionPayConstantUtil.ENCODING)) { LogUtil.writeLog("驗證簽名成功"); String respCode = rspData.get("respCode"); if (("00").equals(respCode)) { //成功 parseStr.append("<br>解析敏感資訊加密資訊如下(如果有):<br>"); String customerInfo = rspData.get("customerInfo"); if (null != customerInfo) { Map<String, String> cm = AcpService.parseCustomerInfo(customerInfo, UnionPayConstantUtil.ENCODING); parseStr.append("customerInfo明文: " + cm + "<br>"); } String an = rspData.get("accNo"); if (null != an) { an = AcpService.decryptData(an, UnionPayConstantUtil.ENCODING); parseStr.append("accNo明文: " + an); } //TODO } else { //其他應答碼為失敗請排查原因或做失敗處理 //TODO } } else { LogUtil.writeErrorLog("驗證簽名失敗"); //TODO 檢查驗證簽名失敗的原因 } } else { //未返回正確的http狀態 LogUtil.writeErrorLog("未獲取到返回報文或返回http狀態碼非200"); } String reqMessage = UnionPayConstantUtil.genHtmlResult(reqData); String rspMessage = UnionPayConstantUtil.genHtmlResult(rspData); response.getWriter().write("請求報文:<br/>" + reqMessage + "<br/>" + "應答報文:</br>" + rspMessage + parseStr); } catch (Exception e) { e.printStackTrace(); return null; } return null; } /** * 首次使用開通 * * @param sessionId * @param orderId * @param accNo * @param phoneNo * @param cvn2 * @param expired * @param response * @return */ @RequestMapping("/unionPayOpenCardBack.do") public @ResponseBody Map<String, Object> unionPayOpenCardBack(String sessionId, String orderId, String accNo, String phoneNo, String cvn2, String expired, HttpServletResponse response) { //判斷引數是否合法 //判斷使用者是否存在 //判斷訂單是否存在 訂單狀態是否合法 //判斷銀行卡號 手機號 //封裝資料 Map<String, String> contentData = new HashMap<String, String>(); //銀聯全渠道預設引數 contentData.put(SDKConstants.param_version, UnionPayConstantUtil.VERSION); //版本號 contentData.put(SDKConstants.param_encoding, UnionPayConstantUtil.ENCODING); //字符集編碼 可以使用UTF-8,GBK兩種方式 contentData.put(SDKConstants.param_signMethod, SDKConfig.getConfig().getSignMethod()); //簽名方法 contentData.put(SDKConstants.param_txnType, UnionPayConstantUtil.TXN_TYPE_OPEN_CARD); //交易型別 79-開通 contentData.put(SDKConstants.param_txnSubType, UnionPayConstantUtil.TXN_SUBTYPE_DEFAULT); //交易子型別 00 contentData.put(SDKConstants.param_bizType, UnionPayConstantUtil.BIZ_TYPE_AUTH); //業務型別 認證支付2.0 contentData.put(SDKConstants.param_channelType, UnionPayConstantUtil.CHANNEL_TYPE_PC); //渠道型別07-PC Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); String txnTime = sdf.format(date); //商戶接入引數 商戶訂單內容的補充 contentData.put(SDKConstants.param_merId, UnionPayConstantUtil.MER_ID); contentData.put(SDKConstants.param_accessType, UnionPayConstantUtil.ACCESS_TYPE_DEFAULT); //接入型別,商戶接入固定填0,不需修改 contentData.put(SDKConstants.param_orderId, orderId); //商戶訂單號,8-40位數字字母,不能含“-”或“_”,可以自行定製規則 contentData.put(SDKConstants.param_txnTime, txnTime); //訂單傳送時間,格式為YYYYMMDDhhmmss,必須取當前時間,否則會報txnTime無效 contentData.put(SDKConstants.param_accType, UnionPayConstantUtil.ACC_TYPE_BANK_CARD); //賬號型別 //商戶需要開通對銀行卡進行開通的許可權 否則商戶不能再自己的站點開通 //消費交易要素 買家交易的賬號進行補充 買家個人資訊 Map<String, String> customInfoData = new HashMap<String, String>(); //商戶號要是開啟了對銀行卡號進行加密 就需要這一步驟 customInfoData.put(SDKConstants.param_phoneNo, phoneNo); customInfoData.put(SDKConstants.param_cvn2, cvn2); customInfoData.put(SDKConstants.param_expired, expired); String customerInfoWithEncrypt = AcpService.getCustomerInfoWithEncrypt(customInfoData, null, UnionPayConstantUtil.ENCODING); contentData.put(SDKConstants.param_customerInfo, customerInfoWithEncrypt); //根據商戶是否開啟加密而設定 String accNo1 = AcpService.encryptData(accNo, UnionPayConstantUtil.ENCODING); contentData.put(SDKConstants.param_accNo, accNo1); contentData.put(SDKConstants.param_encryptCertId, AcpService.getEncryptCertId()); //獲取加密證書的id //後臺通知地址 contentData.put(SDKConstants.param_backUrl, SDKConfig.getConfig().getBackUrl()); //進行交易簽名 並應答 try { Map<String, String> signData = AcpService.sign(contentData, UnionPayConstantUtil.ENCODING); String backRequestUrl = SDKConfig.getConfig().getBackRequestUrl(); //響應回來的資料 這裡只能證明與銀聯連線是否接通 正真的完成交易是在銀聯給後臺地址傳送資料 才能證明交易完成 Map<String, String> resposeData = AcpService.post(signData, backRequestUrl, UnionPayConstantUtil.ENCODING); String reqMessage = UnionPayConstantUtil.genHtmlResult(signData); String rspMessage = UnionPayConstantUtil.genHtmlResult(resposeData); response.getWriter().write("請求報文:<br/>" + reqMessage + "<br/>" + "應答報文:</br>" + rspMessage); if (resposeData == null) { return null; } if (AcpService.validate(resposeData, UnionPayConstantUtil.ENCODING)) { String respCode = resposeData.get("respCode"); if ("00".equals(respCode)) { //處理業務 交易以受理 //儲存訂單日誌 PayRequestLog } else if (("03").equals(respCode) || ("04").equals(respCode) || ("05").equals(respCode)) { //處理沒有受理 情況 } else { //這裡處理錯誤 返回給前臺提示使用者 } } else { return null; } } catch (Exception e) { e.printStackTrace(); } return null; } /** * 銀聯支付介面 * * @param sessionId * @param orderId * @param smsCode * @param accNo * @param fq_num * @return */ @RequestMapping("/unionPay.do") public @ResponseBody Map<String, Object> unionPay(String sessionId, String orderId, String smsCode, String accNo, String fq_num, HttpServletResponse response, String prize) { //判斷當前使用者 //判斷引數是否符合要求 //判斷訂單是否存在 判斷訂單狀態 //判斷accno銀行卡號是否符合規格 並判斷是否是合作的銀行所屬的卡號 Map<String, String> contentData = new HashMap<String, String>(); //銀聯全渠道預設引數 contentData.put(SDKConstants.param_version, UnionPayConstantUtil.VERSION); //版本號 contentData.put(SDKConstants.param_encoding, UnionPayConstantUtil.ENCODING); //字符集編碼 可以使用UTF-8,GBK兩種方式 contentData.put(SDKConstants.param_signMethod, SDKConfig.getConfig().getSignMethod()); //簽名方法 //txnSubType 01-消費 03-分期 contentData.put(SDKConstants.param_txnType, UnionPayConstantUtil.TXN_TYPE_CONSUMER); //交易型別 01-消費 contentData.put(SDKConstants.param_txnSubType, UnionPayConstantUtil.TXN_SUBTYPE_CONSUMER); //交易子型別 01-消費 03-分期 //numberOfInstallments分期期數03 06 12 instalRate分期期率 mchntFeeSubsidy 商戶補貼 //contentData.put("instalTransInfo", "{numberOfInstallments=" + fq_num + "}"); contentData.put(SDKConstants.param_bizType, UnionPayConstantUtil.BIZ_TYPE_AUTH); //業務型別 認證支付2.0 contentData.put(SDKConstants.param_channelType, UnionPayConstantUtil.CHANNEL_TYPE_PC); //渠道型別07-PC Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); String txnTime = sdf.format(date); //商戶接入引數 商戶訂單內容的補充 contentData.put(SDKConstants.param_merId, UnionPayConstantUtil.MER_ID); contentData.put(SDKConstants.param_accessType, UnionPayConstantUtil.ACCESS_TYPE_DEFAULT); //接入型別,商戶接入固定填0,不需修改 contentData.put(SDKConstants.param_orderId, orderId); //商戶訂單號,8-40位數字字母,不能含“-”或“_”,可以自行定製規則 contentData.put(SDKConstants.param_txnTime, txnTime); //訂單傳送時間,格式為yyyyMMddHHmmss,必須取當前時間,否則會報txnTime無效 contentData.put(SDKConstants.param_currencyCode, UnionPayConstantUtil.CURRENCY_CODE); //交易幣種(境內商戶一般是156 人民幣) contentData.put(SDKConstants.param_txnAmt, prize); //交易金額,單位分,不要帶小數點 contentData.put(SDKConstants.param_accType, UnionPayConstantUtil.ACC_TYPE_BANK_CARD); //賬號型別 //contentData.put("orderDesc", "訂單描述"); contentData.put(SDKConstants.param_reqReserved, "orderDesc=訂單描述;remark=備註"); //請求保留域 //消費交易要素 買家交易的賬號進行補充 Map<String, String> customInfoData = new HashMap<String, String>(); customInfoData.put(SDKConstants.param_smsCode, smsCode); //商戶號要是開啟了對銀行卡號進行加密 就需要這一步驟 String customerInfoWithEncrypt = AcpService.getCustomerInfoWithEncrypt(customInfoData, accNo, UnionPayConstantUtil.ENCODING); String accNo1 = AcpService.encryptData(accNo, UnionPayConstantUtil.ENCODING); contentData.put(SDKConstants.param_accNo, accNo1); contentData.put(SDKConstants.param_encryptCertId, AcpService.getEncryptCertId()); //獲取加密證書的id contentData.put(SDKConstants.param_customerInfo, customerInfoWithEncrypt); //後臺通知地址 contentData.put(SDKConstants.param_backUrl, SDKConfig.getConfig().getBackUrl()); //進行交易簽名 並應答 try { Map<String, String> signData = AcpService.sign(contentData, UnionPayConstantUtil.ENCODING); String backRequestUrl = SDKConfig.getConfig().getBackRequestUrl(); //響應回來的資料 這裡只能證明與銀聯連線是否接通 正真的完成交易是在銀聯給後臺地址傳送資料 才能證明交易完成 Map<String, String> resposeData = AcpService.post(signData, backRequestUrl, UnionPayConstantUtil.ENCODING); String reqMessage = UnionPayConstantUtil.genHtmlResult(signData); String rspMessage = UnionPayConstantUtil.genHtmlResult(resposeData); response.getWriter().write("請求報文:<br/>" + reqMessage + "<br/>" + "應答報文:</br>" + rspMessage); if (resposeData == null) { return null; } if (AcpService.validate(resposeData, UnionPayConstantUtil.ENCODING)) { String respCode = resposeData.get("respCode"); if ("00".equals(respCode)) { //處理業務 交易以受理 //儲存訂單日誌 PayRequestLog LogUtil.writeLog("consume=======》OK"); } else if (("03").equals(respCode) || ("04").equals(respCode) || ("05").equals(respCode)) { //處理沒有受理 情況 } else { //這裡處理錯誤 返回給前臺提示使用者 } } else { return null; } } catch (Exception e) { e.printStackTrace(); return null; } return null; } /** * 銀聯消費簡訊 */ @RequestMapping("/unionPayConsumeSMS.do") public @ResponseBody Map<String, Object> unionPayConsumeSMS(String sessionId, String orderId, String accNo, String phoneNo, HttpServletResponse response, String prize) { //判斷引數是否合法 //檢視使用者是否存在 //查詢訂單 判斷訂單狀態 //判斷電話是否符合要求 //封裝資料 Map<String, String> contentData = new HashMap<String, String>(); //銀聯全渠道預設引數 contentData.put(SDKConstants.param_version, UnionPayConstantUtil.VERSION); //版本號 contentData.put(SDKConstants.param_encoding, UnionPayConstantUtil.ENCODING); //字符集編碼 可以使用UTF-8,GBK兩種方式 contentData.put(SDKConstants.param_signMethod, SDKConfig.getConfig().getSignMethod()); //簽名方法 contentData.put(SDKConstants.param_txnType, UnionPayConstantUtil.TXN_TYPE_SMS); //交易型別 77簡訊 contentData.put(SDKConstants.param_txnSubType, UnionPayConstantUtil.TXN_SUBTYPE_CONSUMER_SMS); //交易子型別 01-消費 03-分期 contentData.put(SDKConstants.param_bizType, UnionPayConstantUtil.BIZ_TYPE_AUTH); //業務型別 認證支付2.0 contentData.put(SDKConstants.param_channelType, UnionPayConstantUtil.CHANNEL_TYPE_PC); //渠道型別07-PC Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); String txnTime = sdf.format(date); //商戶接入引數 商戶訂單內容的補充 contentData.put(SDKConstants.param_merId, UnionPayConstantUtil.MER_ID); contentData.put(SDKConstants.param_accessType, UnionPayConstantUtil.ACCESS_TYPE_DEFAULT); //接入型別,商戶接入固定填0,不需修改 contentData.put(SDKConstants.param_orderId, orderId); //商戶訂單號,8-40位數字字母,不能含“-”或“_”,可以自行定製規則 contentData.put(SDKConstants.param_txnTime, txnTime); //訂單傳送時間,格式為YYYYMMDDhhmmss,必須取當前時間,否則會報txnTime無效 contentData.put(SDKConstants.param_currencyCode, UnionPayConstantUtil.CURRENCY_CODE); //交易幣種(境內商戶一般是156 人民幣) contentData.put(SDKConstants.param_txnAmt, prize); //交易金額,單位分,不要帶小數點 contentData.put(SDKConstants.param_accType, UnionPayConstantUtil.ACC_TYPE_BANK_CARD); //賬號型別 //contentData.put("orderDesc", "訂單描述"); contentData.put(SDKConstants.param_reqReserved, "orderDesc=訂單描述;remark=備註"); //請求保留域 //消費交易要素 買家交易的賬號進行補充 Map<String, String> customInfoData = new HashMap<String, String>(); //新增手機號碼 customInfoData.put(SDKConstants.param_phoneNo, phoneNo); String customerInfoWithEncrypt = AcpService.getCustomerInfoWithEncrypt(customInfoData, null, UnionPayConstantUtil.ENCODING); //商戶號要是開啟了對銀行卡號進行加密 就需要這一步驟 String accNo1 = AcpService.encryptData(accNo, UnionPayConstantUtil.ENCODING); contentData.put(SDKConstants.param_accNo, accNo1); contentData.put(SDKConstants.param_encryptCertId, AcpService.getEncryptCertId()); //獲取加密證書的id contentData.put(SDKConstants.param_customerInfo, customerInfoWithEncrypt); //後臺通知地址 contentData.put(SDKConstants.param_backUrl, SDKConfig.getConfig().getBackUrl()); //進行交易簽名 並應答 try { Map<String, String> signData = AcpService.sign(contentData, UnionPayConstantUtil.ENCODING); String backRequestUrl = SDKConfig.getConfig().getBackRequestUrl(); //響應回來的資料 這裡只能證明與銀聯連線是否接通 正真的完成交易是在銀聯給後臺地址傳送資料 才能證明交易完成 Map<St