package cc.mrbird.febs.pay.service.impl; import cc.mrbird.febs.mall.entity.MallMemberBank; import cc.mrbird.febs.mall.entity.MallMemberWithdraw; import cc.mrbird.febs.mall.entity.MallMemberWithdrawMsg; import cc.mrbird.febs.mall.mapper.MallMemberBankMapper; import cc.mrbird.febs.mall.mapper.MallMemberWithdrawMapper; import cc.mrbird.febs.mall.mapper.MallMemberWithdrawMsgMapper; import cc.mrbird.febs.mall.mapper.MallOrderInfoMapper; import cc.mrbird.febs.pay.service.NBYHService; import cn.hutool.core.util.ObjectUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.io.*; import java.math.BigDecimal; import java.net.HttpURLConnection; import java.net.InetAddress; import java.net.Socket; import java.net.URL; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.Map; @Slf4j @Service public class NBYHServiceImpl implements NBYHService { /** * 登录报文原文 */ private static final String SIGN_MESSAGE = "${serialNo}${reqTime}0000005332123456"; /** * 转账报文原文 */ private static final String TRADE_MESSAGE_SEARCH = "${serialNo}${reqTime}${serialNoOld}"; private static final String TRADE_MESSAGE_SINGLE = "${serialNo}${reqTime}82260120102022631780401220000592777923119570.01银企接口测试"; private static final String TRADE_MESSAGE = "${serialNo}${reqTime}${FKZH}${SKZH}${SKHM}${SKYH}${SKSH}${SKSI}${JYJE}${YOTU}${SKHH}"; // private static final String TRADE_MESSAGE = "${serialNo}${reqTime}822601201020226316228481060643871117王苏平中国农业银行舟山市定海支行营业中心浙江省舟山市0.0101020银企接口测试103342040518"; /** * private static final String TRADE_MESSAGE = "" + "${serialNo}" + "${reqTime}" + "" + "82260120102022631" + "6228481060643871117" + "王苏平" + "中国农业银行舟山市定海支行营业中心" + "浙江省" + "舟山市" + "0.01" + "银企接口测试" + "103342040518" + "" + ""; 跨行转账 交易序列号 客户端请求时间 付款账号 收款账号 收款方户名 收款账号开户行名称 收款方行所在省 收款方行所在市 交易金额 用途 收款行号 ${serialNo}${reqTime}822601201020226316228481060643871117王苏平中国农业银行舟山市定海支行营业中心浙江省舟山市0.01银企接口测试103342040518 行内转账 交易序列号 客户端请求时间 付款账号 收款账号 收款方户名 交易金额 用途 ${serialNo}${reqTime}82260120102022631780401220000592777923119570.01银企接口测试 交易序列号 客户端请求时间 原交易序列号 ${serialNo}${reqTime}${serialNoOld} */ /** * 接收报文url */ private static final String URL = "http://127.0.0.1:9080/directlink/httpAccess"; /** * 签名ip */ private static final String VERIFY_IP = "127.0.0.1"; /** * 付款账号 */ private static final String FKZH = "82260120102022631"; /** * 签名端口 */ private static final int VERIFY_PORT = 8010; /** * cookies */ private static String cookies = null; /** * sessionId */ private static String sessionId = "-1"; /** * 客户号 */ private static String customerId = "0000005332"; /** * 客户号 */ private static String softwareId = "002"; /** * 返回码 */ private static String retCode; /** * 返回信息 */ private static String errorMessage; public static void main(String[] args) { try { // System.out.println("发送登录请求:"); // test.executeServerHttpService("srv001_signOn"); // System.out.println("\n发送转账结果查询请求:"); // executeServerHttpService("srv008_transferResultInfoQuery","转账结果查询","2023032910585227466"); // System.out.println("\n发送跨行转账请求:"); // test.executeServerHttpService("srv007_singleOuterTransfer","跨行转账",null); // System.out.println("\n发送行内转账请求:"); // executeServerHttpService("srv006_singleInnerTransfer","行内转账","2023032910585227466"); } catch (Exception e) { e.printStackTrace(); } } @Autowired private MallMemberWithdrawMapper mallMemberWithdrawMapper; @Autowired private MallMemberWithdrawMsgMapper mallMemberWithdrawMsgMapper; @Autowired private MallMemberBankMapper mallMemberBankMapper; @Override public boolean tradeSinge(Long id) { boolean flag = false; MallMemberWithdraw mallMemberWithdraw = mallMemberWithdrawMapper.selectById(id); MallMemberBank mallMemberBank = mallMemberBankMapper.selectById(mallMemberWithdraw.getWtihdrawTypeId()); try { String requestDataForWithDraw = getRequestDataForWithDraw("srv006_singleInnerTransfer", "行内转账", mallMemberWithdraw, mallMemberBank); String responseStr = executeServerHttpService(requestDataForWithDraw); boolean b = parseReturnValueForTrade(responseStr); if(b){ //插入一条记录 MallMemberWithdrawMsg mallMemberWithdrawMsg = mallMemberWithdrawMapper.selectMsgByWithdrawNo(mallMemberWithdraw.getWithdrawNo()); if(ObjectUtil.isEmpty(mallMemberWithdrawMsg)){ MallMemberWithdrawMsg mallMemberWithdrawMsg1 = new MallMemberWithdrawMsg(); mallMemberWithdrawMsg1.setWithdrawNo(mallMemberWithdraw.getWithdrawNo()); mallMemberWithdrawMsg1.setWithdrawId(mallMemberWithdraw.getId()); mallMemberWithdrawMsg1.setStatus(2); mallMemberWithdrawMsgMapper.insert(mallMemberWithdrawMsg1); } } flag = b; } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return flag; } @Override public boolean tradeSingeOuterTransfer(Long id) { boolean flag = false; MallMemberWithdraw mallMemberWithdraw = mallMemberWithdrawMapper.selectById(id); MallMemberBank mallMemberBank = mallMemberBankMapper.selectById(mallMemberWithdraw.getWtihdrawTypeId()); try { String requestDataForWithDraw = getRequestDataForWithDraw("srv007_singleOuterTransfer", "跨行汇款", mallMemberWithdraw, mallMemberBank); String responseStr = executeServerHttpService(requestDataForWithDraw); boolean b = parseReturnValueForTrade(responseStr); if(b){ //插入一条记录 MallMemberWithdrawMsg mallMemberWithdrawMsg = mallMemberWithdrawMapper.selectMsgByWithdrawNo(mallMemberWithdraw.getWithdrawNo()); if(ObjectUtil.isEmpty(mallMemberWithdrawMsg)){ MallMemberWithdrawMsg mallMemberWithdrawMsg1 = new MallMemberWithdrawMsg(); mallMemberWithdrawMsg1.setWithdrawNo(mallMemberWithdraw.getWithdrawNo()); mallMemberWithdrawMsg1.setWithdrawId(mallMemberWithdraw.getId()); mallMemberWithdrawMsg1.setStatus(2); mallMemberWithdrawMsgMapper.insert(mallMemberWithdrawMsg1); } } flag = b; } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return flag; } @Override public void transferResultInfoQuery(String withdrawNo) { MallMemberWithdrawMsg mallMemberWithdrawMsg = mallMemberWithdrawMapper.selectMsgByWithdrawNo(withdrawNo); if(ObjectUtil.isEmpty(mallMemberWithdrawMsg)){ return; } Integer status = mallMemberWithdrawMsg.getStatus(); if(1 == status){ return; } MallMemberWithdraw mallMemberWithdraw = mallMemberWithdrawMapper.selectById(mallMemberWithdrawMsg.getWithdrawId()); MallMemberBank mallMemberBank = mallMemberBankMapper.selectById(mallMemberWithdraw.getWtihdrawTypeId()); try { String requestDataForWithDraw = getRequestDataForWithDraw("srv008_transferResultInfoQuery", "转账结果查询", mallMemberWithdraw, mallMemberBank); String responseStr = executeServerHttpService(requestDataForWithDraw); boolean b = parseReturnValue(responseStr); if(b){ mallMemberWithdrawMsg.setStatus(1); mallMemberWithdrawMsgMapper.updateById(mallMemberWithdrawMsg); } return; } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } /** * 执行交易 * * @throws Exception */ @SuppressWarnings("rawtypes") public static String executeServerHttpService(String requestData) throws Exception { // public static void executeServerHttpService(String serviceId, String serviceName, String serialNo,String requestData) throws Exception { // 处理交易的url java.net.URL url = new URL(URL); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); if (cookies != null) { // 如果已登录,设置coikie connection.setRequestProperty("cokie", cookies); } // 请求以utf-8格式编码 connection.setRequestProperty("content-type", "text/xml;charset=utf-8"); connection.setDoInput(true); connection.setDoOutput(true); // post方式发送 connection.setRequestMethod("POST"); OutputStream out = connection.getOutputStream(); // 组装完整的交易报文 // String reqData = getRequestData(serviceId,serviceName,serialNo); String reqData = requestData; // utf-8 编码发送 System.out.println("请求报文:\n" + reqData); out.write(reqData.getBytes("UTF-8")); out.flush(); out.close(); int retCode = connection.getResponseCode(); if (retCode != 200) { throw new Exception("交易出错!retCode=" + retCode); } // 设置cookie Map heads = connection.getHeaderFields(); Object[] headNames = heads.keySet().toArray(); for (int i = 0; i < headNames.length; i++) { if (headNames[i] == null) { continue; } if ("Set-Cookie".equalsIgnoreCase((String) headNames[i])) { cookies = connection.getHeaderField(headNames[i] .toString()); } } int len = connection.getContentLength(); byte[] retData = readContent(connection.getInputStream(), len); String retStr = new String(retData, "UTF-8"); System.out.println("【返回报文】Ret Data:\n " + retStr); return retStr; // return parseReturnValue(retStr); } /** * 组装完整的报文 * * @param serviceId * @return * @throws FileNotFoundException * @throws IOException */ public static String getRequestData(String serviceId, String serviceName, String serialNo) throws FileNotFoundException, IOException { StringBuffer buf = new StringBuffer(); // 报文编码格式utf-8 buf.append(""); buf.append(""); buf.append(sessionId); buf.append(""); buf.append(""); buf.append(serviceId); buf.append(""); String reqData = ""; if (serviceId.equals("srv001_signOn")) { reqData = SIGN_MESSAGE; } else if (serviceId.equals("srv006_singleInnerTransfer")) { reqData = TRADE_MESSAGE_SINGLE; /** * ${serialNo}${reqTime}82260120102022631780401220000592777923119570.01银企接口测试 * * ${serialNo} * ${reqTime} * * ${FKZH} * ${SKZH} * ${SKHM} * ${JYJE} * ${YOTU} * * */ reqData = reqData.replaceFirst("\\$\\{FKZH\\}", serialNo); reqData = reqData.replaceFirst("\\$\\{SKZH\\}", serialNo); reqData = reqData.replaceFirst("\\$\\{SKHM\\}", serialNo); reqData = reqData.replaceFirst("\\$\\{JYJE\\}", serialNo); reqData = reqData.replaceFirst("\\$\\{YOTU\\}", serialNo); }else if (serviceId.equals("srv007_singleOuterTransfer")) { reqData = TRADE_MESSAGE; }else if (serviceId.equals("srv008_transferResultInfoQuery")) { reqData = TRADE_MESSAGE_SEARCH; //原订单流水号 reqData = reqData.replaceFirst("\\$\\{serialNoOld\\}", serialNo); } // String serialNo = String.valueOf(Math.round(Math.random() * 10000)) // + System.currentTimeMillis(); Calendar calendar = Calendar.getInstance(); Date date = calendar.getTime(); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); String reqTime = sdf.format(date); reqData = reqData.replaceFirst("\\$\\{serialNo\\}", serialNo); reqData = reqData.replaceFirst("\\$\\{reqTime\\}", reqTime); String signData = null; try { signData = signData(reqData); signData = getNodeValue(signData, "signed_data"); } catch (Exception e) { e.printStackTrace(); } buf.append(""); buf.append(customerId); buf.append(""); buf.append(""); buf.append(softwareId); buf.append(""); buf.append(""); buf.append(serviceId.substring(0, 6)); buf.append(""); buf.append(""); buf.append(serviceName); buf.append(""); buf.append(reqData + "" + signData + ""); return buf.toString(); } /** * 组装完整的报文 * * @param serviceId * @return * @throws FileNotFoundException * @throws IOException */ public static String getRequestDataForWithDraw(String serviceId, String serviceName,MallMemberWithdraw mallMemberWithdraw,MallMemberBank mallMemberBank) throws FileNotFoundException, IOException { StringBuffer buf = new StringBuffer(); // 报文编码格式utf-8 buf.append(""); buf.append(""); buf.append(sessionId); buf.append(""); buf.append(""); buf.append(serviceId); buf.append(""); String reqData = ""; if (serviceId.equals("srv001_signOn")) { reqData = SIGN_MESSAGE; } else if (serviceId.equals("srv006_singleInnerTransfer")) { reqData = TRADE_MESSAGE_SINGLE; /** * ${serialNo}${reqTime}82260120102022631780401220000592777923119570.01银企接口测试 * * ${serialNo} * ${reqTime} * * ${FKZH} * ${SKZH} * ${SKHM} * ${JYJE} * ${YOTU} * * */ reqData = reqData.replaceFirst("\\$\\{FKZH\\}", FKZH); reqData = reqData.replaceFirst("\\$\\{SKZH\\}", mallMemberBank.getBankNo()); reqData = reqData.replaceFirst("\\$\\{SKHM\\}", mallMemberBank.getName()); if(mallMemberWithdraw.getRemark().equals("凭证提现")){ reqData = reqData.replaceFirst("\\$\\{JYJE\\}", mallMemberWithdraw.getAmount().setScale(2, BigDecimal.ROUND_DOWN).toString()); }else{ reqData = reqData.replaceFirst("\\$\\{JYJE\\}", mallMemberWithdraw.getAmount().subtract(mallMemberWithdraw.getAmountFee()).setScale(2, BigDecimal.ROUND_DOWN).toString()); } reqData = reqData.replaceFirst("\\$\\{YOTU\\}", "行内转账"); }else if (serviceId.equals("srv007_singleOuterTransfer")) { /** * ${serialNo}${reqTime}822601201020226316228481060643871117王苏平中国农业银行舟山市定海支行营业中心浙江省舟山市0.01银企接口测试103342040518 * * ${serialNo} * ${reqTime} * * ${FKZH} * ${SKZH} * ${SKHM} * ${SKYH} * ${SKSH} * ${SKSI} * ${JYJE} * ${YOTU} * ${SKHH} * * * * ${serialNo}${reqTime}${FKZH}${SKZH}${SKHM}${SKYH}${SKSH}${SKSI}${JYJE}${YOTU}${SKHH} */ reqData = TRADE_MESSAGE; reqData = reqData.replaceFirst("\\$\\{FKZH\\}", FKZH); reqData = reqData.replaceFirst("\\$\\{SKZH\\}", mallMemberBank.getBankNo()); reqData = reqData.replaceFirst("\\$\\{SKHM\\}", mallMemberBank.getName()); reqData = reqData.replaceFirst("\\$\\{SKYH\\}", mallMemberBank.getBankName()+mallMemberBank.getSubbranchName()); reqData = reqData.replaceFirst("\\$\\{SKSH\\}", mallMemberBank.getProvince()); reqData = reqData.replaceFirst("\\$\\{SKSI\\}", mallMemberBank.getCity()); if(mallMemberWithdraw.getRemark().equals("凭证提现")){ reqData = reqData.replaceFirst("\\$\\{JYJE\\}", mallMemberWithdraw.getAmount().setScale(2, BigDecimal.ROUND_DOWN).toString()); }else{ reqData = reqData.replaceFirst("\\$\\{JYJE\\}", mallMemberWithdraw.getAmount().subtract(mallMemberWithdraw.getAmountFee()).setScale(2, BigDecimal.ROUND_DOWN).toString()); } reqData = reqData.replaceFirst("\\$\\{YOTU\\}", "跨行汇款"); reqData = reqData.replaceFirst("\\$\\{SKHH\\}", mallMemberBank.getSkhh()); }else if (serviceId.equals("srv008_transferResultInfoQuery")) { reqData = TRADE_MESSAGE_SEARCH; //原订单流水号 reqData = reqData.replaceFirst("\\$\\{serialNoOld\\}", mallMemberWithdraw.getWithdrawNo()); } // String serialNo = String.valueOf(Math.round(Math.random() * 10000)) // + System.currentTimeMillis(); Calendar calendar = Calendar.getInstance(); Date date = calendar.getTime(); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); String reqTime = sdf.format(date); reqData = reqData.replaceFirst("\\$\\{serialNo\\}", mallMemberWithdraw.getWithdrawNo()); reqData = reqData.replaceFirst("\\$\\{reqTime\\}", reqTime); String signData = null; try { signData = signData(reqData); signData = getNodeValue(signData, "signed_data"); } catch (Exception e) { e.printStackTrace(); } buf.append(""); buf.append(customerId); buf.append(""); buf.append(""); buf.append(softwareId); buf.append(""); buf.append(""); buf.append(serviceId.substring(0, 6)); buf.append(""); buf.append(""); buf.append(serviceName); buf.append(""); buf.append(reqData + "" + signData + ""); return buf.toString(); } /** * 数据加密 *
* 重点 *
* 1.orignalData.getBytes("GBK").length 获取GBK编码格式的字节长度,为了通过格式验证 *
* 2.new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(),"GBK")); 指定流的编码格式,使加密服务接收到正确的中文字符 *
* * @param orignalData 原报文体 * @return * @throws UnsupportedEncodingException */ public static String signData(String orignalData) throws UnsupportedEncodingException { InetAddress addr = null; Socket socket = null; // 加密报文编码格式gbk String verifyheader = "\n" + "\n" + "\n" + "0\n" + "1005\n" + "0\n" + "1\n" + "\n" + "\n" + "" + orignalData.getBytes("GBK").length + "\n" + "" + orignalData + "\n" + "\n" + ""; try { addr = InetAddress.getByName(VERIFY_IP); socket = new Socket(addr, VERIFY_PORT); // 发送 BufferedWriter wr = new BufferedWriter(new OutputStreamWriter( socket.getOutputStream(),"GBK")); System.out.println("【数据加密】加密的明文:" + verifyheader); wr.write(verifyheader); wr.flush(); // 接收 BufferedReader rd = new BufferedReader(new InputStreamReader( socket.getInputStream(),"ISO8859-1")); String line = null; StringBuffer sb = new StringBuffer(); while ((line = rd.readLine()) != null) { sb.append(line); } // 处理返回 String returnStr = new String(sb.toString().getBytes("ISO8859-1"),"GBK"); System.out.println("【数据加密】返回的密文:" + returnStr); wr.close(); rd.close(); socket.close(); return returnStr; } catch (Exception e) { e.printStackTrace(); } return ""; } /** * 从加密返回密文中取出signData * * @param returnStr * @param tagName * @return */ public static String getNodeValue(String returnStr, String tagName) { int startIdx, endIdx; String beginTag = "<" + tagName + ">"; String endTag = ""; startIdx = returnStr.indexOf(beginTag) + beginTag.length(); endIdx = returnStr.indexOf(endTag, startIdx); return returnStr.substring(startIdx, endIdx); } /** * 处理返回信息 * * @param src * @throws Exception */ public static boolean parseReturnValueForTrade(String src) throws Exception { int beginIndex = src.indexOf(""); int endIndex = src.indexOf(""); String sessionIdRep = ""; if (beginIndex != -1 && endIndex != -1) { sessionIdRep = src.substring(beginIndex + 11, endIndex); } if (!sessionIdRep.equals("-1") && !sessionId.equals("-1") && !sessionId.equals(sessionIdRep)) // throw new Exception("上送的sessionId和返回的sessionId不一致! " + src); return false; if (sessionId.equals("-1")) sessionId = sessionIdRep; retCode = src.substring(src.indexOf("") + 9, src.indexOf("")); String JyztStr = src.substring(src.indexOf("") + 6, src.indexOf("")); String YddmStr = src.substring(src.indexOf("") + 6, src.indexOf("")); try { errorMessage = src.substring(src.indexOf("") + 10, src.indexOf("")); } catch (Exception e) { } // if (retCode == null || !retCode.equals("0000")) { // throw new Exception("ServerException: ErrorCode=" + retCode // + " ErrorMessage=" + errorMessage); // } /** * JyztStr * 交易成功 90 * 银行已受理,可通过转账结果查询进行状态查证 94 * 交易处理中,需过转账结果查询接口进行状态查证 99或者值为空 * * YddmStr * 0000或000000表示成功,其他标识失败 */ if((JyztStr.equals("90") || JyztStr.equals("94") || JyztStr.equals("99")) && (YddmStr.equals("0000") || YddmStr.equals("000000"))){ return true; }else{ return false; } } /** * 处理返回信息 * * @param src * @throws Exception */ public static boolean parseReturnValue(String src) throws Exception { int beginIndex = src.indexOf(""); int endIndex = src.indexOf(""); String sessionIdRep = ""; if (beginIndex != -1 && endIndex != -1) { sessionIdRep = src.substring(beginIndex + 11, endIndex); } if (!sessionIdRep.equals("-1") && !sessionId.equals("-1") && !sessionId.equals(sessionIdRep)) // throw new Exception("上送的sessionId和返回的sessionId不一致! " + src); return false; if (sessionId.equals("-1")) sessionId = sessionIdRep; retCode = src.substring(src.indexOf("") + 9, src.indexOf("")); String JyztStr = src.substring(src.indexOf("") + 6, src.indexOf("")); String YddmStr = src.substring(src.indexOf("") + 6, src.indexOf("")); try { errorMessage = src.substring(src.indexOf("") + 10, src.indexOf("")); } catch (Exception e) { } // if (retCode == null || !retCode.equals("0000")) { // throw new Exception("ServerException: ErrorCode=" + retCode // + " ErrorMessage=" + errorMessage); // } /** * JyztStr * 交易成功 90 * 银行已受理,可通过转账结果查询进行状态查证 94 * 交易处理中,需过转账结果查询接口进行状态查证 99或者值为空 * * YddmStr * 0000或000000表示成功,其他标识失败 */ if((JyztStr.equals("90")) && (YddmStr.equals("0000") || YddmStr.equals("000000"))){ return true; }else{ return false; } } /** * 读取返回信息 * * @param in * @param len * @return * @throws IOException */ public static byte[] readContent(InputStream in, int len) throws IOException { if (len <= 0) { byte[] buf = new byte[2048]; byte[] readBuf = new byte[1024]; int totalLen = 0; while (true) { int readLen = in.read(readBuf); if (readLen <= 0) break; if (totalLen + readLen > buf.length) { byte[] tmp = new byte[buf.length + readLen + 1024]; System.arraycopy(buf, 0, tmp, 0, totalLen); buf = tmp; } System.arraycopy(readBuf, 0, buf, totalLen, readLen); totalLen = totalLen + readLen; } byte[] retBuf = new byte[totalLen]; System.arraycopy(buf, 0, retBuf, 0, totalLen); return retBuf; } else { int totalLen = 0; byte[] buf = new byte[len]; while (totalLen < len) { int readLen = in.read(buf, totalLen, len - totalLen); if (readLen <= 0) break; totalLen = totalLen + readLen; } return buf; } } }