package com.saye.hgddmz.controller; import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.text.csv.CsvData; import cn.hutool.core.text.csv.CsvReader; import cn.hutool.core.text.csv.CsvRow; import cn.hutool.core.text.csv.CsvUtil; import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.XmlUtil; import cn.hutool.crypto.SecureUtil; import cn.hutool.http.HttpUtil; import cn.hutool.json.JSONUtil; import com.saye.hgddmz.commons.date.DateDUtil; import com.saye.hgddmz.commons.string.StringDUtil; import com.saye.hgddmz.entity.BankbillHistory; import com.saye.hgddmz.entity.UserOrder; import com.saye.hgddmz.util.DownloadFtpUtil; import com.saye.hgddmz.util.HttpClientUtil; import lombok.extern.slf4j.Slf4j; import org.apache.poi.hssf.usermodel.*; import org.apache.poi.ss.usermodel.Cell; import org.springframework.core.io.InputStreamResource; import org.springframework.http.*; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.text.DecimalFormat; import java.util.*; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.w3c.dom.Document; import org.w3c.dom.Element; /** * @author thuang * @version 1.0 * @description: TODO * @date 2021/9/22 13:55 */ @Controller @Slf4j public class GetDateController { private static String grant_type = "client_credential"; private static String appid = "wx45acd2b4907cb8f4"; private static String secret = "895b90585c4698485c07e113711eac85"; private static String key = "Nxwj20250903Jojubanking12091209x"; private static String key_yb = "086831b6021364d2e96e523771087a02"; // 微信消息推送相关常量 private static String WX_APP_ID = "wx45acd2b4907cb8f4"; private static String WX_SECRET = "895b90585c4698485c07e113711eac85"; /** * 安全获取单元格字符串值 * @param row 行对象 * @param cellIndex 单元格索引 * @return 单元格字符串值,如果单元格为空则返回空字符串 */ private static String getCellStringValue(HSSFRow row, int cellIndex) { if (row == null) { return ""; } HSSFCell cell = row.getCell(cellIndex); if (cell == null) { return ""; } try { cell.setCellType(Cell.CELL_TYPE_STRING); String value = cell.getStringCellValue(); return value != null ? value.trim() : ""; } catch (Exception e) { log.warn("获取单元格值失败,行: {}, 列: {}, 错误: {}", row.getRowNum(), cellIndex, e.getMessage()); return ""; } } /** * 安全获取单元格日期值 * @param row 行对象 * @param cellIndex 单元格索引 * @return 日期字符串,如果单元格为空或不是日期格式则返回空字符串 */ private static String getCellDateValue(HSSFRow row, int cellIndex) { if (row == null) { return ""; } HSSFCell cell = row.getCell(cellIndex); if (cell == null) { return ""; } try { cell.setCellType(Cell.CELL_TYPE_NUMERIC); if (HSSFDateUtil.isCellDateFormatted(cell)) { Date dateCellValue = cell.getDateCellValue(); return DateDUtil.DateToStr(DateDUtil.yyyy_MM_dd, dateCellValue); } return ""; } catch (Exception e) { log.warn("获取单元格日期值失败,行: {}, 列: {}, 错误: {}", row.getRowNum(), cellIndex, e.getMessage()); return ""; } } /** * @description: 获取银行端商户对账数据 * @author thuang * @date 2021/9/22 13:57 * @version 1.0 */ @PostMapping("/getBankDataBySH") @ResponseBody public HashMap getBankDataBySH(@RequestBody HashMap map) { HashMap responseMap = new HashMap<>(); String errCode = "0"; String errMsg = ""; // 先下载文件 String host = StringDUtil.changeNullToEmpty(map.get("FTP_HOST")); String portStr = StringDUtil.changeNullToEmpty(map.get("FTP_PORT")); int port = Integer.parseInt("".equals(portStr) ? "21" : portStr); String username = StringDUtil.changeNullToEmpty(map.get("FTP_USER")); String password = StringDUtil.changeNullToEmpty(map.get("FTP_PASSWORD")); String localPath = StringDUtil.changeNullToEmpty(map.get("LOCAL_PATH")); String mch_id = StringDUtil.changeNullToEmpty(map.get("MCH_ID")); String ftp_path = StringDUtil.changeNullToEmpty(map.get("FTP_PATH")); String ftp_file_name = StringDUtil.changeNullToEmpty(map.get("FTP_FILE_NAME")); String bill_table_name = StringDUtil.changeNullToEmpty(map.get("BILL_TABLE_NAME")); String thirdConfigId = StringDUtil.changeNullToEmpty(map.get("ID")); String trade_date = StringDUtil.changeNullToEmpty(map.get("trade_date")); HSSFWorkbook sheets = null; try { // 下载文件 log.info("开始下载FTP文件: " + ftp_file_name); boolean b = DownloadFtpUtil.downloadFtpFile(host, username, password, port, ftp_path, localPath, ftp_file_name); // 判断是否下载到文件 if (!b) { log.error("FTP文件下载失败: " + ftp_file_name); errCode = "1"; errMsg = "FTP文件下载失败,请检查FTP连接参数和文件是否存在"; responseMap.put("errCode", errCode); responseMap.put("errMsg", errMsg); return responseMap; } // 判断本地是否有文件 File file = new File(localPath + "/" + ftp_file_name); if (file.exists()) { // 存在 开始解析 存入数据库 FileInputStream fileInputStream = new FileInputStream(localPath + "/" + ftp_file_name); sheets = new HSSFWorkbook(fileInputStream); HSSFSheet sheet = sheets.getSheetAt(0); // 获取sheet中第一行行号 int firstRowNum = sheet.getFirstRowNum(); // 获取sheet中最后一行行号 int lastRowNum = sheet.getLastRowNum(); List list = new ArrayList<>(); for (int i = firstRowNum + 3; i <= lastRowNum - 2; i++) {// 因为表格中第一行为说明,第二行为列标题 HSSFRow row = sheet.getRow(i); if (row == null) { continue; } BankbillHistory bankbillHistory = new BankbillHistory(); // 清算日期 String qsrqStr = getCellStringValue(row, 0); // 拿第一个字段判断这条记录是否为空 如果为空直接跳出 一般这字段为空就是数据结束了或根本没有 // 为合计也跳出 if ("".equals(qsrqStr) || "合计".equals(qsrqStr)) { break; } bankbillHistory.setCQsrq(qsrqStr); // 交易日期 String jyrqStr = getCellDateValue(row, 1); bankbillHistory.setCJyrq(jyrqStr); if (i == firstRowNum + 3) { trade_date = jyrqStr; } // 交易时间 String jysjStr = getCellStringValue(row, 2); bankbillHistory.setCJysj(jysjStr); // 卡号 String khStr = getCellStringValue(row, 3); bankbillHistory.setCCard(khStr); // 交易类型 String jylxStr = getCellStringValue(row, 4); bankbillHistory.setCJylx(jylxStr); // 交易金额 String jyjeStr = getCellStringValue(row, 5); bankbillHistory.setCJyje(jyjeStr); // 终端号 String zdhStr = getCellStringValue(row, 6); bankbillHistory.setCZdh(zdhStr); // 清算金额 String qsjeStr = getCellStringValue(row, 7); bankbillHistory.setCQsje(qsjeStr); // 手续费 String sxfStr = getCellStringValue(row, 8); bankbillHistory.setCSxf(sxfStr); // 参考号 String ckhStr = getCellStringValue(row, 9); bankbillHistory.setCCkh(ckhStr); // 流水号 String lshStr = getCellStringValue(row, 10); bankbillHistory.setCLsh(lshStr); // 卡类型 String klxStr = getCellStringValue(row, 11); bankbillHistory.setCKlx(klxStr); // 商户订单号 String shddhStr = getCellStringValue(row, 12); bankbillHistory.setCShddh(shddhStr); // 支付方式 String zffsStr = getCellStringValue(row, 13); bankbillHistory.setCZffs(zffsStr); // 银商订单号 String ysddhStr = getCellStringValue(row, 14); bankbillHistory.setCYsddh(ysddhStr); // 退货订单号 String thddhStr = getCellStringValue(row, 15); bankbillHistory.setCThddh(thddhStr); // 实际支付金额 String sjzfjeStr = getCellStringValue(row, 16); bankbillHistory.setCSjzfje(sjzfjeStr); // 备注字段 String bzzdStr = getCellStringValue(row, 17); bankbillHistory.setCBzzd(bzzdStr); // 付款附言 String fkfyStr = getCellStringValue(row, 18); bankbillHistory.setCFkfy(fkfyStr); // 钱包优惠金额 String qbyhjeStr = getCellStringValue(row, 19); bankbillHistory.setCQbyhje(qbyhjeStr); // 商户优惠金额 String shyhjeStr = getCellStringValue(row, 20); bankbillHistory.setCShyhje(shyhjeStr); // 发卡行 String fkhStr = getCellStringValue(row, 21); bankbillHistory.setCFkh(fkhStr); // 分店简称 String fdjcStr = getCellStringValue(row, 22); bankbillHistory.setCFdjc(fdjcStr); // 其他优惠金额 String qtyhjeStr = getCellStringValue(row, 23); bankbillHistory.setCQtyhje(qtyhjeStr); // 分期期数 String fqqsStr = getCellStringValue(row, 24); bankbillHistory.setCFqqs(fqqsStr); // 分期手续费 String fqsxfStr = getCellStringValue(row, 25); bankbillHistory.setCFqsxf(fqsxfStr); // 分期服务方 String fqfwfStr = getCellStringValue(row, 26); bankbillHistory.setCFqfwf(fqfwfStr); // 分期付息方 String fqfxfStr = getCellStringValue(row, 27); bankbillHistory.setCFqfxf(fqfxfStr); // 子订单号 String zddhStr = getCellStringValue(row, 28); bankbillHistory.setCZddh(zddhStr); // 表名 bankbillHistory.setBillTableName(bill_table_name); list.add(bankbillHistory); } responseMap.put("list", list); } else { System.out.println("执行失败,原因:路径" + ftp_path + "下无下载文件" + ftp_file_name); errCode = "999"; errMsg = "执行失败,原因:路径" + ftp_path + "下无下载文件" + ftp_file_name; } } catch (Exception e) { e.printStackTrace(); System.out.println("执行失败,原因:" + e.getMessage()); errCode = "999"; errMsg = "执行失败,原因:" + e.getMessage(); } finally { try { if (sheets != null) { sheets.close(); } } catch (Exception ie) { ie.printStackTrace(); } } responseMap.put("errCode", errCode); responseMap.put("errMsg", errMsg); return responseMap; } /** * @description: 获取银行端商户POS对账数据 * @author thuang * @date 2021/9/22 13:57 * @version 1.0 */ @PostMapping("/getBankDataBySHPOS") @ResponseBody public HashMap getBankDataBySHPOS(@RequestBody HashMap map) { HashMap responseMap = new HashMap<>(); String errCode = "0"; String errMsg = ""; // 先下载文件 String host = StringDUtil.changeNullToEmpty(map.get("FTP_HOST")); String portStr = StringDUtil.changeNullToEmpty(map.get("FTP_PORT")); int port = Integer.parseInt("".equals(portStr) ? "21" : portStr); String username = StringDUtil.changeNullToEmpty(map.get("FTP_USER")); String password = StringDUtil.changeNullToEmpty(map.get("FTP_PASSWORD")); String localPath = StringDUtil.changeNullToEmpty(map.get("LOCAL_PATH")); String mch_id = StringDUtil.changeNullToEmpty(map.get("MCH_ID")); String ftp_path = StringDUtil.changeNullToEmpty(map.get("FTP_PATH")); String ftp_file_name = StringDUtil.changeNullToEmpty(map.get("FTP_FILE_NAME")); String bill_table_name = StringDUtil.changeNullToEmpty(map.get("BILL_TABLE_NAME")); String thirdConfigId = StringDUtil.changeNullToEmpty(map.get("ID")); String trade_date = StringDUtil.changeNullToEmpty(map.get("trade_date")); HSSFWorkbook sheets = null; try { // 下载文件 log.info("开始下载FTP文件: " + ftp_file_name); boolean b = DownloadFtpUtil.downloadFtpFile(host, username, password, port, ftp_path, localPath, ftp_file_name); // 判断是否下载到文件 if (!b) { log.error("FTP文件下载失败: " + ftp_file_name); errCode = "1"; errMsg = "FTP文件下载失败,请检查FTP连接参数和文件是否存在"; responseMap.put("errCode", errCode); responseMap.put("errMsg", errMsg); return responseMap; } // 判断本地是否有文件 File file = new File(localPath + "/" + ftp_file_name); if (file.exists()) { // 存在 开始解析 存入数据库 FileInputStream fileInputStream = new FileInputStream(localPath + "/" + ftp_file_name); sheets = new HSSFWorkbook(fileInputStream); HSSFSheet sheet = sheets.getSheetAt(0); // 获取sheet中第一行行号 int firstRowNum = sheet.getFirstRowNum(); // 获取sheet中最后一行行号 int lastRowNum = sheet.getLastRowNum(); List list = new ArrayList<>(); for (int i = firstRowNum + 3; i <= lastRowNum - 4; i++) { log.info("正在解析第" + i + "行数据");// 因为表格中第一行为说明,第二行为列标题 HSSFRow row = sheet.getRow(i); if (row == null) { continue; } BankbillHistory bankbillHistory = new BankbillHistory(); // 清算日期 String qsrqStr = getCellStringValue(row, 0); // 拿第一个字段判断这条记录是否为空 如果为空直接跳出 一般这字段为空就是数据结束了或根本没有 if ("".equals(qsrqStr) || "汇总信息".equals(qsrqStr)) { break; } bankbillHistory.setCQsrq(qsrqStr); // 交易日期 String jyrqStr = getCellDateValue(row, 1); bankbillHistory.setCJyrq(jyrqStr); if (i == firstRowNum + 3) { trade_date = jyrqStr; } // 交易时间 String jysjStr = getCellStringValue(row, 2); bankbillHistory.setCJysj(jysjStr); // 终端号 String zdhStr = getCellStringValue(row, 3); bankbillHistory.setCZdh(zdhStr); // 卡号 String khStr = getCellStringValue(row, 4); bankbillHistory.setCCard(khStr); // 交易类型 String jylxStr = getCellStringValue(row, 5); bankbillHistory.setCJylx(jylxStr); // 交易金额 String jyjeStr = getCellStringValue(row, 6); log.info("jyjeStr:" + jyjeStr); bankbillHistory.setCJyje(jyjeStr); // 清算金额 String qsjeStr = getCellStringValue(row, 7); bankbillHistory.setCQsje(qsjeStr); // 手续费 String sxfStr = getCellStringValue(row, 8); bankbillHistory.setCSxf(sxfStr); // 参考号 String ckhStr = getCellStringValue(row, 9); bankbillHistory.setCCkh(ckhStr); // 流水号 String lshStr = getCellStringValue(row, 10); bankbillHistory.setCLsh(lshStr); // 卡类型 String klxStr = getCellStringValue(row, 11); bankbillHistory.setCKlx(klxStr); // 发卡行 String fkhStr = getCellStringValue(row, 12); bankbillHistory.setCFkh(fkhStr); // 支付方式 String zffsStr = getCellStringValue(row, 13); bankbillHistory.setCZffs(zffsStr); // 银商订单号 String ysddhStr = getCellStringValue(row, 15); log.info("ysddhStr:" + ysddhStr); bankbillHistory.setCYsddh(ysddhStr); // 商户订单号 String shddhStr = getCellStringValue(row, 16); bankbillHistory.setCShddh(shddhStr); // 备注字段 String bzzdStr = getCellStringValue(row, 18); bankbillHistory.setCBzzd(bzzdStr); // 钱包优惠金额 String fdmcjjStr = getCellStringValue(row, 19); bankbillHistory.setCFdjc(fdmcjjStr); // 表名 bankbillHistory.setBillTableName(bill_table_name); list.add(bankbillHistory); } responseMap.put("list", list); } else { System.out.println("执行失败,原因:路径" + ftp_path + "下无下载文件" + ftp_file_name); errCode = "999"; errMsg = "执行失败,原因:路径" + ftp_path + "下无下载文件" + ftp_file_name; } } catch (Exception e) { e.printStackTrace(); System.out.println("执行失败,原因:" + e.getMessage()); errCode = "999"; errMsg = "执行失败,原因:" + e.getMessage(); } finally { try { if (sheets != null) { sheets.close(); } } catch (Exception ie) { ie.printStackTrace(); } } responseMap.put("errCode", errCode); responseMap.put("errMsg", errMsg); return responseMap; } /** * @description: 获取银行端商户银联卡对账数据 * @author thuang * @date 2021/9/22 13:57 * @version 1.0 */ @PostMapping("/getBankDataBySHYLK") @ResponseBody public HashMap getBankDataBySHYLK(@RequestBody HashMap map) { HashMap responseMap = new HashMap<>(); String errCode = "0"; String errMsg = ""; // 先下载文件 String host = StringDUtil.changeNullToEmpty(map.get("FTP_HOST")); String portStr = StringDUtil.changeNullToEmpty(map.get("FTP_PORT")); int port = Integer.parseInt("".equals(portStr) ? "21" : portStr); String username = StringDUtil.changeNullToEmpty(map.get("FTP_USER")); String password = StringDUtil.changeNullToEmpty(map.get("FTP_PASSWORD")); String localPath = StringDUtil.changeNullToEmpty(map.get("LOCAL_PATH")); String mch_id = StringDUtil.changeNullToEmpty(map.get("MCH_ID")); String ftp_path = StringDUtil.changeNullToEmpty(map.get("FTP_PATH")); String ftp_file_name = StringDUtil.changeNullToEmpty(map.get("FTP_FILE_NAME")); String bill_table_name = StringDUtil.changeNullToEmpty(map.get("BILL_TABLE_NAME")); String thirdConfigId = StringDUtil.changeNullToEmpty(map.get("ID")); String trade_date = StringDUtil.changeNullToEmpty(map.get("trade_date")); HSSFWorkbook sheets = null; try { // 下载文件 log.info("开始下载FTP文件: " + ftp_file_name); boolean b = DownloadFtpUtil.downloadFtpFile(host, username, password, port, ftp_path, localPath, ftp_file_name); // 判断是否下载到文件 if (!b) { log.error("FTP文件下载失败: " + ftp_file_name); errCode = "1"; errMsg = "FTP文件下载失败,请检查FTP连接参数和文件是否存在"; responseMap.put("errCode", errCode); responseMap.put("errMsg", errMsg); return responseMap; } // 判断本地是否有文件 File file = new File(localPath + "/" + ftp_file_name); if (file.exists()) { // 存在 开始解析 存入数据库 FileInputStream fileInputStream = new FileInputStream(localPath + "/" + ftp_file_name); sheets = new HSSFWorkbook(fileInputStream); HSSFSheet sheet = sheets.getSheetAt(0); // 获取sheet中第一行行号 int firstRowNum = sheet.getFirstRowNum(); // 获取sheet中最后一行行号 int lastRowNum = sheet.getLastRowNum(); List list = new ArrayList<>(); for (int i = firstRowNum + 3; i <= lastRowNum - 2; i++) {// 因为表格中第一行为说明,第二行为列标题 HSSFRow row = sheet.getRow(i); if (row == null) { continue; } BankbillHistory bankbillHistory = new BankbillHistory(); // 清算日期 String qsrqStr = getCellStringValue(row, 0); // 拿第一个字段判断这条记录是否为空 如果为空直接跳出 一般这字段为空就是数据结束了或根本没有 if ("".equals(qsrqStr) || "合计".equals(qsrqStr)) { break; } bankbillHistory.setCQsrq(qsrqStr); // 交易日期 String jyrqStr = getCellDateValue(row, 1); bankbillHistory.setCJyrq(jyrqStr); if (i == firstRowNum + 3) { trade_date = jyrqStr; } // 交易时间 String jysjStr = getCellStringValue(row, 2); bankbillHistory.setCJysj(jysjStr); // 终端号 String zdhStr = getCellStringValue(row, 3); bankbillHistory.setCZdh(zdhStr); // 卡号 String khStr = getCellStringValue(row, 4); bankbillHistory.setCCard(khStr); // 交易类型 String jylxStr = getCellStringValue(row, 5); bankbillHistory.setCJylx(jylxStr); // 交易金额 String jyjeStr = getCellStringValue(row, 6); bankbillHistory.setCJyje(jyjeStr); // 清算金额 String qsjeStr = getCellStringValue(row, 7); bankbillHistory.setCQsje(qsjeStr); // 手续费 String sxfStr = getCellStringValue(row, 8); bankbillHistory.setCSxf(sxfStr); // 流水号 String lshStr = getCellStringValue(row, 9); bankbillHistory.setCLsh(lshStr); // 卡类型 String klxStr = getCellStringValue(row, 10); bankbillHistory.setCKlx(klxStr); // 发卡行 String fkhStr = getCellStringValue(row, 11); bankbillHistory.setCFkh(fkhStr); // 系统参考号 (对应银商订单号) String xtckhStr = getCellStringValue(row, 12); // 支付方式 bankbillHistory.setCZffs("银行卡支付"); // 银商订单号 bankbillHistory.setCYsddh(xtckhStr); // 表名 bankbillHistory.setBillTableName(bill_table_name); list.add(bankbillHistory); } responseMap.put("list", list); } else { System.out.println("执行失败,原因:路径" + ftp_path + "下无下载文件" + ftp_file_name); errCode = "999"; errMsg = "执行失败,原因:路径" + ftp_path + "下无下载文件" + ftp_file_name; } } catch (Exception e) { e.printStackTrace(); System.out.println("执行失败,原因:" + e.getMessage()); errCode = "999"; errMsg = "执行失败,原因:" + e.getMessage(); } finally { try { if (sheets != null) { sheets.close(); } } catch (Exception ie) { ie.printStackTrace(); } } responseMap.put("errCode", errCode); responseMap.put("errMsg", errMsg); return responseMap; } /** * @description: 获取银行端商户银联外卡对账数据 * @author yuan * @date 2025/7/18 13:57 * @version 1.0 */ @PostMapping("/getBankDataBySHYLWK") @ResponseBody public HashMap getBankDataBySHYLWK(@RequestBody HashMap map) { HashMap responseMap = new HashMap<>(); String errCode = "0"; String errMsg = ""; // 先下载文件 String host = StringDUtil.changeNullToEmpty(map.get("FTP_HOST")); String portStr = StringDUtil.changeNullToEmpty(map.get("FTP_PORT")); int port = Integer.parseInt("".equals(portStr) ? "21" : portStr); String username = StringDUtil.changeNullToEmpty(map.get("FTP_USER")); String password = StringDUtil.changeNullToEmpty(map.get("FTP_PASSWORD")); String localPath = StringDUtil.changeNullToEmpty(map.get("LOCAL_PATH")); String mch_id = StringDUtil.changeNullToEmpty(map.get("MCH_ID")); String ftp_path = StringDUtil.changeNullToEmpty(map.get("FTP_PATH")); String ftp_file_name = StringDUtil.changeNullToEmpty(map.get("FTP_FILE_NAME")); String bill_table_name = StringDUtil.changeNullToEmpty(map.get("BILL_TABLE_NAME")); String thirdConfigId = StringDUtil.changeNullToEmpty(map.get("ID")); String trade_date = StringDUtil.changeNullToEmpty(map.get("trade_date")); HSSFWorkbook sheets = null; try { // 下载文件 log.info("开始下载FTP文件: " + ftp_file_name); boolean b = DownloadFtpUtil.downloadFtpFile(host, username, password, port, ftp_path, localPath, ftp_file_name); // 判断是否下载到文件 if (!b) { log.error("FTP文件下载失败: " + ftp_file_name); errCode = "1"; errMsg = "FTP文件下载失败,请检查FTP连接参数和文件是否存在"; responseMap.put("errCode", errCode); responseMap.put("errMsg", errMsg); return responseMap; } // 判断本地是否有文件 File file = new File(localPath + "/" + ftp_file_name); if (file.exists()) { // 存在 开始解析 存入数据库 FileInputStream fileInputStream = new FileInputStream(localPath + "/" + ftp_file_name); sheets = new HSSFWorkbook(fileInputStream); HSSFSheet sheet = sheets.getSheetAt(0); // 获取sheet中第一行行号 int firstRowNum = sheet.getFirstRowNum(); // 获取sheet中最后一行行号 int lastRowNum = sheet.getLastRowNum(); List list = new ArrayList<>(); // 银联外卡对账单从第4行开始解析数据(前3行是标题和表头) for (int i = firstRowNum + 3; i <= lastRowNum - 2; i++) { HSSFRow row = sheet.getRow(i); if (row == null) { continue; } BankbillHistory bankbillHistory = new BankbillHistory(); // 清算日期 String qsrqStr = getCellStringValue(row, 0); // 拿第一个字段判断这条记录是否为空 如果为空直接跳出 if ("".equals(qsrqStr) || "合计".equals(qsrqStr)) { break; } bankbillHistory.setCQsrq(qsrqStr); // 交易日期 String jyrqStr = getCellDateValue(row, 1); bankbillHistory.setCJyrq(jyrqStr); // 交易时间 String jysjStr = getCellStringValue(row, 2); bankbillHistory.setCJysj(jysjStr); // 终端号 String zdhStr = getCellStringValue(row, 3); bankbillHistory.setCZdh(zdhStr); // 卡号 String khStr = getCellStringValue(row, 4); bankbillHistory.setCCard(khStr); // 交易类型 String jylxStr = getCellStringValue(row, 5); bankbillHistory.setCJylx(jylxStr); // 交易金额 String jyjeStr = getCellStringValue(row, 6); bankbillHistory.setCJyje(jyjeStr); // 清算金额 String qsjeStr = getCellStringValue(row, 7); bankbillHistory.setCQsje(qsjeStr); // 手续费 String sxfStr = getCellStringValue(row, 8); bankbillHistory.setCSxf(sxfStr); // 参考号 String ckhStr = getCellStringValue(row, 9); bankbillHistory.setCCkh(ckhStr); // 流水号 String lshStr = getCellStringValue(row, 10); bankbillHistory.setCLsh(lshStr); // 卡类型 String klxStr = getCellStringValue(row, 11); bankbillHistory.setCKlx(klxStr); // 授权码 String sqmStr = getCellStringValue(row, 12); bankbillHistory.setCBzzd(sqmStr); // 使用备注字段存储授权码 // 分店名称 String fdmcStr = getCellStringValue(row, 13); bankbillHistory.setCFdjc(fdmcStr); // 设置支付方式 bankbillHistory.setCZffs("银联外卡支付"); // 设置表名 bankbillHistory.setBillTableName(bill_table_name); list.add(bankbillHistory); } responseMap.put("list", list); } else { System.out.println("执行失败,原因:路径" + ftp_path + "下无下载文件" + ftp_file_name); errCode = "999"; errMsg = "执行失败,原因:路径" + ftp_path + "下无下载文件" + ftp_file_name; } } catch (Exception e) { e.printStackTrace(); System.out.println("执行失败,原因:" + e.getMessage()); errCode = "999"; errMsg = "执行失败,原因:" + e.getMessage(); } finally { try { if (sheets != null) { sheets.close(); } } catch (Exception ie) { ie.printStackTrace(); } } responseMap.put("errCode", errCode); responseMap.put("errMsg", errMsg); return responseMap; } /** * @description: 获取微信支付对账数据 * @author thuang * @date 2021/9/22 13:57 * @version 1.0 */ @PostMapping("/getBankDataByWXAPI") @ResponseBody public HashMap getBankDataByWXAPI(@RequestBody HashMap map) { List list = new ArrayList<>(); log.info("开始获取微信账单"); HashMap responseMap = new HashMap<>(); String errCode = "0"; String errMsg = ""; try { String localPath = StringDUtil.changeNullToEmpty(map.get("LOCAL_PATH")); String mch_id = StringDUtil.changeNullToEmpty(map.get("MCH_ID")); String trade_date = StringDUtil.changeNullToEmpty(map.get("trade_date")); log.info("开始获取微信账单,参数: mch_id={}, trade_date={}", mch_id, trade_date); HashMap reqMap = new HashMap<>(); reqMap.put("grant_type", grant_type); reqMap.put("appid", appid); reqMap.put("secret", secret); String randomStr = RandomUtil.randomString(32); String signString = "appid=" + appid + "&bill_date=" + trade_date + "&bill_type=ALL&mch_id=" + mch_id + "&nonce_str=" + randomStr + "&key="+ key; String sign = SecureUtil.md5(signString).toUpperCase(); String reqXml = "\n" + " " + appid + "\n" + " " + trade_date + "\n" + " ALL\n" + " " + mch_id + "\n" + " " + randomStr + "\n" + " " + sign + "\n" + ""; // 获取access_token log.info("开始调用微信账单接口,参数: mch_id={}, trade_date={}", mch_id, trade_date); String body1 = HttpUtil.createPost("https://api.mch.weixin.qq.com/pay/downloadbill") .header("Content-Type", "text/xml") .timeout(30000) // 设置30秒超时 .body(reqXml) .execute() .body(); log.info("微信账单接口返回数据长度: {}", body1 != null ? body1.length() : 0); log.info("微信账单接口返回数据: {}", body1); // 检查微信接口返回状态 if (body1.contains("")) { log.info("账单正在生成中,请稍后重试"); errCode = "999"; errMsg = "微信账单正在生成中,请稍后重试"; responseMap.put("errCode", errCode); responseMap.put("errMsg", errMsg); return responseMap; } String[] split = body1.split("\n"); for (int i = 1; i < split.length - 2; i++) { String[] split1 = split[i].split(","); if (Arrays.toString(split1).equals("[]")) { break; } // 检查是否是账单正在生成状态 if (Arrays.toString(split1).contains("Bill Creating")) { log.info("账单正在生成中,跳过处理"); break; } BankbillHistory bankbillHistory = new BankbillHistory(); int flag = 0; // 解析CSV数据到BankbillHistory实体 for (int j = 0; j < split1.length; j++) { String value = split1[j].replaceAll("`", "").trim(); switch (j) { case 0: // 交易时间 if (value.contains(" ")) { String[] timeSplit = value.split(" "); bankbillHistory.setCQsrq(timeSplit[0]); // 清算日期 bankbillHistory.setCJyrq(timeSplit[0]); // 交易日期 bankbillHistory.setCJysj(timeSplit[1]); // 交易时间 } break; case 4: // 设备号 bankbillHistory.setCZdh(value); break; case 5: // 微信订单号 bankbillHistory.setCYsddh(value); break; case 6: // 商户订单号 bankbillHistory.setCShddh(value); break; case 7: // 用户标识 bankbillHistory.setCCard(value); break; case 8: // 交易类型 bankbillHistory.setCJylx(value); break; case 9: // 交易状态 if ("REFUND".equals(value)) { flag = -1; } break; case 10: // 付款银行 bankbillHistory.setCFkh(value); break; case 12: // 应结订单金额 bankbillHistory.setCQsje(value); break; case 24: // 订单金额 // 只有在非退款状态时才设置订单金额 if (flag >= 0) { bankbillHistory.setCJyje(value); } break; case 20: // 商品名称 bankbillHistory.setCBzzd(value); break; case 22: // 手续费 bankbillHistory.setCSxf(value); break; case 14: // 微信退款单号 bankbillHistory.setCThddh(value); break; case 15: // 商户退款单号 bankbillHistory.setCYjylsh(value); break; case 25: // 申请退款金额 if (!"0.00".equals(value) && !value.isEmpty()) { bankbillHistory.setCJyje("-" + value); } break; } } // 设置支付方式 bankbillHistory.setCZffs("微信支付"); // 设置表名 bankbillHistory.setBillTableName("微信支付账单"); list.add(bankbillHistory); } // // 获取access_token // String body = HttpUtil.createPost("https://api.weixin.qq.com/cgi-bin/stable_token").body(JSONUtil.toJsonStr(reqMap)).execute().body(); // // String access_token = JSONUtil.parseObj(body).getStr("access_token"); // // 获取医保账单下载地址 // // https://api.weixin.qq.com/payinsurance/billdownload?access_token=ACCESS_TOKEN // String signYBString = "appid=" + appid + "&bill_date=" + trade_date + "&bill_type=ALL&mch_id=" + mch_id + "&nonce_str=" + randomStr + "&key="+key; // log.info("微信账单签名:" + signYBString); // String signYB = SecureUtil.md5(signYBString).toUpperCase(); // String reqYbXml = "\n" + // " " + appid + "\n" + // " " + trade_date + "\n" + // " ALL\n" + // " " + mch_id + "\n" + // " " + randomStr + "\n" + // " " + signYB + "\n" + // ""; // String resBody = HttpUtil.createPost("https://api.weixin.qq.com/payinsurance/billdownload?access_token=" + access_token).header("Content-Type", "text/xml").body(reqYbXml).execute().body(); // log.info("微信账单下载返回结果:" + resBody); // Document document = XmlUtil.parseXml(resBody); // Element elementG = XmlUtil.getRootElement(document); // Element returnCode = XmlUtil.getElement(elementG, "return_code"); // // if (returnCode.getTextContent().equals("SUCCESS")) {// 响应成功 // // 下载文件 // Element downloadUrl = XmlUtil.getElement(elementG, "download_url"); // String dwUrl = downloadUrl.getTextContent(); // log.info("开始下载文件"); // HttpUtil.downloadFileFromUrl(dwUrl, localPath + File.separator + trade_date + ".csv"); // HttpUtil.downloadFileFromUrl(dwUrl, localPath + File.separator + trade_date + ".txt"); // // HttpUtil.downloadFileFromUrl(dwUrl, localPath); // log.info("下载文件成功"); // CsvReader reader = CsvUtil.getReader(); // try { // CsvData read = reader.read(FileUtil.file(localPath + File.separator + trade_date + ".csv")); // List rows = read.getRows(); // if (rows.size() > 1) { // for (int i = 1; i < rows.size(); i++) { // CsvRow row = rows.get(i); // BankbillHistory bankbillHistory = new BankbillHistory(); // String s = row.get(0).replaceAll("`", ""); // String[] s1 = s.split(" "); // log.info("s1 is :" + Arrays.toString(s1)); // bankbillHistory.setCJyrq(s1[0]); // bankbillHistory.setCQsrq(s1[0]); // bankbillHistory.setCJysj(s1[1]); // bankbillHistory.setCZdh(row.get(1).replaceAll("`", "")); // bankbillHistory.setCCkh(row.get(2).replaceAll("`", "")); // bankbillHistory.setCLsh(row.get(5).replaceAll("`", "")); // bankbillHistory.setCShddh(row.get(6).replaceAll("`", "")); // bankbillHistory.setCCard(row.get(7).replaceAll("`", "")); // bankbillHistory.setCYsddh(row.get(25).replaceAll("`", "")); // if (row.get(46).replaceAll("`", "").equals("0.00")) { // continue; // } // if (row.get(45).replaceAll("`", "").equals("REFUND")) { // bankbillHistory.setCJyje("-" + row.get(46).replaceAll("`", "")); // } else { // bankbillHistory.setCJyje(row.get(46).replaceAll("`", "")); // } // bankbillHistory.setBillTableName("微信支付账单"); // list.add(bankbillHistory); // } // } // responseMap.put("list", list); // } catch (IORuntimeException e) { // throw new RuntimeException(e); // } finally { // try { // reader.close(); // } catch (IOException e) { // throw new RuntimeException(e); // } // } // } if (list.size() > 0) { responseMap.put("list", list); } else { errCode = "999"; errMsg = "账单数据为空,或未获取到账单!"; } responseMap.put("errCode", errCode); responseMap.put("errMsg", errMsg); return responseMap; } catch (Exception e) { log.error("微信账单获取异常", e); errCode = "999"; errMsg = "微信账单获取异常: " + e.getMessage(); responseMap.put("errCode", errCode); responseMap.put("errMsg", errMsg); return responseMap; } } // public static void main(String[] args) { // // String a = "?交易时间,公众账号ID,商户号,特约商户号,设备号,微信订单号,商户订单号,用户标识,交易类型,交易状态,付款银行,货币种类,应结订单金额,代金券金额,微信退款单号,商户退款单号,退款金额,充值券退款金额,退款类型,退款状态,商品名称,商户数据包,手续费,费率,订单金额,申请退款金额,费率备注\n" + // "`2024-08-09 17:55:10,`wx83bc9715be856b14,`1648728329,`0,`,`4200002314202408091169938410,`JJ20240809175501,`o-ZxO47Otvo5Rsq7kN-4PHvZIOt8,`JSAPI,`SUCCESS,`ICBC_DEBIT,`CNY,`61.00,`0.00,`0,`0,`0.00,`0.00,`,`,`库尔勒市妇幼保健院-门诊付款,`{\\\"patid\\\":\\\"385606\\\"\\ \\\"sjh\\\":\\\"20240809yypt120016\\\"\\ \\\"ysje\\\":\\\"61.0000\\\"\\ \\\"zfje\\\":\\\"61.0000\\\"\\ \\\"zje\\\":\\\"61.0000\\\"},`0.00000,`0.00%,`61.00,`0.00,`\n" + // "`2024-08-09 19:09:18,`wx83bc9715be856b14,`1648728329,`0,`,`4200002314202408091169938410,`JJ20240809175501,`o-ZxO47Otvo5Rsq7kN-4PHvZIOt8,`JSAPI,`REFUND,`ICBC_DEBIT,`CNY,`0.00,`0.00,`50303000492024080988526514493,`C0_20240809yypt120016,`61.00,`0.00,`ORIGINAL,`SUCCESS,`库尔勒市妇幼保健院-门诊付款,`{\\\"patid\\\":\\\"385606\\\"\\ \\\"sjh\\\":\\\"20240809yypt120016\\\"\\ \\\"ysje\\\":\\\"61.0000\\\"\\ \\\"zfje\\\":\\\"61.0000\\\"\\ \\\"zje\\\":\\\"61.0000\\\"},`0.00000,`0.00%,`0.00,`61.00,`\n" + // "`2024-08-09 18:07:51,`wx83bc9715be856b14,`1648728329,`0,`,`4200002320202408095363202348,`JJ20240809180744,`o-ZxO47Otvo5Rsq7kN-4PHvZIOt8,`JSAPI,`SUCCESS,`ICBC_DEBIT,`CNY,`104.00,`0.00,`0,`0,`0.00,`0.00,`,`,`库尔勒市妇幼保健院-门诊付款,`{\\\"patid\\\":\\\"447719\\\"\\ \\\"sjh\\\":\\\"20240809yypt120017\\\"\\ \\\"ysje\\\":\\\"104.0000\\\"\\ \\\"zfje\\\":\\\"104.0000\\\"\\ \\\"zje\\\":\\\"104.0000\\\"},`0.00000,`0.00%,`104.00,`0.00,`\n" + // "`2024-08-09 19:07:39,`wx83bc9715be856b14,`1648728329,`0,`,`4200002320202408095363202348,`JJ20240809180744,`o-ZxO47Otvo5Rsq7kN-4PHvZIOt8,`JSAPI,`REFUND,`ICBC_DEBIT,`CNY,`0.00,`0.00,`50303500422024080937274513002,`C0_20240809yypt120017,`104.00,`0.00,`ORIGINAL,`SUCCESS,`库尔勒市妇幼保健院-门诊付款,`{\\\"patid\\\":\\\"447719\\\"\\ \\\"sjh\\\":\\\"20240809yypt120017\\\"\\ \\\"ysje\\\":\\\"104.0000\\\"\\ \\\"zfje\\\":\\\"104.0000\\\"\\ \\\"zje\\\":\\\"104.0000\\\"},`0.00000,`0.00%,`0.00,`104.00,`\n" + // "`2024-08-09 17:54:18,`wx83bc9715be856b14,`1648728329,`0,`,`4200002326202408099114331548,`JJ20240809175411,`o-ZxO47Otvo5Rsq7kN-4PHvZIOt8,`JSAPI,`SUCCESS,`ICBC_DEBIT,`CNY,`298.38,`0.00,`0,`0,`0.00,`0.00,`,`,`库尔勒市妇幼保健院-门诊付款,`{\\\"patid\\\":\\\"447719\\\"\\ \\\"sjh\\\":\\\"20240809yypt120015\\\"\\ \\\"ysje\\\":\\\"298.3800\\\"\\ \\\"zfje\\\":\\\"298.3800\\\"\\ \\\"zje\\\":\\\"298.3800\\\"},`0.00000,`0.00%,`298.38,`0.00,`\n" + // "`2024-08-09 19:47:02,`wx83bc9715be856b14,`1648728329,`0,`,`4200002326202408099114331548,`JJ20240809175411,`o-ZxO47Otvo5Rsq7kN-4PHvZIOt8,`JSAPI,`REFUND,`ICBC_DEBIT,`CNY,`0.00,`0.00,`50303500342024080940745293001,`C0_20240809yypt120015,`298.38,`0.00,`ORIGINAL,`SUCCESS,`库尔勒市妇幼保健院-门诊付款,`{\\\"patid\\\":\\\"447719\\\"\\ \\\"sjh\\\":\\\"20240809yypt120015\\\"\\ \\\"ysje\\\":\\\"298.3800\\\"\\ \\\"zfje\\\":\\\"298.3800\\\"\\ \\\"zje\\\":\\\"298.3800\\\"},`0.00000,`0.00%,`0.00,`298.38,`\n" + // "总交易单数,应结订单总金额,退款总金额,充值券退款总金额,手续费总金额,订单总金额,申请退款总金额\n" + // "`6,`463.38,`463.38,`0.00,`0.00000,`463.38,`463.38"; // String[] split = a.split("\n"); // for (int i = 1; i < split.length - 2; i++) { // String[] split1 = split[i].split(","); // for (int j = 0; j < split1.length; j++) { // // System.out.println("=============="); // System.out.println("第" + j + "个:"); // System.out.println(split1[j]); // System.out.println("=============="); // if (j == 21) { // String s = split1[j].replaceAll("`", ""); // String s1 = s.replaceAll(" ", ",").replaceAll("\\\\", ""); // JSONObject entries = JSONUtil.parseObj(s1); // Object zfje = entries.get("zfje"); // // System.out.println(zfje.toString().substring(0, 5)); // // } // } // } // System.out.println(); // } /** * 发送对账结果微信消息推送 * @param tradeDate 对账时间 * @param operationResult 操作结果 * @param reconcileResult 对账结果 * @param operatorName 操作人 * @param openid 用户openid * @return 推送结果 */ public int SendNotifyYJJ(String tradeDate, String operationResult, String reconcileResult, String operatorName, String openid) { try { //第一步 获取token String accessUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&" + "&appid=" + WX_APP_ID + "&secret=" + WX_SECRET; String accessTokenStr = HttpClientUtil.doGet(accessUrl, null); log.info("step 1 get accesstoken:" + accessTokenStr); if (accessTokenStr == null || accessTokenStr.isEmpty()) { log.error("获取微信access_token失败,响应为空"); return -1; } JSONObject jsonObject = JSON.parseObject(accessTokenStr); if (jsonObject == null) { log.error("解析微信access_token响应失败,无法解析JSON"); return -1; } Object accessTokenObj = jsonObject.get("access_token"); if (accessTokenObj == null) { log.error("微信access_token响应中没有access_token字段,响应内容: {}", accessTokenStr); return -1; } String accessToken = accessTokenObj.toString(); String sendUrl = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + accessToken; JSONObject sendPara = new JSONObject(); JSONObject dataPara = new JSONObject(); // 对账时间 JSONObject time2 = new JSONObject(); time2.put("value", tradeDate); time2.put("color", "#173177"); // 操作结果 JSONObject const3 = new JSONObject(); const3.put("value", operationResult); const3.put("color", "#173177"); // 对账结果 JSONObject const4 = new JSONObject(); const4.put("value", reconcileResult); const4.put("color", "#173177"); // 操作人和时间 JSONObject character_string5 = new JSONObject(); character_string5.put("value", operatorName + " " + DateDUtil.DateToStr(DateDUtil.yyyy_MM_dd_HH_mm_ss, new Date())); character_string5.put("color", "#173177"); dataPara.put("time2", time2); dataPara.put("const3", const3); dataPara.put("const4", const4); dataPara.put("character_string5", character_string5); sendPara.put("touser", openid); sendPara.put("template_id", "sbzMHunU1zmB_Hg4LRAs7BSmYPw6CtxFuBHMXllxZB0"); sendPara.put("url", "https://nxwj.btlsoln.com/nxwj-gzh/#/reconciliation"); sendPara.put("data", dataPara); String sendRes = HttpClientUtil.doPost(sendUrl, sendPara); log.info("step 2 send notify:" + sendRes); if (sendRes == null || sendRes.isEmpty()) { log.error("发送微信消息失败,响应为空"); return -1; } JSONObject jsonSend = JSON.parseObject(sendRes); if (jsonSend != null && jsonSend.containsKey("errcode")) { Integer errcode = jsonSend.getInteger("errcode"); String errmsg = jsonSend.getString("errmsg"); if (errcode != null && errcode == 0) { log.info("微信消息发送成功"); return 0; } else { // 根据不同错误码提供具体的错误信息 switch (errcode) { case 43004: log.error("微信消息发送失败:用户未关注公众号,无法接收模板消息。errcode: {}, errmsg: {}", errcode, errmsg); return -2; // 特殊返回码表示用户未关注 case 40001: log.error("微信消息发送失败:access_token无效。errcode: {}, errmsg: {}", errcode, errmsg); return -3; case 40003: log.error("微信消息发送失败:openid无效。errcode: {}, errmsg: {}", errcode, errmsg); return -4; case 41030: log.error("微信消息发送失败:页面不存在或者小程序没有关联公众号。errcode: {}, errmsg: {}", errcode, errmsg); return -5; default: log.error("微信消息发送失败,errcode: {}, errmsg: {}", errcode, errmsg); return -1; } } } return 0; } catch (Exception e) { log.error("发送微信消息异常", e); return -1; } } /** * 测试对账结果微信消息推送接口 * @param map 包含对账信息和openid的参数 * @return 推送结果 */ @PostMapping("/sendNotifyYJJ") @ResponseBody public HashMap sendNotifyYJJ(@RequestBody HashMap map) { HashMap responseMap = new HashMap<>(); String errCode = "0"; String errMsg = ""; try { // 从请求参数中获取数据 String tradeDate = StringDUtil.changeNullToEmpty(map.get("tradeDate")); String operationResult = StringDUtil.changeNullToEmpty(map.get("operationResult")); String reconcileResult = StringDUtil.changeNullToEmpty(map.get("reconcileResult")); String operatorName = StringDUtil.changeNullToEmpty(map.get("operatorName")); String openid = StringDUtil.changeNullToEmpty(map.get("openid")); // 参数校验 if (tradeDate.isEmpty()) { errCode = "1"; errMsg = "对账时间不能为空"; responseMap.put("errCode", errCode); responseMap.put("errMsg", errMsg); return responseMap; } if (openid.isEmpty()) { errCode = "1"; errMsg = "openid不能为空"; responseMap.put("errCode", errCode); responseMap.put("errMsg", errMsg); return responseMap; } // 设置默认值 if (operationResult.isEmpty()) { operationResult = "操作完成!"; } if (reconcileResult.isEmpty()) { reconcileResult = "对账完成!"; } if (operatorName.isEmpty()) { operatorName = "系统"; } // 调用推送方法 int result = SendNotifyYJJ(tradeDate, operationResult, reconcileResult, operatorName, openid); if (result == 0) { errMsg = "对账结果消息推送成功"; } else { errCode = "1"; // 根据返回码提供具体的错误信息 switch (result) { case -2: errMsg = "消息推送失败:用户未关注公众号,无法接收模板消息"; break; case -3: errMsg = "消息推送失败:微信access_token无效"; break; case -4: errMsg = "消息推送失败:用户openid无效"; break; case -5: errMsg = "消息推送失败:页面不存在或小程序未关联公众号"; break; default: errMsg = "对账结果消息推送失败"; break; } } } catch (Exception e) { log.error("微信消息推送异常", e); errCode = "999"; errMsg = "微信消息推送异常: " + e.getMessage(); } responseMap.put("errCode", errCode); responseMap.put("errMsg", errMsg); return responseMap; } /** * 检查用户是否关注公众号 * @param openid 用户openid * @return true-已关注,false-未关注 */ public boolean checkUserSubscribe(String openid) { try { // 获取access_token String accessUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&" + "&appid=" + WX_APP_ID + "&secret=" + WX_SECRET; String accessTokenStr = HttpClientUtil.doGet(accessUrl, null); if (accessTokenStr == null || accessTokenStr.isEmpty()) { log.error("获取access_token失败"); return false; } JSONObject tokenJson = JSON.parseObject(accessTokenStr); Object accessTokenObj = tokenJson.get("access_token"); if (accessTokenObj == null) { log.error("access_token响应中没有access_token字段"); return false; } String accessToken = accessTokenObj.toString(); // 获取用户信息 String userInfoUrl = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + accessToken + "&openid=" + openid; String userInfoResponse = HttpClientUtil.doGet(userInfoUrl, null); log.info("用户信息响应: {}", userInfoResponse); if (userInfoResponse != null && !userInfoResponse.isEmpty()) { JSONObject userInfo = JSON.parseObject(userInfoResponse); if (userInfo.containsKey("subscribe")) { Integer subscribe = userInfo.getInteger("subscribe"); return subscribe != null && subscribe == 1; } } } catch (Exception e) { log.error("检查用户关注状态异常", e); } return false; } /** * 根据验证码和手机号获取openid * @param yz 验证码 * @param phone 手机号 * @return openid,如果获取失败返回null */ public String getUserOpenIdByPhone(String yz, String phone) { try { String url = "http://172.16.21.21:8443/nxgzh/userInfo/getUserOpenIdByPhone?yz=" + yz + "&phone=" + phone; String response = HttpClientUtil.doPost(url, null); log.info("获取openid请求URL: {}", url); log.info("获取openid响应: {}", response); if (response != null && !response.isEmpty()) { JSONObject jsonResponse = JSON.parseObject(response); log.info("解析后的JSON对象: {}", jsonResponse); // 返回格式为 {"code": 200, "message": "执行成功", "refreshToken": null, "data": "o4MF86KDH-v1Rh5ryVj4TAeLs2JY"} // 检查code是否为200 Integer code = jsonResponse.getInteger("code"); log.info("响应code: {}", code); if (code != null && code == 200) { // data字段直接是openid字符串 if (jsonResponse.containsKey("data")) { String openid = jsonResponse.getString("data"); log.info("获取到的openid: {}", openid); if (openid != null && !openid.isEmpty() && !"null".equals(openid)) { log.info("成功获取openid,手机号: {}, openid: {}", phone, openid); return openid; } else { log.warn("openid为空或null,手机号: {}, data值: {}", phone, openid); } } else { log.warn("响应中不包含data字段,手机号: {}", phone); } } else { String message = jsonResponse.getString("message"); log.warn("获取openid失败,手机号: {}, code: {}, 返回信息: {}", phone, code, message); } } else { log.warn("响应为空,手机号: {}", phone); } } catch (Exception e) { log.error("获取openid失败,验证码: {}, 手机号: {}, 错误: {}", yz, phone, e.getMessage(), e); } return null; } /** * 获取用户openid的REST接口 * @param map 包含yz和phone参数的请求体 * @return 包含openid的响应结果 */ @PostMapping("/getUserOpenId") @ResponseBody public HashMap getUserOpenId(@RequestBody HashMap map) { HashMap responseMap = new HashMap<>(); String errCode = "0"; String errMsg = ""; try { // 从请求参数中获取验证码和手机号 String yz = StringDUtil.changeNullToEmpty(map.get("yz")); String phone = StringDUtil.changeNullToEmpty(map.get("phone")); log.info("请求获取openid,yz: {}, phone: {}", yz, phone); if (yz.isEmpty()) { errCode = "1"; errMsg = "验证码不能为空"; responseMap.put("errCode", errCode); responseMap.put("errMsg", errMsg); return responseMap; } if (phone.isEmpty()) { errCode = "1"; errMsg = "手机号不能为空"; responseMap.put("errCode", errCode); responseMap.put("errMsg", errMsg); return responseMap; } // 调用获取openid的方法 String openid = getUserOpenIdByPhone(yz, phone); if (openid != null && !openid.isEmpty()) { responseMap.put("openid", openid); errMsg = "获取openid成功"; } else { errCode = "1"; errMsg = "获取openid失败,验证码或手机号错误或网络异常"; } } catch (Exception e) { log.error("获取openid异常", e); errCode = "999"; errMsg = "获取openid异常: " + e.getMessage(); } responseMap.put("errCode", errCode); responseMap.put("errMsg", errMsg); return responseMap; } /** * 下载ZIP文件接口 * 调用远程服务下载文件并将字节流返回给客户端 * @param fileName 文件名(通过路径参数传递) * @return 文件字节流 */ @GetMapping("/download/{fileName}") public ResponseEntity downloadFile(@PathVariable String fileName) { CloseableHttpClient httpClient = null; CloseableHttpResponse response = null; try { log.info("开始调用远程下载接口,文件名: {}", fileName); // 构建远程下载URL String remoteUrl = "http://172.16.21.21:8443/nxgzh/find/download/" + fileName; log.info("远程下载URL: {}", remoteUrl); // 创建HTTP客户端 httpClient = HttpClients.createDefault(); HttpGet httpGet = new HttpGet(remoteUrl); // 执行请求 response = httpClient.execute(httpGet); int statusCode = response.getStatusLine().getStatusCode(); log.info("远程接口响应状态码: {}", statusCode); if (statusCode == 200) { // 获取响应的输入流 InputStream inputStream = response.getEntity().getContent(); InputStreamResource resource = new InputStreamResource(inputStream); // 获取文件大小 long contentLength = response.getEntity().getContentLength(); // 构造响应头 HttpHeaders headers = new HttpHeaders(); headers.add("Content-Disposition", "attachment; filename=\"" + fileName + "\""); headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); if (contentLength > 0) { headers.setContentLength(contentLength); } log.info("文件下载成功,文件名: {}, 大小: {} bytes", fileName, contentLength); return ResponseEntity.ok() .headers(headers) .body(resource); } else if (statusCode == 404) { log.error("远程文件不存在: {}", fileName); return ResponseEntity.status(HttpStatus.NOT_FOUND) .header("X-Error", "File not found: " + fileName) .body(null); } else { log.error("远程接口返回错误状态码: {}", statusCode); return ResponseEntity.status(statusCode) .header("X-Error", "Remote server error: " + statusCode) .body(null); } } catch (Exception e) { log.error("下载文件异常,文件名: {}, 错误: {}", fileName, e.getMessage(), e); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .header("X-Error", "Download failed: " + e.getMessage()) .body(null); } finally { // 注意:不要关闭response和httpClient,因为流还在被读取 // Spring会在响应完成后自动处理资源清理 } } @PostMapping("/getBankDataByMedicalInsuranceAPI") @ResponseBody public HashMap getBankDataByMedicalInsuranceAPI(@RequestBody HashMap map) { List list = new ArrayList<>(); log.info("开始获取微信医保账单"); HashMap responseMap = new HashMap<>(); String errCode = "0"; String errMsg = ""; try { String localPath = StringDUtil.changeNullToEmpty(map.get("LOCAL_PATH")); String mch_id = StringDUtil.changeNullToEmpty(map.get("MCH_ID")); String trade_date = StringDUtil.changeNullToEmpty(map.get("trade_date")); log.info("开始获取微信账单,参数: mch_id={}, trade_date={}", mch_id, trade_date); HashMap reqMap = new HashMap<>(); reqMap.put("grant_type", grant_type); reqMap.put("appid", appid); reqMap.put("secret", secret); String randomStr = RandomUtil.randomString(32); // String signString = "appid=" + appid + "&bill_date=" + trade_date + "&bill_type=ALL&mch_id=" + mch_id + "&nonce_str=" + randomStr + "&key="+ key; // String sign = SecureUtil.md5(signString).toUpperCase(); // String reqXml = "\n" + // " " + appid + "\n" + // " " + trade_date + "\n" + // " ALL\n" + // " " + mch_id + "\n" + // " " + randomStr + "\n" + // " " + sign + "\n" + // ""; // // 获取access_token // log.info("开始调用微信账单接口,参数: mch_id={}, trade_date={}", mch_id, trade_date); // String body1 = HttpUtil.createPost("https://api.mch.weixin.qq.com/pay/downloadbill") // .header("Content-Type", "text/xml") // .timeout(30000) // 设置30秒超时 // .body(reqXml) // .execute() // .body(); // log.info("微信账单接口返回数据长度: {}", body1 != null ? body1.length() : 0); // log.info("微信账单接口返回数据: {}", body1); // // // 检查微信接口返回状态 // // if (body1.contains("")) { // log.info("账单正在生成中,请稍后重试"); // errCode = "999"; // errMsg = "微信账单正在生成中,请稍后重试"; // responseMap.put("errCode", errCode); // responseMap.put("errMsg", errMsg); // return responseMap; // } // // // 检查是否无账单数据 // if (body1.contains("")) { // log.info("该日期无账单数据"); // errCode = "999"; // errMsg = "该日期无账单数据"; // responseMap.put("errCode", errCode); // responseMap.put("errMsg", errMsg); // return responseMap; // } // // String[] split = body1.split("\n"); // for (int i = 1; i < split.length - 2; i++) { // String[] split1 = split[i].split(","); // if (Arrays.toString(split1).equals("[]")) { // break; // } // // 检查是否是账单正在生成状态 // if (Arrays.toString(split1).contains("Bill Creating")) { // log.info("账单正在生成中,跳过处理"); // break; // } // // BankbillHistory bankbillHistory = new BankbillHistory(); // int flag = 0; // // // 解析CSV数据到BankbillHistory实体 // for (int j = 0; j < split1.length; j++) { // String value = split1[j].replaceAll("`", "").trim(); // // switch (j) { // case 0: // 交易时间 // if (value.contains(" ")) { // String[] timeSplit = value.split(" "); // bankbillHistory.setCQsrq(timeSplit[0]); // 清算日期 // bankbillHistory.setCJyrq(timeSplit[0]); // 交易日期 // bankbillHistory.setCJysj(timeSplit[1]); // 交易时间 // } // break; // case 4: // 设备号 // bankbillHistory.setCZdh(value); // break; // case 5: // 微信订单号 // bankbillHistory.setCYsddh(value); // break; // case 6: // 商户订单号 // bankbillHistory.setCShddh(value); // break; // case 7: // 用户标识 // bankbillHistory.setCCard(value); // break; // case 8: // 交易类型 // bankbillHistory.setCJylx(value); // break; // case 9: // 交易状态 // if ("REFUND".equals(value)) { // flag = -1; // } // break; // case 10: // 付款银行 // bankbillHistory.setCFkh(value); // break; // case 12: // 应结订单金额 // bankbillHistory.setCQsje(value); // break; // case 24: // 订单金额 // // 只有在非退款状态时才设置订单金额 // if (flag >= 0) { // bankbillHistory.setCJyje(value); // } // break; // case 20: // 商品名称 // bankbillHistory.setCBzzd(value); // break; // case 22: // 手续费 // bankbillHistory.setCSxf(value); // break; // case 14: // 微信退款单号 // bankbillHistory.setCThddh(value); // break; // case 15: // 商户退款单号 // bankbillHistory.setCYjylsh(value); // break; // case 25: // 申请退款金额 // if (!"0.00".equals(value) && !value.isEmpty()) { // bankbillHistory.setCJyje("-" + value); // } // break; // } // } // // // 设置支付方式 // bankbillHistory.setCZffs("微信支付"); // // // 设置表名 // bankbillHistory.setBillTableName("微信支付账单"); // // list.add(bankbillHistory); // } // 获取access_token String body = HttpUtil.createPost("https://api.weixin.qq.com/cgi-bin/stable_token").body(JSONUtil.toJsonStr(reqMap)).execute().body(); String access_token = JSONUtil.parseObj(body).getStr("access_token"); // 获取医保账单下载地址 // https://api.weixin.qq.com/payinsurance/billdownload?access_token=ACCESS_TOKEN String signYBString = "appid=" + appid + "&bill_date=" + trade_date + "&bill_type=ALL&mch_id=" + mch_id + "&nonce_str=" + randomStr + "&key="+key_yb; log.info("微信账单签名:" + signYBString); String signYB = SecureUtil.md5(signYBString).toUpperCase(); log.info("微信账单签名结果:" + signYB); String reqYbXml = "\n" + " " + appid + "\n" + " " + trade_date + "\n" + " ALL\n" + " " + mch_id + "\n" + " " + randomStr + "\n" + " " + signYB + "\n" + ""; log.info("微信账单请求参数:" + reqYbXml); String resBody = HttpUtil.createPost("https://api.weixin.qq.com/payinsurance/billdownload?access_token=" + access_token).header("Content-Type", "text/xml").body(reqYbXml).execute().body(); log.info("微信账单下载返回结果:" + resBody); Document document = XmlUtil.parseXml(resBody); Element elementG = XmlUtil.getRootElement(document); Element returnCode = XmlUtil.getElement(elementG, "return_code"); if (returnCode.getTextContent().equals("SUCCESS")) {// 响应成功 // 下载文件 Element downloadUrl = XmlUtil.getElement(elementG, "download_url"); String dwUrl = downloadUrl.getTextContent(); log.info("开始下载文件"); HttpUtil.downloadFileFromUrl(dwUrl, localPath + File.separator + trade_date + ".csv"); HttpUtil.downloadFileFromUrl(dwUrl, localPath + File.separator + trade_date + ".txt"); // HttpUtil.downloadFileFromUrl(dwUrl, localPath); log.info("下载文件成功"); CsvReader reader = CsvUtil.getReader(); try { CsvData read = reader.read(FileUtil.file(localPath + File.separator + trade_date + ".csv")); List rows = read.getRows(); if (rows.size() > 1) { for (int i = 1; i < rows.size(); i++) { CsvRow row = rows.get(i); BankbillHistory bankbillHistory = new BankbillHistory(); String s = row.get(0).replaceAll("`", ""); String[] s1 = s.split(" "); log.info("s1 is :" + Arrays.toString(s1)); bankbillHistory.setCJyrq(s1[0]); bankbillHistory.setCQsrq(s1[0]); bankbillHistory.setCJysj(s1[1]); bankbillHistory.setCZdh(row.get(1).replaceAll("`", "")); bankbillHistory.setCCkh(row.get(2).replaceAll("`", "")); bankbillHistory.setCLsh(row.get(5).replaceAll("`", "")); bankbillHistory.setCShddh(row.get(25).replaceAll("`", "")); bankbillHistory.setCCard(row.get(7).replaceAll("`", "")); bankbillHistory.setCYsddh(row.get(6).replaceAll("`", "")); // 处理交易金额,不跳过0.00的记录 String amount = row.get(46).replaceAll("`", ""); if (row.get(45).replaceAll("`", "").equals("REFUND")) { // 退款记录,金额为负数 if (!"0.00".equals(amount) && !amount.isEmpty()) { bankbillHistory.setCJyje("-" + amount); } else { bankbillHistory.setCJyje("0.00"); } } else { // 普通交易记录 bankbillHistory.setCJyje(amount); } // 医保账户金额(医保个账金额,第53列,索引52) if (row.size() > 52) { String acctPay = row.get(52).replaceAll("`", ""); bankbillHistory.setAcctPay(acctPay); } // 医保统筹金额(第54列,索引53) if (row.size() > 53) { String fundPaySumamt = row.get(53).replaceAll("`", ""); bankbillHistory.setFundPaySumamt(fundPaySumamt); } // 医疗总费用(订单总金额,第49列,索引48) if (row.size() > 48) { String medfeeSumamt = row.get(48).replaceAll("`", ""); bankbillHistory.setMedfeeSumamt(medfeeSumamt); } bankbillHistory.setBillTableName("微信医保账单"); list.add(bankbillHistory); // 打印第一条记录的完整实体类信息 if (i == 1) { log.info("========== 微信账单解析实体类示例 =========="); log.info("实体类完整信息(JSON格式):"); log.info(JSONUtil.toJsonStr(bankbillHistory)); log.info(""); log.info("实体类字段详情:"); log.info(" 交易日期(cJyrq): {}", bankbillHistory.getCJyrq()); log.info(" 清算日期(cQsrq): {}", bankbillHistory.getCQsrq()); log.info(" 交易时间(cJysj): {}", bankbillHistory.getCJysj()); log.info(" 终端号(cZdh): {}", bankbillHistory.getCZdh()); log.info(" 参考号(cCkh): {}", bankbillHistory.getCCkh()); log.info(" 流水号(cLsh): {}", bankbillHistory.getCLsh()); log.info(" 商户订单号(cShddh): {}", bankbillHistory.getCShddh()); log.info(" 用户标识(cCard): {}", bankbillHistory.getCCard()); log.info(" 微信订单号(cYsddh): {}", bankbillHistory.getCYsddh()); log.info(" 交易金额(cJyje): {}", bankbillHistory.getCJyje()); log.info(" 医疗总费用(medfeeSumamt): {}", bankbillHistory.getMedfeeSumamt()); log.info(" 医保账户金额(acctPay): {}", bankbillHistory.getAcctPay()); log.info(" 医保统筹金额(fundPaySumamt): {}", bankbillHistory.getFundPaySumamt()); log.info(" 表名(billTableName): {}", bankbillHistory.getBillTableName()); log.info("=========================================="); } } } responseMap.put("list", list); } catch (IORuntimeException e) { throw new RuntimeException(e); } finally { try { reader.close(); } catch (IOException e) { throw new RuntimeException(e); } } } if (list.size() > 0) { log.info("集合大小为"+ list.size()); responseMap.put("list", list); } else { errCode = "999"; errMsg = "账单数据为空,或未获取到账单!"; } responseMap.put("errCode", errCode); responseMap.put("errMsg", errMsg); return responseMap; } catch (Exception e) { log.error("微信账单获取异常", e); errCode = "999"; errMsg = "微信账单获取异常: " + e.getMessage(); responseMap.put("errCode", errCode); responseMap.put("errMsg", errMsg); return responseMap; } } }