java.math.BigDecimal小缺陷

本文探讨了java.math.BigDecimal在执行除法操作时遇到无限循环小数情况下的异常处理机制。当使用BigDecimal进行如10除以3这类无法得到精确有限小数结果的运算时,会触发ArithmeticException。文章解释了此现象的原因,并提供了相应的解决思路。
java.math.BigDecimal可以表示任意精度的有限位数值,可是表示不了无限循环小数。
当运算
new java.math.BigDecimal("10").divide(new java.math.BigDecimal("3"))
就会抛出ArithmeticException("Non-terminating decimal expansion; no exact representable decimal result.")
package com.htsc.service; import com.alibaba.dubbo.common.utils.CollectionUtils; import com.htsc.commons.SystemUtil; import com.htsc.jpa.po.FileStore; import com.htsc.jpa.po.LiquidReportChart; import com.htsc.jpa.po.ReportStatusManage; import com.htsc.jpa.repository.*; import com.htsc.view.vo.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.stream.Collectors; /** * @Author K0171746 * @Date 2025/10/22 14:35 */ @Service public class DebtBusinessDayReportService { private static final Logger logger = LoggerFactory.getLogger(DebtBusinessDayReportService.class); // 日报名称 public static String debtBusinessDayReport = "AssetDebtDailyReport"; // 部门列表 private static final String[] departments = {"母公司汇总", "证券投资部", "中央交易室", "金融创新部", "销售交易部", "固定收益部", "报价融资部", "资金运营部", "融资融券部" }; /** * 部门业务映射关系 * @author K0171746 */ private static final Map<String, List<String>> DEPT_TO_BUSINESS_MAPPING = new HashMap<>(); static { DEPT_TO_BUSINESS_MAPPING.put("母公司汇总", Arrays.asList("证券投资部", "金融创新部", "固定收益部")); DEPT_TO_BUSINESS_MAPPING.put("证券投资部", Arrays.asList("创新业务", "大数据业务", "宏观对冲")); DEPT_TO_BUSINESS_MAPPING.put("中央交易室", Arrays.asList("北交所股票做市业务", "科创板股票做市业务", "基金做市业务")); DEPT_TO_BUSINESS_MAPPING.put("金融创新部", Arrays.asList("场外衍生品业务", "期权做市业务", "场内自营业务")); DEPT_TO_BUSINESS_MAPPING.put("销售交易部", Arrays.asList("场外衍生品", "资产合计", "衍生品合计")); DEPT_TO_BUSINESS_MAPPING.put("固定收益部", Arrays.asList("传统固收业务", "固收衍生品业务", "债券销售交易业务")); DEPT_TO_BUSINESS_MAPPING.put("报价融资部", Arrays.asList("资产合计", "负债合计")); DEPT_TO_BUSINESS_MAPPING.put("资金运营部", Arrays.asList("资金部委托固收投资", "流动性储备", "资产合计")); DEPT_TO_BUSINESS_MAPPING.put("融资融券部", Arrays.asList("两融部融券券源", "场外衍生品业务", "券源业务")); } @Autowired private JdbcTemplate jdbcTemplate; @Autowired private LiquidReportChartRepository liquidReportChartRepository; @Autowired private ReportStatusRepository reportStatusRepository; @Autowired private MultiClientRepository multiClientRepository; @Autowired private WorkDayService workDayService; // 生成日报 public void generateReport(String dateDt) { int i = this.queryCount(dateDt); if(i==0){ logger.info("#############{}没有数据,不生成报告", dateDt); } else { liquidReportChartRepository.deleteLiquidReportChartByDataDtAndReportCode(dateDt, debtBusinessDayReport); List<DebtBusinessDayReportWholeAssetVO> wholeVO = this.queryAsset(dateDt); this.generateChart1(wholeVO,dateDt); this.generateChart2(wholeVO,dateDt); this.generateParent(wholeVO,dateDt); this.generateDpAsset(wholeVO,dateDt); reportStatusRepository.deleteByReportConfirmDateAndReportName(SystemUtil.strToDate(dateDt), "资产负债业务日报"); ReportStatusManage reportStatusManage = new ReportStatusManage(); reportStatusManage.setReportStatus("Y"); reportStatusManage.setReportName("资产负债业务日报"); reportStatusManage.setReportConfirmDate(SystemUtil.strToDate(dateDt)); reportStatusRepository.save(reportStatusManage); } } /** * 查询指定日期范围内的资产数据 * @author K0171746 */ private List<DebtBusinessDayReportWholeAssetVO> queryAsset (String dateDt) { // 获取今年第一天 String bgnDt = workDayService.findYearFirstNaturalDay(dateDt); // 获取去年最后一个工作日 // String lastYearFinalWorkDay = workDayService.findLastYearFinalWorkDayStr(dateDt); String lastYearFinalWorkDay = "20250613"; // 获取两个日期之间的交易日 List<String> bgnDts = workDayService.findTransDts(bgnDt, dateDt); String firstWorkDay = bgnDts.get(0); if (Integer.parseInt(firstWorkDay) < 20250613){ firstWorkDay = "20250613"; } StringBuffer sql = new StringBuffer(); sql.append("SELECT a.DEPT," + "a.BUSI_BIGC_NAME," + "a.BUSI_SMLC_NAME," + "a.PAL," + "a.PAL_MON," + "a.PAL_YEAR," + "a.COMPARE_YEAR," + "a.PROJ_TYPE," + "a.AMT," + "a.COMPARE_DAY," + "a.COMPARE_MON, " + "a.AMT - b.AMT as COMPARE_BEGIN_YEAR, " + "c.PAL_YEAR as compareLastYearWorkDay from T_LIQUID_BURDEN_DEPT a left join T_LIQUID_BURDEN_DEPT b on a.DEPT = b.DEPT" + " AND a.LIQ_BIG_CLAS = b.LIQ_BIG_CLAS" + " AND a.BUSI_BIGC_NAME = b.BUSI_BIGC_NAME" + " AND a.BUSI_SMLC_NAME = b.BUSI_SMLC_NAME" + " AND a.STRA = b.STRA" + " AND a.PROJ_TYPE = b.PROJ_TYPE " + " AND a.BS = b.BS AND a.REMARK = B.REMARK" + " AND b.DATA_DT = '"+firstWorkDay+"' left join T_LIQUID_BURDEN_DEPT c on a.DEPT = c.DEPT" + " AND a.BUSI_BIGC_NAME = c.BUSI_BIGC_NAME" + " AND a.BUSI_SMLC_NAME = c.BUSI_SMLC_NAME" + " AND a.STRA = c.STRA" + " AND a.PROJ_TYPE = c.PROJ_TYPE " + " AND a.BS = c.BS AND a.REMARK = c.REMARK" + " and c.DATA_DT = '" + lastYearFinalWorkDay + "' where a.DATA_DT = '"+ dateDt +"'"); return jdbcTemplate.query(sql.toString(),new BeanPropertyRowMapper(DebtBusinessDayReportWholeAssetVO.class)); } /** * @Description 生成损益折线图 * @author K0171746 */ private void generateChart1(List<DebtBusinessDayReportWholeAssetVO> wholeVO,String dateDt){ // 查询资负表,获取全部数据 List<LiquidReportChart> chartList = new ArrayList<>(); int rowNum = 1; for (String dept : departments) { List<String> bizTypes = DEPT_TO_BUSINESS_MAPPING.get(dept); if (bizTypes == null || bizTypes.isEmpty()) { logger.warn("部门 {} 没有关联的业务类型", dept); continue; } // 截取前3个业务类型(如果少于3个,放入bizTypes) List<String> top3BizTypes = bizTypes.size() <= 3 ? new ArrayList<>(bizTypes) : bizTypes.subList(0, 3); Map<String, BigDecimal> result = CalculateChart1(wholeVO, dept, top3BizTypes); // 今年总计 LiquidReportChart chartYear = new LiquidReportChart(); chartYear.setDataDt(dateDt); chartYear.setReportCode(debtBusinessDayReport); chartYear.setChartId("chart0010"); chartYear.setRowNum(rowNum++); chartYear.setCellValue1("部门合计(今年)"); chartYear.setCellValue2(result.getOrDefault("部门合计(今年)",BigDecimal.ZERO).toString()); // 业务值 chartYear.setCellValue3("部门合计(去年)"); chartYear.setCellValue4(result.getOrDefault("部门合计(去年)",BigDecimal.ZERO).toString()); chartYear.setCellValue5(top3BizTypes.get(0)); chartYear.setCellValue6(result.getOrDefault(top3BizTypes.get(0), BigDecimal.ZERO).toString()); chartYear.setCellValue7(top3BizTypes.get(1)); chartYear.setCellValue8(result.getOrDefault(top3BizTypes.get(1), BigDecimal.ZERO).toString()); if (top3BizTypes.size() >= 3) { chartYear.setCellValue9(top3BizTypes.get(2)); chartYear.setCellValue10(result.getOrDefault(top3BizTypes.get(2), BigDecimal.ZERO).toString()); } chartYear.setChartName(dept); chartList.add(chartYear); } if (!chartList.isEmpty()) { liquidReportChartRepository.save(chartList); logger.info("成功将 {} 条 chart1 ({}) 数据落库", chartList.size(), "chart0010"); } else { logger.warn("没有有效数据生成 chart1"); } } /** * @Description 计算损益折线图数据 * @author K0171746 */ private Map<String,BigDecimal> CalculateChart1(List<DebtBusinessDayReportWholeAssetVO> wholeVO, String department, List<String> bizTypes) { BigDecimal totalYear = BigDecimal.ZERO; BigDecimal totalLastYear = BigDecimal.ZERO; Map<String, BigDecimal> bizMap = new HashMap<>(); for (String biz : bizTypes) { bizMap.put(biz, BigDecimal.ZERO); } for (DebtBusinessDayReportWholeAssetVO vo : wholeVO) { if (!department.equals(vo.getDept())) continue; if (vo.getProjType() != null && vo.getProjType().contains("合计")) continue; totalYear = totalYear.add(Optional.ofNullable(vo.getPalYear()).orElse(BigDecimal.ZERO)); totalLastYear = totalLastYear.add(Optional.ofNullable(vo.getCompareLastYearWorkDay()).orElse(BigDecimal.ZERO)); String busiName = vo.getBusiBigcName(); if (busiName != null && bizTypes.contains(busiName)) { BigDecimal palYear = Optional.ofNullable(vo.getPalYear()).orElse(BigDecimal.ZERO); bizMap.put(busiName, bizMap.get(busiName).add(palYear)); } } Map<String, BigDecimal> result = new HashMap<>(); result.put("部门合计(今年)", totalYear); result.put("部门合计(去年)", totalLastYear); result.putAll(bizMap); return result; } /** * @Description 生成资负规模变化数据 * @author K0171746 */ private void generateChart2(List<DebtBusinessDayReportWholeAssetVO> wholeVO,String dateDt){ List<LiquidReportChart> chartList = new ArrayList<>(); int rowNum = 1; for (String dept : departments) { // 获取该部门各业务类型的汇总金额 Map<String, BigDecimal> result = calculateChart2(wholeVO, dept); // 动态遍历这个部门实际出现的所有业务类型 for (String bizType : result.keySet()) { BigDecimal value = result.get(bizType); if (value == null) { value = BigDecimal.ZERO; } LiquidReportChart chart = new LiquidReportChart(); chart.setDataDt(dateDt); chart.setReportCode(debtBusinessDayReport); chart.setChartId("chart0020"); chart.setRowNum(rowNum++); chart.setCellValue1(bizType); chart.setCellValue2(value.stripTrailingZeros().toPlainString()); // 列头:业务类型 chart.setChartName(dept); chartList.add(chart); } } // 落库 try { if (!chartList.isEmpty()) { liquidReportChartRepository.save(chartList); logger.info("成功将 {} 条 chart2 ({}, date={}) 数据落库", chartList.size(), "chart0020", dateDt); } else { logger.warn("没有有效数据生成 chart2 (date={})", dateDt); } } catch (Exception e) { logger.error("保存 chart2 数据时发生异常 (date={})", dateDt, e); throw new RuntimeException("Failed to save chart2 data", e); } } /** * @Description 计算资负规模变化图数据 * @author K0171746 */ private Map<String, BigDecimal> calculateChart2(List<DebtBusinessDayReportWholeAssetVO> wholeVO, String department){ Map<String, BigDecimal> result = new HashMap<>(); for (int i = 0; i < wholeVO.size(); i++) { DebtBusinessDayReportWholeAssetVO vo = wholeVO.get(i); String dept = vo.getDept(); // 跳过 null 或不匹配的部门 if (department == null || dept == null) { continue; } if (!department.equals(dept)) { continue; } // 获取业务类型(projType) String projType = vo.getProjType(); if (projType == null) { continue; // 类型为空则跳过 } projType = projType.trim(); if (projType.isEmpty()) { continue; // 空字符串也跳过 } // 获取 pal 值,null 视为 0 BigDecimal pal = vo.getPal(); if (pal == null) { pal = BigDecimal.ZERO; } // 判断此业务类型是否已存在 boolean found = false; for (String existingType : result.keySet()) { if (existingType.equals(projType)) { // 找到了,取出原值并相加 BigDecimal oldSum = result.get(existingType); BigDecimal newSum = oldSum.add(pal); result.put(projType, newSum); found = true; break; } } // 如果没找到(第一次出现),直接放入 if (!found) { result.put(projType, pal); } } return result; } /** * 检查指定日期是否有数据记录 * @author K0171746 */ public int queryCount(String dateDt) { StringBuilder sql = new StringBuilder(); sql.append("SELECT "); sql.append(" count(1) "); sql.append("FROM "); sql.append(" T_LIQUID_BURDEN_DEPT "); sql.append("WHERE "); sql.append(" DATA_DT = ? "); logger.info("查询T_LIQUID_BURDEN_DEPT数据是否为空{}", sql.toString()); return jdbcTemplate.queryForObject(sql.toString(), Integer.class, dateDt); } /** * 生成汇总数据图表 chart0030 * @author K0171746 */ private void generateParent(List<DebtBusinessDayReportWholeAssetVO> wholeVO,String dateDt){ // 按部门分组数据 Map<String, List<DebtBusinessDayReportWholeAssetVO>> deptDataMap = new HashMap<>(); for (DebtBusinessDayReportWholeAssetVO vo : wholeVO) { // 判空处理 String projType = vo.getProjType(); if (projType == null || !projType.contains("合计")){ continue; } String dept = vo.getDept(); if (!deptDataMap.containsKey(dept)) { deptDataMap.put(dept, new ArrayList<>()); } deptDataMap.get(dept).add(vo); } int rowNum = 1; List<LiquidReportChart> chartList = new ArrayList<>(); // 为每个部门生成数据,确保不超过23行 for (Map.Entry<String, List<DebtBusinessDayReportWholeAssetVO>> entry : deptDataMap.entrySet()) { String dept = entry.getKey(); List<DebtBusinessDayReportWholeAssetVO> deptData = entry.getValue(); // 如果部门数据超过23行,需要进行动态调整 if (deptData.size() > 23) { // 获取所有项目类型 Set<String> projTypes = new HashSet<>(); for (DebtBusinessDayReportWholeAssetVO vo : deptData) { if (vo.getProjType() != null) { projTypes.add(vo.getProjType()); } } // 如果项目类型数量较多,则进行分组汇总 if (projTypes.size() > 6) { // 按项目类型分组汇总数据 Map<String, DebtBusinessDayReportParentAssetVO> aggregatedData = new HashMap<>(); // 前5个项目 List<String> mainTypes = new ArrayList<>(projTypes).subList(0, 5); for (String type : mainTypes) { DebtBusinessDayReportParentAssetVO aggregatedVO = new DebtBusinessDayReportParentAssetVO(); aggregatedVO.setDept(dept); aggregatedVO.setProjType(type); for (DebtBusinessDayReportWholeAssetVO vo : deptData) { if (type.equals(vo.getProjType())) { // 累加各项指标 aggregatedVO.setPal(Optional.ofNullable(aggregatedVO.getPal()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getPal()).orElse(BigDecimal.ZERO))); aggregatedVO.setPalMon(Optional.ofNullable(aggregatedVO.getPalMon()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getPalMon()).orElse(BigDecimal.ZERO))); aggregatedVO.setPalYear(Optional.ofNullable(aggregatedVO.getPalYear()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getPalYear()).orElse(BigDecimal.ZERO))); aggregatedVO.setCompareYear(Optional.ofNullable(aggregatedVO.getCompareYear()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getCompareYear()).orElse(BigDecimal.ZERO))); aggregatedVO.setAmt(Optional.ofNullable(aggregatedVO.getAmt()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getAmt()).orElse(BigDecimal.ZERO))); aggregatedVO.setCompareDay(Optional.ofNullable(aggregatedVO.getCompareDay()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getCompareDay()).orElse(BigDecimal.ZERO))); aggregatedVO.setCompareMon(Optional.ofNullable(aggregatedVO.getCompareMon()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getCompareMon()).orElse(BigDecimal.ZERO))); aggregatedVO.setCompareBeginYear(Optional.ofNullable(aggregatedVO.getCompareBeginYear()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getCompareBeginYear()).orElse(BigDecimal.ZERO))); } } aggregatedData.put(type, aggregatedVO); } // 处理"其他"项目 DebtBusinessDayReportParentAssetVO otherVO = new DebtBusinessDayReportParentAssetVO(); otherVO.setDept(dept); otherVO.setProjType("其他"); for (DebtBusinessDayReportWholeAssetVO vo : deptData) { if (!mainTypes.contains(vo.getProjType())) { // 累加各项指标 otherVO.setPal(Optional.ofNullable(otherVO.getPal()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getPal()).orElse(BigDecimal.ZERO))); otherVO.setPalMon(Optional.ofNullable(otherVO.getPalMon()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getPalMon()).orElse(BigDecimal.ZERO))); otherVO.setPalYear(Optional.ofNullable(otherVO.getPalYear()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getPalYear()).orElse(BigDecimal.ZERO))); otherVO.setCompareYear(Optional.ofNullable(otherVO.getCompareYear()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getCompareYear()).orElse(BigDecimal.ZERO))); otherVO.setAmt(Optional.ofNullable(otherVO.getAmt()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getAmt()).orElse(BigDecimal.ZERO))); otherVO.setCompareDay(Optional.ofNullable(otherVO.getCompareDay()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getCompareDay()).orElse(BigDecimal.ZERO))); otherVO.setCompareMon(Optional.ofNullable(otherVO.getCompareMon()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getCompareMon()).orElse(BigDecimal.ZERO))); otherVO.setCompareBeginYear(Optional.ofNullable(otherVO.getCompareBeginYear()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getCompareBeginYear()).orElse(BigDecimal.ZERO))); } } aggregatedData.put("其他", otherVO); // 生成图表数据 for (DebtBusinessDayReportParentAssetVO vo : aggregatedData.values()) { LiquidReportChart chart = new LiquidReportChart(); chart.setDataDt(dateDt); chart.setReportCode(debtBusinessDayReport); chart.setChartId("chart0030"); chart.setRowNum(rowNum++); chart.setCellValue1(vo.getDept()); chart.setCellValue2(String.valueOf(vo.getPal())); chart.setCellValue3(String.valueOf(vo.getPalMon())); chart.setCellValue4(String.valueOf(vo.getPalYear())); chart.setCellValue5(String.valueOf(vo.getCompareYear())); chart.setCellValue6(vo.getProjType()); chart.setCellValue7(String.valueOf(vo.getAmt())); chart.setCellValue8(String.valueOf(vo.getCompareDay())); chart.setCellValue9(String.valueOf(vo.getCompareMon())); chart.setCellValue10(String.valueOf(vo.getCompareBeginYear())); chartList.add(chart); } } else { // 按项目类型去重 Map<String, DebtBusinessDayReportParentAssetVO> uniqueData = new HashMap<>(); for (DebtBusinessDayReportWholeAssetVO vo : deptData) { String projType = vo.getProjType(); if (!uniqueData.containsKey(projType)) { DebtBusinessDayReportParentAssetVO parentVO = new DebtBusinessDayReportParentAssetVO(); parentVO.setDept(vo.getDept()); parentVO.setPal(Optional.ofNullable(vo.getPal()).orElse(BigDecimal.ZERO)); parentVO.setPalMon(Optional.ofNullable(vo.getPalMon()).orElse(BigDecimal.ZERO)); parentVO.setPalYear(Optional.ofNullable(vo.getPalYear()).orElse(BigDecimal.ZERO)); parentVO.setCompareYear(Optional.ofNullable(vo.getCompareYear()).orElse(BigDecimal.ZERO)); parentVO.setProjType(vo.getProjType()); parentVO.setAmt(Optional.ofNullable(vo.getAmt()).orElse(BigDecimal.ZERO)); parentVO.setCompareDay(Optional.ofNullable(vo.getCompareDay()).orElse(BigDecimal.ZERO)); parentVO.setCompareMon(Optional.ofNullable(vo.getCompareMon()).orElse(BigDecimal.ZERO)); parentVO.setCompareBeginYear(Optional.ofNullable(vo.getCompareBeginYear()).orElse(BigDecimal.ZERO)); uniqueData.put(projType, parentVO); } else { // 累加到已存在的记录 DebtBusinessDayReportParentAssetVO existing = uniqueData.get(projType); existing.setPal(Optional.ofNullable(existing.getPal()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getPal()).orElse(BigDecimal.ZERO))); existing.setPalMon(Optional.ofNullable(existing.getPalMon()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getPalMon()).orElse(BigDecimal.ZERO))); existing.setPalYear(Optional.ofNullable(existing.getPalYear()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getPalYear()).orElse(BigDecimal.ZERO))); existing.setCompareYear(Optional.ofNullable(existing.getCompareYear()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getCompareYear()).orElse(BigDecimal.ZERO))); existing.setAmt(Optional.ofNullable(existing.getAmt()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getAmt()).orElse(BigDecimal.ZERO))); existing.setCompareDay(Optional.ofNullable(existing.getCompareDay()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getCompareDay()).orElse(BigDecimal.ZERO))); existing.setCompareMon(Optional.ofNullable(existing.getCompareMon()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getCompareMon()).orElse(BigDecimal.ZERO))); existing.setCompareBeginYear(Optional.ofNullable(existing.getCompareBeginYear()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getCompareBeginYear()).orElse(BigDecimal.ZERO))); } } // 生成图表数据 for (DebtBusinessDayReportParentAssetVO vo : uniqueData.values()) { LiquidReportChart chart = new LiquidReportChart(); chart.setDataDt(dateDt); chart.setReportCode(debtBusinessDayReport); chart.setChartId("chart0030"); chart.setRowNum(rowNum++); chart.setCellValue1(vo.getDept()); chart.setCellValue2(String.valueOf(vo.getPal())); chart.setCellValue3(String.valueOf(vo.getPalMon())); chart.setCellValue4(String.valueOf(vo.getPalYear())); chart.setCellValue5(String.valueOf(vo.getCompareYear())); chart.setCellValue6(vo.getProjType()); chart.setCellValue7(String.valueOf(vo.getAmt())); chart.setCellValue8(String.valueOf(vo.getCompareDay())); chart.setCellValue9(String.valueOf(vo.getCompareMon())); chart.setCellValue10(String.valueOf(vo.getCompareBeginYear())); chartList.add(chart); } } } else { // 数据行数不超过23,直接处理 for (DebtBusinessDayReportWholeAssetVO vo : deptData) { DebtBusinessDayReportParentAssetVO parentVO = new DebtBusinessDayReportParentAssetVO(); parentVO.setDept(vo.getDept()); parentVO.setPal(Optional.ofNullable(vo.getPal()).orElse(BigDecimal.ZERO)); parentVO.setPalMon(Optional.ofNullable(vo.getPalMon()).orElse(BigDecimal.ZERO)); parentVO.setPalYear(Optional.ofNullable(vo.getPalYear()).orElse(BigDecimal.ZERO)); parentVO.setCompareYear(Optional.ofNullable(vo.getCompareYear()).orElse(BigDecimal.ZERO)); parentVO.setProjType(vo.getProjType()); parentVO.setAmt(Optional.ofNullable(vo.getAmt()).orElse(BigDecimal.ZERO)); parentVO.setCompareDay(Optional.ofNullable(vo.getCompareDay()).orElse(BigDecimal.ZERO)); parentVO.setCompareMon(Optional.ofNullable(vo.getCompareMon()).orElse(BigDecimal.ZERO)); parentVO.setCompareBeginYear(Optional.ofNullable(vo.getCompareBeginYear()).orElse(BigDecimal.ZERO)); LiquidReportChart chart = new LiquidReportChart(); chart.setDataDt(dateDt); chart.setReportCode(debtBusinessDayReport); chart.setChartId("chart0030"); chart.setRowNum(rowNum++); chart.setCellValue1(parentVO.getDept()); chart.setCellValue2(String.valueOf(parentVO.getPal())); chart.setCellValue3(String.valueOf(parentVO.getPalMon())); chart.setCellValue4(String.valueOf(parentVO.getPalYear())); chart.setCellValue5(String.valueOf(parentVO.getCompareYear())); chart.setCellValue6(parentVO.getProjType()); chart.setCellValue7(String.valueOf(parentVO.getAmt())); chart.setCellValue8(String.valueOf(parentVO.getCompareDay())); chart.setCellValue9(String.valueOf(parentVO.getCompareMon())); chart.setCellValue10(String.valueOf(parentVO.getCompareBeginYear())); chartList.add(chart); } } } // 落地入库 try { if (!chartList.isEmpty()) { liquidReportChartRepository.save(chartList); logger.info("成功将 {} 条 chart3 ({}, date={}) 数据落库", chartList.size(), "chart0030", dateDt); } else { logger.warn("没有有效数据生成 chart3 (date={})", dateDt); } } catch (Exception e) { logger.error("保存 chart3 数据时发生异常 (date={})", dateDt, e); throw new RuntimeException("Failed to save chart3 data", e); } } /** * @Description 生成各部门数据表 chart0040 * @author K0171746 */ private void generateDpAsset(List<DebtBusinessDayReportWholeAssetVO> wholeVO,String dateDt){ // 参数校验 if (CollectionUtils.isEmpty(wholeVO)) { logger.warn("输入的 wholeVO 数据为空,跳过 generateDpAsset 处理"); return; } if (dateDt == null || dateDt.trim().isEmpty()) { logger.error("日期 dateDt 不能为空"); throw new IllegalArgumentException("dateDt is required"); } // 按部门分组数据 Map<String, List<DebtBusinessDayReportWholeAssetVO>> deptDataMap = new HashMap<>(); for (DebtBusinessDayReportWholeAssetVO vo : wholeVO) { if (vo == null || vo.getDept() == null) { continue; } String dept = vo.getDept(); if (!deptDataMap.containsKey(dept)) { deptDataMap.put(dept, new ArrayList<>()); } deptDataMap.get(dept).add(vo); } List<LiquidReportChart> chartList = new ArrayList<>(); int rowNum = 1; // 为每个部门生成数据,确保不超过23行 for (Map.Entry<String, List<DebtBusinessDayReportWholeAssetVO>> entry : deptDataMap.entrySet()) { String dept = entry.getKey(); List<DebtBusinessDayReportWholeAssetVO> deptData = entry.getValue(); // 如果部门数据超过23行,需要进行动态调整 if (deptData.size() > 23) { // 获取所有业务大类和小类组合 Map<String, List<DebtBusinessDayReportWholeAssetVO>> businessTypeMap = new HashMap<>(); for (DebtBusinessDayReportWholeAssetVO vo : deptData) { String businessType = (vo.getBusiBigcName() != null ? vo.getBusiBigcName() : "") + "|" + (vo.getBusiSmlcName() != null ? vo.getBusiSmlcName() : ""); if (!businessTypeMap.containsKey(businessType)) { businessTypeMap.put(businessType, new ArrayList<>()); } businessTypeMap.get(businessType).add(vo); } // 如果业务类型数量较多,则进行分组汇总 if (businessTypeMap.size() > 6) { // 按业务类型分组汇总数据 Map<String, DebtBusinessDayReportWholeAssetVO> aggregatedData = new HashMap<>(); // 前5个 List<String> mainTypes = new ArrayList<>(businessTypeMap.keySet()).subList(0, 5); for (String type : mainTypes) { List<DebtBusinessDayReportWholeAssetVO> typeData = businessTypeMap.get(type); String[] parts = type.split("\\|"); String bigType = parts.length > 0 ? parts[0] : ""; String smallType = parts.length > 1 ? parts[1] : ""; // 创建汇总对象 DebtBusinessDayReportWholeAssetVO aggregatedVO = new DebtBusinessDayReportWholeAssetVO(); aggregatedVO.setDept(dept); aggregatedVO.setBusiBigcName(bigType); aggregatedVO.setBusiSmlcName(smallType); // 累加各项指标 for (DebtBusinessDayReportWholeAssetVO vo : typeData) { aggregatedVO.setPal(Optional.ofNullable(aggregatedVO.getPal()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getPal()).orElse(BigDecimal.ZERO))); aggregatedVO.setPalMon(Optional.ofNullable(aggregatedVO.getPalMon()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getPalMon()).orElse(BigDecimal.ZERO))); aggregatedVO.setPalYear(Optional.ofNullable(aggregatedVO.getPalYear()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getPalYear()).orElse(BigDecimal.ZERO))); aggregatedVO.setCompareYear(Optional.ofNullable(aggregatedVO.getCompareYear()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getCompareYear()).orElse(BigDecimal.ZERO))); aggregatedVO.setAmt(Optional.ofNullable(aggregatedVO.getAmt()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getAmt()).orElse(BigDecimal.ZERO))); aggregatedVO.setCompareDay(Optional.ofNullable(aggregatedVO.getCompareDay()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getCompareDay()).orElse(BigDecimal.ZERO))); aggregatedVO.setCompareMon(Optional.ofNullable(aggregatedVO.getCompareMon()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getCompareMon()).orElse(BigDecimal.ZERO))); aggregatedVO.setCompareBeginYear(Optional.ofNullable(aggregatedVO.getCompareBeginYear()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getCompareBeginYear()).orElse(BigDecimal.ZERO))); } aggregatedData.put(type, aggregatedVO); } // 处理"其他" DebtBusinessDayReportWholeAssetVO otherVO = new DebtBusinessDayReportWholeAssetVO(); otherVO.setDept(dept); otherVO.setBusiBigcName("其他"); otherVO.setBusiSmlcName(""); otherVO.setProjType("其他"); for (Map.Entry<String, List<DebtBusinessDayReportWholeAssetVO>> typeEntry : businessTypeMap.entrySet()) { if (!mainTypes.contains(typeEntry.getKey())) { for (DebtBusinessDayReportWholeAssetVO vo : typeEntry.getValue()) { // 累加各项指标 otherVO.setPal(Optional.ofNullable(otherVO.getPal()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getPal()).orElse(BigDecimal.ZERO))); otherVO.setPalMon(Optional.ofNullable(otherVO.getPalMon()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getPalMon()).orElse(BigDecimal.ZERO))); otherVO.setPalYear(Optional.ofNullable(otherVO.getPalYear()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getPalYear()).orElse(BigDecimal.ZERO))); otherVO.setCompareYear(Optional.ofNullable(otherVO.getCompareYear()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getCompareYear()).orElse(BigDecimal.ZERO))); otherVO.setAmt(Optional.ofNullable(otherVO.getAmt()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getAmt()).orElse(BigDecimal.ZERO))); otherVO.setCompareDay(Optional.ofNullable(otherVO.getCompareDay()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getCompareDay()).orElse(BigDecimal.ZERO))); otherVO.setCompareMon(Optional.ofNullable(otherVO.getCompareMon()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getCompareMon()).orElse(BigDecimal.ZERO))); otherVO.setCompareBeginYear(Optional.ofNullable(otherVO.getCompareBeginYear()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getCompareBeginYear()).orElse(BigDecimal.ZERO))); } } } aggregatedData.put("其他|", otherVO); // 生成图表数据 for (DebtBusinessDayReportWholeAssetVO vo : aggregatedData.values()) { LiquidReportChart chart = new LiquidReportChart(); chart.setDataDt(dateDt); chart.setReportCode(debtBusinessDayReport); chart.setChartId("chart0040"); chart.setRowNum(rowNum++); chart.setCellValue1(vo.getBusiBigcName()); chart.setCellValue2(vo.getBusiSmlcName()); chart.setCellValue3(String.valueOf(vo.getPal())); chart.setCellValue4(String.valueOf(vo.getPalMon())); chart.setCellValue5(String.valueOf(vo.getPalYear())); chart.setCellValue6(vo.getProjType()); chart.setCellValue7(String.valueOf(vo.getAmt())); chart.setCellValue8(String.valueOf(vo.getCompareDay())); chart.setCellValue9(String.valueOf(vo.getCompareMon())); chart.setCellValue10(String.valueOf(vo.getCompareBeginYear())); chart.setChartName(vo.getDept()); chartList.add(chart); } } else { // 按业务类型去重 Map<String, DebtBusinessDayReportWholeAssetVO> uniqueData = new HashMap<>(); for (DebtBusinessDayReportWholeAssetVO vo : deptData) { String businessType = (vo.getBusiBigcName() != null ? vo.getBusiBigcName() : "") + "|" + (vo.getBusiSmlcName() != null ? vo.getBusiSmlcName() : ""); if (!uniqueData.containsKey(businessType)) { DebtBusinessDayReportWholeAssetVO uniqueVO = new DebtBusinessDayReportWholeAssetVO(); uniqueVO.setDept(vo.getDept()); uniqueVO.setBusiBigcName(vo.getBusiBigcName()); uniqueVO.setBusiSmlcName(vo.getBusiSmlcName()); uniqueVO.setPal(Optional.ofNullable(vo.getPal()).orElse(BigDecimal.ZERO)); uniqueVO.setPalMon(Optional.ofNullable(vo.getPalMon()).orElse(BigDecimal.ZERO)); uniqueVO.setPalYear(Optional.ofNullable(vo.getPalYear()).orElse(BigDecimal.ZERO)); uniqueVO.setCompareYear(Optional.ofNullable(vo.getCompareYear()).orElse(BigDecimal.ZERO)); uniqueVO.setProjType(vo.getProjType()); uniqueVO.setAmt(Optional.ofNullable(vo.getAmt()).orElse(BigDecimal.ZERO)); uniqueVO.setCompareDay(Optional.ofNullable(vo.getCompareDay()).orElse(BigDecimal.ZERO)); uniqueVO.setCompareMon(Optional.ofNullable(vo.getCompareMon()).orElse(BigDecimal.ZERO)); uniqueVO.setCompareBeginYear(Optional.ofNullable(vo.getCompareBeginYear()).orElse(BigDecimal.ZERO)); uniqueData.put(businessType, uniqueVO); } else { // 累加到已存在的记录 DebtBusinessDayReportWholeAssetVO existing = uniqueData.get(businessType); existing.setPal(Optional.ofNullable(existing.getPal()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getPal()).orElse(BigDecimal.ZERO))); existing.setPalMon(Optional.ofNullable(existing.getPalMon()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getPalMon()).orElse(BigDecimal.ZERO))); existing.setPalYear(Optional.ofNullable(existing.getPalYear()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getPalYear()).orElse(BigDecimal.ZERO))); existing.setCompareYear(Optional.ofNullable(existing.getCompareYear()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getCompareYear()).orElse(BigDecimal.ZERO))); existing.setAmt(Optional.ofNullable(existing.getAmt()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getAmt()).orElse(BigDecimal.ZERO))); existing.setCompareDay(Optional.ofNullable(existing.getCompareDay()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getCompareDay()).orElse(BigDecimal.ZERO))); existing.setCompareMon(Optional.ofNullable(existing.getCompareMon()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getCompareMon()).orElse(BigDecimal.ZERO))); existing.setCompareBeginYear(Optional.ofNullable(existing.getCompareBeginYear()).orElse(BigDecimal.ZERO) .add(Optional.ofNullable(vo.getCompareBeginYear()).orElse(BigDecimal.ZERO))); } } // 生成图表数据 for (DebtBusinessDayReportWholeAssetVO vo : uniqueData.values()) { LiquidReportChart chart = new LiquidReportChart(); chart.setDataDt(dateDt); chart.setReportCode(debtBusinessDayReport); chart.setChartId("chart0040"); chart.setRowNum(rowNum++); chart.setCellValue1(vo.getBusiBigcName()); chart.setCellValue2(vo.getBusiSmlcName()); chart.setCellValue3(String.valueOf(vo.getPal())); chart.setCellValue4(String.valueOf(vo.getPalMon())); chart.setCellValue5(String.valueOf(vo.getPalYear())); chart.setCellValue6(vo.getProjType()); chart.setCellValue7(String.valueOf(vo.getAmt())); chart.setCellValue8(String.valueOf(vo.getCompareDay())); chart.setCellValue9(String.valueOf(vo.getCompareMon())); chart.setCellValue10(String.valueOf(vo.getCompareBeginYear())); chart.setChartName(vo.getDept()); chartList.add(chart); } } } else { // 数据行数不超过23,直接处理 for (DebtBusinessDayReportWholeAssetVO vo : deptData) { LiquidReportChart chart = new LiquidReportChart(); chart.setDataDt(dateDt); chart.setReportCode(debtBusinessDayReport); chart.setChartId("chart0040"); chart.setRowNum(rowNum++); chart.setCellValue1(vo.getBusiBigcName()); chart.setCellValue2(vo.getBusiSmlcName()); chart.setCellValue3(String.valueOf(vo.getPal())); chart.setCellValue4(String.valueOf(vo.getPalMon())); chart.setCellValue5(String.valueOf(vo.getPalYear())); chart.setCellValue6(vo.getProjType()); chart.setCellValue7(String.valueOf(vo.getAmt())); chart.setCellValue8(String.valueOf(vo.getCompareDay())); chart.setCellValue9(String.valueOf(vo.getCompareMon())); chart.setCellValue10(String.valueOf(vo.getCompareBeginYear())); chart.setChartName(vo.getDept()); chartList.add(chart); } } } // 落地入库 try { if (!chartList.isEmpty()) { liquidReportChartRepository.save(chartList); logger.info("成功将 {} 条部门明细数据 ({}, date={}) 落库", chartList.size(), "chart0040", dateDt); } else { logger.warn("没有有效数据生成部门明细表 (date={})", dateDt); } } catch (Exception e) { logger.error("保存部门明细数据时发生异常 (date={})", dateDt, e); throw new RuntimeException("Failed to save department asset detail data", e); } } /** * @Description 查询日报,不传部门参数则为母公司数据 * @author K0171746 */ public DebtBusinessDayReportResultVO getReport (String dataDt,String department){ DebtBusinessDayReportResultVO result = new DebtBusinessDayReportResultVO(); // 获取今年第一天 String bgnDt = workDayService.findYearFirstNaturalDay(dataDt); // 测试用 if (Integer.parseInt(bgnDt)<20250613){ bgnDt = "20250613"; } // 获取两个日期之间的交易日 List<String> bgnDts = workDayService.findTransDts(bgnDt, dataDt); // 查询今年年初到指定日期的数据 List<LiquidReportChart> chartCells10 = liquidReportChartRepository.findByDataDtInAndReportCodeAndChartId(bgnDts, debtBusinessDayReport, "chart0010") .stream() .filter(chart -> department.equals(chart.getChartName())) .collect(Collectors.toList()); // 处理chart0010数据,转换为VO列表 List<DebtBusinessDayReportChartVO> vos = chartCells10.stream() .map(chart -> { DebtBusinessDayReportChartVO vo = new DebtBusinessDayReportChartVO(); vo.setDataDt(chart.getDataDt()); vo.setReportCode(debtBusinessDayReport); vo.setDepartment(chart.getChartName()); vo.setChartID(chart.getChartId()); // 提取所有有效的业务类型和值 List<Map<String, String>> values = new ArrayList<>(); // 提取cellValue1-cellValue10中的有效数据对 extractValuePairs(chart.getCellValue1(), chart.getCellValue2(), values); extractValuePairs(chart.getCellValue3(), chart.getCellValue4(), values); extractValuePairs(chart.getCellValue5(), chart.getCellValue6(), values); extractValuePairs(chart.getCellValue7(), chart.getCellValue8(), values); extractValuePairs(chart.getCellValue9(), chart.getCellValue10(), values); vo.setValues(values); return vo; }) .collect(Collectors.toList()); // 查询chart0020数据 List<LiquidReportChart> chartCells2 = liquidReportChartRepository.findByDataDtInAndReportCodeAndChartId(bgnDts, debtBusinessDayReport, "chart0020"); // 处理chart0020数据 List<DebtBusinessDayReportChartVO> chart2Vos = chartCells2.stream() .filter(chart -> department.equals(chart.getChartName())) .collect(Collectors.groupingBy(LiquidReportChart::getDataDt)) .entrySet().stream() .sorted(Map.Entry.comparingByKey()) .map(entry -> { String dateDt = entry.getKey(); List<LiquidReportChart> chartsForDate = entry.getValue(); DebtBusinessDayReportChartVO chartVO = new DebtBusinessDayReportChartVO(); chartVO.setDataDt(dateDt); chartVO.setReportCode(debtBusinessDayReport); chartVO.setChartID("chart0020"); chartVO.setDepartment(department); // 提取所有业务类型和金额 List<Map<String, String>> values = chartsForDate.stream() .filter(chart -> chart.getCellValue1() != null && !chart.getCellValue1().trim().isEmpty() && chart.getCellValue2() != null && !chart.getCellValue2().trim().isEmpty()) .map(chart -> { Map<String, String> item = new HashMap<>(); item.put("name", chart.getCellValue1().trim()); item.put("value", chart.getCellValue2().trim()); return item; }) .collect(Collectors.toList()); chartVO.setValues(values); return chartVO; }) .collect(Collectors.toList()); // 母公司 List<LiquidReportChart> chartCells30 = liquidReportChartRepository.findLiquidReportChartByDataDtAndReportCodeAndChartId(dataDt, debtBusinessDayReport, "chart0030"); // 各部门 List<LiquidReportChart> chartCells40 = liquidReportChartRepository.findLiquidReportChartByDataDtAndReportCodeAndChartId(dataDt, debtBusinessDayReport, "chart0040"); List<LiquidReportChart> chartCells0030 = chartCells30.stream() .filter(chart -> "母公司汇总".equals(department)) .collect(Collectors.toList()); List<LiquidReportChart> chartCells0040 = chartCells40.stream() .filter(chart -> department.equals(chart.getChartName())) .collect(Collectors.toList()); Map<String,Object> map=new HashMap<>(); map.put("chart0010",vos); map.put("chart0020",chart2Vos); if ("母公司汇总".equals(department)){ map.put("chart0030",chartCells0030); } if (!"母公司汇总".equals(department)){ map.put("chart0040",chartCells0040); } result.setCharts(map); // 并行查询状态信息 Date date = SystemUtil.strToDate(dataDt, "yyyyMMdd"); String reportType = "资产负债业务日报"; CompletableFuture<ReportStatusManage> rsmFuture = CompletableFuture.supplyAsync(() -> reportStatusRepository.findReportStatusManageByParam(date, reportType)); CompletableFuture<FileStore> fileStoreFuture = CompletableFuture.supplyAsync(() -> multiClientRepository.findFileStoreByBusiType(reportType + "-" + dataDt)); CompletableFuture<ReportStatusManage> rsmPushFuture = CompletableFuture.supplyAsync(() -> reportStatusRepository.findReportStatusManageByParam(date, reportType + "推送")); try { // 设置超时时间,避免无限等待 ReportStatusManage rsm = rsmFuture.get(30, TimeUnit.SECONDS); FileStore fileStoreByBusiType = fileStoreFuture.get(30, TimeUnit.SECONDS); ReportStatusManage rsmPush = rsmPushFuture.get(30, TimeUnit.SECONDS); // 设置状态,优先级:已推送 > 报告预生成 > 报告预览 > 未生成 if(rsmPush!=null){ result.setStatus("已推送"); } else if(fileStoreByBusiType!=null){ result.setStatus("报告预生成"); } else if(rsm!=null){ result.setStatus("报告预览"); } else { result.setStatus("未生成"); } } catch (TimeoutException e) { logger.error("查询报告状态超时", e); result.setStatus("查询超时"); } catch (Exception e) { logger.error("查询报告状态时发生异常", e); result.setStatus("查询失败"); } return result; } private void extractValuePairs(String name, String value, List<Map<String, String>> values) { if (name != null && !name.trim().isEmpty() && value != null && !value.trim().isEmpty()) { Map<String, String> item = new HashMap<>(); item.put("name", name.trim()); item.put("value", value.trim()); values.add(item); } } } 检查一下代码有没有问题
最新发布
10-30
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值