string.Empty 和 "" 并不总是可以互换的

博客介绍了C#中\\和string.Empty的使用情况,多数情况下二者可互换,但在标签构造器里只能用\\。还给出判定空字符串性能从高到低的写法:s.Length == 0 优于 s == string.Empty 优于 s == \\,并提供了参考链接。
在 C# 中,大多数情况下 "" 和 string.Empty 可以互换使用。比如:

string  s  =   "" ;
string  s2  =   string .Empty;

if  (s  ==   string .Empty)  {
  
// 
}

但是我发现有一种情况下只能是用常数形式: "", 而不能使用 string.Empty 这个静态变量。就是在标签(Attribute) 的构造器里面:

这个代码是正确的:
[Default( "" )]
public   string  Name  {
  
get return name; }
  
set { name = value; }
}

这个是错误的,无法通过编译:
[Default( string .Empty)]
public   string  Name  {
  
get return name; }
  
set { name = value; }
}

错误信息是:
error CS0182: 属性参数必须是常数表达式、typeof 表达式或数组创建表达式

其他地方我并未发现类似的例子。

顺便提一下,判定为空字符串的几种写法,按照性能从高到低的顺序是:

s.Length == 0  优于 s == string.Empty  优于 s == "" 

这个结论来自于:
http://www.cnblogs.com/allenlooplee/archive/2004/11/11/62805.html
package com.htsc.service; import com.alibaba.dubbo.common.utils.CollectionUtils; import com.htsc.commons.SystemUtil; import com.htsc.jpa.po.LiquidReportChart; import com.htsc.jpa.po.ReportStatusManage; import com.htsc.jpa.repository.LiquidBurdenDeptRepository; import com.htsc.jpa.repository.LiquidReportChartRepository; import com.htsc.jpa.repository.LiquidReportDocxRepository; import com.htsc.jpa.repository.ReportStatusRepository; import com.htsc.view.vo.DebtBusinessDayReportDpAssetVO; import com.htsc.view.vo.DebtBusinessDayReportParentAssetVO; import com.htsc.view.vo.DebtBusinessDayReportWholeAssetVO; import com.htsc.view.vo.LiquidAssetDailyReportResultVO; 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 static com.htsc.strategy.ISubLcrNsfrHandlerStrategy.log; /** * @Author K0171746 * @Date 2025/10/22 14:35 */ @Service public class DebtBusinessDayReportService { private static final Logger logger = LoggerFactory.getLogger(SwapConvenienceWeeklyService.class); // 日报名称 public static String debtBusinessDayReport = "AssetDebtDailyReport"; // 部门列表 private static final String[] departments = {"母公司整体", "证券投资部", "中央交易室", "金融创新部", "销售交易部", "固定收益部", "报价融资部", "资金运营部", "融资融券部" }; 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("两融业务", "转融通", "约定购回")); } private static final Map<String, String> PROJ_TYPE_TO_KEY = new HashMap<>(); private static final Map<String, String> KEY_TO_DISPLAY_NAME = new LinkedHashMap<>(); // 保持顺序 static { // 中文 projType 映射到内部字段 key PROJ_TYPE_TO_KEY.put("债券", "bond"); PROJ_TYPE_TO_KEY.put("股票", "stock"); PROJ_TYPE_TO_KEY.put("基金", "fund"); PROJ_TYPE_TO_KEY.put("股指期货", "indexFutures"); PROJ_TYPE_TO_KEY.put("国债期货", "treasuryFutures"); PROJ_TYPE_TO_KEY.put("收益互换", "swap"); PROJ_TYPE_TO_KEY.put("场外期权", "otcOption"); // 内部 key 映射回中文显示名(用于报表第二列) KEY_TO_DISPLAY_NAME.put("bond", "债券"); KEY_TO_DISPLAY_NAME.put("stock", "股票"); KEY_TO_DISPLAY_NAME.put("fund", "基金"); KEY_TO_DISPLAY_NAME.put("indexFutures", "股指期货"); KEY_TO_DISPLAY_NAME.put("treasuryFutures", "国债期货"); KEY_TO_DISPLAY_NAME.put("swap", "收益互换"); KEY_TO_DISPLAY_NAME.put("otcOption", "场外期权"); } @Autowired private JdbcTemplate jdbcTemplate; @Autowired private LiquidReportChartRepository liquidReportChartRepository; @Autowired private LiquidReportDocxRepository liquidReportDocxRepository; @Autowired private LiquidBurdenDeptRepository liquidBurdenDeptRepository; @Autowired private ReportStatusRepository reportStatusRepository; @Autowired private WorkDayService workDayService; // 生成日报 public void generateReport(String dateDt) { int i = this.queryCount(dateDt); if(i==0){ logger.info("#############{}没有数据,不生成报告", dateDt); return; } // 删除当日数据 liquidReportChartRepository.deleteLiquidReportChartByDataDtAndReportCode(dateDt, debtBusinessDayReport); liquidReportDocxRepository.deleteLiquidReportDocxByDataDtAndReportCode(dateDt, debtBusinessDayReport); // 查询所有数据 List<DebtBusinessDayReportWholeAssetVO> wholeVO = this.queryAsset(dateDt); // 生成折线图1数据 this.generateChart1(wholeVO,dateDt); // 生成折线图2数据 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); } /** * @Description 根据时间查询所有数据 * @author K0171746 */ private List<DebtBusinessDayReportWholeAssetVO> queryAsset (String dateDt) { // 获取今年第一个工作日 String bgnDt = workDayService.findYearFirstNaturalDay(dateDt); // 获取去年最后一个工作日 String lastYearFinalWorkDay = workDayService.findLastYearFinalWorkDayStr(dateDt); List<String> bgnDts = workDayService.findTransDts(bgnDt, dateDt); String firstWorkDay = bgnDts.get(0); 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 compareBeginYear, " + "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 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 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.size() < 3) { log.warn("部门 {} 未配置完整的三项业务类型,跳过", dept); continue; } Map<String, BigDecimal> result = CalculateChart1(wholeVO, dept, bizTypes.get(0), bizTypes.get(1), bizTypes.get(2)); for (int i = 0; i < 3; i++) { LiquidReportChart chart = new LiquidReportChart(); chart.setDataDt(dateDt); chart.setReportCode(debtBusinessDayReport); chart.setChartId("char0010"); chart.setRowNum(rowNum++); chart.setCellValue1(dept); // 部门名 chart.setCellValue2(bizTypes.get(i).toString()); // 业务名 chart.setCellValue3(String.valueOf(result.get(bizTypes.get(i)))); // 业务值 chartList.add(chart); } } if (!chartList.isEmpty()) { liquidReportChartRepository.save(chartList); log.info("成功将 {} 条 chart1 ({}) 数据落库", chartList.size(), "char0010"); } else { log.warn("没有有效数据生成 chart1"); } } /** * @Description 计算损益折线图数据 * @author K0171746 */ private Map<String,BigDecimal> CalculateChart1(List<DebtBusinessDayReportWholeAssetVO> wholeVO, String department, String bs1, String bs2, String bs3) { BigDecimal totalYear = BigDecimal.ZERO; BigDecimal totalLastYear = BigDecimal.ZERO; BigDecimal totalDpOrBs1 = BigDecimal.ZERO; BigDecimal totalDpOrBs2 = BigDecimal.ZERO; BigDecimal totalDpOrBs3 = BigDecimal.ZERO; // 遍历列表,逐个累加 for (int i = 0; i < wholeVO.size(); i++) { DebtBusinessDayReportWholeAssetVO vo = wholeVO.get(i); String dept = vo.getDept(); // 精确匹配部门(不去空格) if (!department.equals(dept)) { continue; } // 累加 if (!vo.getProjType().contains("合计")) { totalYear = totalYear.add(vo.getPalYear()); totalLastYear = totalLastYear.add(vo.getCompareLastYearWorkDay()); if (vo.getBusiBigcName().equals(bs1)){ totalDpOrBs1 = totalDpOrBs1.add(vo.getPal()); } if (vo.getBusiBigcName().equals(bs2)){ totalDpOrBs2 = totalDpOrBs2.add(vo.getPal()); } if (vo.getBusiBigcName().equals(bs3)){ totalDpOrBs3 = totalDpOrBs3.add(vo.getPal()); } } } // 封装结果到 Map Map<String, BigDecimal> result = new HashMap<>(); result.put("部门合计(今年)", totalYear); result.put("部门合计(去年)", totalLastYear); result.put(bs1, totalDpOrBs1); result.put(bs2, totalDpOrBs2); result.put(bs3, totalDpOrBs3); return result; } /** * @Description 生成资负规模变化数据 * @author K0171746 */ private void generateChart2(List<DebtBusinessDayReportWholeAssetVO> wholeVO,String dateDt){ String[] fieldKeys = {"bond", "stock", "fund", "indexFutures", "treasuryFutures", "swap", "otcOption"}; String[] displayNames = {"债券", "股票", "基金", "股指期货", "国债期货", "收益互换", "场外期权"}; List<LiquidReportChart> chartList = new ArrayList<>(); int rowNum = 1; for (String dept : departments) { // 调用 chart2 统计该部门各项 P&L Map<String, BigDecimal> result = CalculateChart2(wholeVO, dept); // 内层循环:遍历七种类型(固定7次) for (int i = 0; i < 7; i++) { String fieldKey = fieldKeys[i]; String displayName = displayNames[i]; // 从 result 中取值(手动 get) BigDecimal value = result.get(fieldKey); if (value == null) { value = BigDecimal.ZERO; } // 构造实体对象 LiquidReportChart chart = new LiquidReportChart(); chart.setDataDt(dateDt); chart.setReportCode(debtBusinessDayReport); chart.setChartId("char0020"); chart.setRowNum(rowNum++); chart.setCellValue1(dept); // 部门名称 chart.setCellValue2(displayName); // 业务名称 // 格式化数值:去掉末尾零,转字符串 chart.setCellValue3(value.stripTrailingZeros().toPlainString()); // 添加到列表 chartList.add(chart); } } // 批量落库 + 异常捕获 try { if (!chartList.isEmpty()) { liquidReportChartRepository.save(chartList); log.info("成功将 {} 条 chart2 ({}, date={}) 数据落库", chartList.size(), "chart0020", dateDt); } else { log.warn("没有有效数据生成 chart2 (date={})", dateDt); } } catch (Exception e) { log.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){ BigDecimal totalBond = BigDecimal.ZERO; BigDecimal totalStock = BigDecimal.ZERO; BigDecimal totalFund = BigDecimal.ZERO; BigDecimal totalIndexFutures = BigDecimal.ZERO; BigDecimal totalTreasuryFutures = BigDecimal.ZERO; BigDecimal totalSwap = BigDecimal.ZERO; BigDecimal totalOtcOption = BigDecimal.ZERO; // 遍历列表,逐个累加 for (DebtBusinessDayReportWholeAssetVO vo:wholeVO) { String dept = vo.getDept(); if (department == null || dept == null) { continue; // 如果任一方为 null,跳过 } if (!department.equals(dept)) { continue; // 部门不匹配则跳过 } // 获取项目类型并判空 String projType = vo.getProjType(); if (projType == null) { continue; } // 累加 if (vo.getProjType().equals("债券")){ totalBond = totalBond.add(vo.getPal()); } if (vo.getProjType().equals("股票")){ totalStock = totalStock.add(vo.getPal()); } if (vo.getProjType().equals("基金")){ totalFund = totalFund.add(vo.getPal()); } if (vo.getProjType().equals("股指期货")){ totalIndexFutures = totalIndexFutures.add(vo.getPal()); } if (vo.getProjType().equals("国债期货")){ totalTreasuryFutures = totalTreasuryFutures.add(vo.getPal()); } if (vo.getProjType().equals("收益互换")){ totalSwap = totalSwap.add(vo.getPal()); } if (vo.getProjType().equals("场外期权")){ totalOtcOption = totalOtcOption.add(vo.getPal()); } } // 封装结果到 Map Map<String, BigDecimal> changes = new HashMap<>(); changes.put("bond", totalBond); changes.put("stock", totalStock); changes.put("fund", totalFund); changes.put("indexFutures", totalIndexFutures); changes.put("treasuryFutures", totalTreasuryFutures); changes.put("swap", totalSwap); changes.put("otcOption", totalOtcOption); return changes; } /** * @Description 查询资负表有无当日数据 * @author K0171746 */ private 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(" d_date = ? "); logger.info("查询T_LIQUID_BURDEN_DEPT数据是否为空", sql); return jdbcTemplate.queryForObject(sql.toString(), Integer.class, dateDt); } /** * @Description 生成母公司数据表 * @author K0171746 */ private void generateParent(List<DebtBusinessDayReportWholeAssetVO> wholeVO,String dateDt){ List<DebtBusinessDayReportParentAssetVO> parent = new ArrayList<>(); for (DebtBusinessDayReportWholeAssetVO vo : wholeVO) { // 判空处理 String projType = vo.getProjType(); // 检查是否符合两个条件之一 boolean isTotalLine = projType.contains("合计"); if (!isTotalLine) { continue; // 不符合条件,跳过 } DebtBusinessDayReportParentAssetVO parentVO = new DebtBusinessDayReportParentAssetVO(); parentVO.setDept(vo.getDept()); parentVO.setPal(vo.getPal()); parentVO.setPalMon(vo.getPalMon()); parentVO.setPalYear(vo.getPalYear()); parentVO.setCompareYear(vo.getCompareYear()); parentVO.setProjType(vo.getProjType()); parentVO.setAmt(vo.getAmt()); parentVO.setCompareYesterday(vo.getCompareYesterday()); parentVO.setCompareMon(vo.getCompareMon()); parentVO.setCompareBeginYear(vo.getCompareBeginYear()); parent.add(parentVO); } // 排序 Collections.sort(parent, (a, b) -> { String deptA = a.getDept() == null ? "" : a.getDept().trim(); String deptB = b.getDept() == null ? "" : b.getDept().trim(); // 规则1:a 是母公司 → 排前面(返回 -1) if ("母公司整体".equals(deptA) && !"母公司整体".equals(deptB)) return -1; // 规则2:b 是母公司 → b 排前面(即 a 后移,返回 1) if (!"母公司整体".equals(deptA) && "母公司整体".equals(deptB)) return 1; // 规则3:都不是或都是母公司 → 按部门名升序排序 return deptA.compareTo(deptB); }); int rowNum = 1; List<LiquidReportChart> chartList = new ArrayList<>(); for (DebtBusinessDayReportParentAssetVO vo : parent) { String deptName = vo.getDept(); // 当前部门名 addField(chartList, deptName, "单日损益", String.valueOf(vo.getPal()), dateDt, debtBusinessDayReport, rowNum++); addField(chartList, deptName, "本月损益累计", String.valueOf(vo.getPalMon()), dateDt, debtBusinessDayReport, rowNum++); addField(chartList, deptName, "年度损益累计", String.valueOf(vo.getPalYear()), dateDt, debtBusinessDayReport, rowNum++); addField(chartList, deptName, "较上年同期", String.valueOf(vo.getCompareYear()), dateDt, debtBusinessDayReport, rowNum++); addField(chartList, deptName, "资负类别", String.valueOf(vo.getProjType()), dateDt, debtBusinessDayReport, rowNum++); addField(chartList, deptName, "本日规模", String.valueOf(vo.getAmt()), dateDt, debtBusinessDayReport, rowNum++); addField(chartList, deptName, "较上日变化", String.valueOf(vo.getCompareYesterday()), dateDt, debtBusinessDayReport, rowNum++); addField(chartList, deptName, "较上月末变化", String.valueOf(vo.getCompareMon()), dateDt, debtBusinessDayReport, rowNum++); addField(chartList, deptName, "较年初变化", String.valueOf(vo.getCompareBeginYear()), dateDt, debtBusinessDayReport, rowNum++); } try { if (!chartList.isEmpty()) { liquidReportChartRepository.save(chartList); log.info("成功将 {} 条 chart2 ({}, date={}) 数据落库", chartList.size(), "chart0030", dateDt); } else { log.warn("没有有效数据生成 chart3 (date={})", dateDt); } } catch (Exception e) { log.error("保存 chart3 数据时发生异常 (date={})", dateDt, e); throw new RuntimeException("Failed to save chart3 data", e); } } /** * @Description 表格计算公式 * @author K0171746 */ private void addField(List<LiquidReportChart> chartList, String deptName, String fieldName, String fieldValue, String dateDt, String reportCode, int rowNum) { LiquidReportChart chart = new LiquidReportChart(); chart.setDataDt(dateDt); chart.setReportCode(reportCode); chart.setChartId("char0030"); // 固定图表ID(可配置) chart.setRowNum(rowNum); chart.setCellValue1(deptName); // 维度1: 部门 chart.setCellValue2(fieldName); // 维度2: 指标名称 chart.setCellValue3(fieldValue); // 指标值(字符串化) chartList.add(chart); } /** * @Description 母公司计算部门数据表 * @author K0171746 */ private List<DebtBusinessDayReportDpAssetVO> CalculateDpAsset(List<DebtBusinessDayReportWholeAssetVO> wholeVO, String department){ // 参数校验 if (wholeVO == null || wholeVO.isEmpty()) { logger.warn("输入数据为空,无法生成部门资负数据"); return new ArrayList<>(); } if (department == null || department.isEmpty()) { logger.warn("目标部门列表为空,返回空结果"); return new ArrayList<>(); } // 生成部门资负数据 List<DebtBusinessDayReportDpAssetVO> assetVOS = new ArrayList<>(); for (DebtBusinessDayReportWholeAssetVO vo : wholeVO) { // 跳过 null 记录 if (vo == null) continue; String dept = vo.getDept(); // 跳过 dept 为 null 的记录 if (dept == null) { logger.debug("发现 dept 为 null 的记录,已跳过"); continue; } // 判断是否在目标部门列表中 if (department.contains(dept)) { DebtBusinessDayReportDpAssetVO dpVO = new DebtBusinessDayReportDpAssetVO(); dpVO.setDept(dept); dpVO.setBusiBigcName(vo.getBusiBigcName()); dpVO.setBusiSmlcName(vo.getBusiSmlcName()); dpVO.setPal(vo.getPal()); dpVO.setPalMon(vo.getPalMon()); dpVO.setPalYear(vo.getPalYear()); dpVO.setProjType(vo.getProjType()); dpVO.setAmt(vo.getAmt()); dpVO.setCompareYesterday(vo.getCompareYesterday()); dpVO.setCompareMon(vo.getCompareMon()); dpVO.setCompareBeginYear(vo.getCompareBeginYear()); dpVO.setCompareLastYearWorkDay(vo.getCompareLastYearWorkDay()); assetVOS.add(dpVO); } } return assetVOS; } /** * @Description 生成各部门数据表 * @author K0171746 */ private void generateDpAsset(List<DebtBusinessDayReportWholeAssetVO> wholeVO,String dateDt){ // 1. 参数校验 if (CollectionUtils.isEmpty(wholeVO)) { logger.warn("输入的 wholeVO 数据为空,跳过 generateDpAsset 处理"); return; } if (dateDt == null || dateDt.trim().isEmpty()) { logger.error("日期 dateDt 不能为空"); throw new IllegalArgumentException("dateDt is required"); } List<LiquidReportChart> chartList = new ArrayList<>(); int rowNum = 1; // 2. 遍历每一个目标部门 for (String dept : departments) { for (DebtBusinessDayReportWholeAssetVO vo : wholeVO) { // 跳过 null 或不匹配部门的数据 if (vo == null || vo.getDept() == null || !dept.equals(vo.getDept())) { continue; } // 获取业务维度 String busiBigcName = vo.getBusiBigcName(); String busiSmlcName = vo.getBusiSmlcName(); // 添加多个指标字段 addField(chartList, dept, busiBigcName, busiSmlcName, "单日损益", String.valueOf((vo.getPal())), dateDt, "char0040", rowNum++); addField(chartList, dept, busiBigcName, busiSmlcName, "本月损益累计", String.valueOf(vo.getPalMon()), dateDt, "char0040", rowNum++); addField(chartList, dept, busiBigcName, busiSmlcName, "年度损益累计", String.valueOf(vo.getPalYear()), dateDt, "char0040", rowNum++); addField(chartList, dept, busiBigcName, busiSmlcName, "资负类别", String.valueOf(vo.getProjType()), dateDt, "char0040", rowNum++); addField(chartList, dept, busiBigcName, busiSmlcName, "本日规模", String.valueOf(vo.getAmt()), dateDt, "char0040", rowNum++); addField(chartList, dept, busiBigcName, busiSmlcName, "较上日变化", String.valueOf(vo.getCompareYesterday()), dateDt, "char0040", rowNum++); addField(chartList, dept, busiBigcName, busiSmlcName, "较上月末变化", String.valueOf(vo.getCompareMon()), dateDt, "char0040", rowNum++); addField(chartList, dept, busiBigcName, busiSmlcName, "较年初变化", String.valueOf(vo.getCompareBeginYear()), dateDt, "char0040", rowNum++); } } // 3. 落地入库 try { if (!chartList.isEmpty()) { liquidReportChartRepository.save(chartList); log.info("成功将 {} 条部门明细数据 ({}, date={}) 落库", chartList.size(), "char0040", dateDt); } else { log.warn("没有有效数据生成部门明细表 (date={})", dateDt); } } catch (Exception e) { log.error("保存部门明细数据时发生异常 (date={})", dateDt, e); throw new RuntimeException("Failed to save department asset detail data", e); } } /** * @Description 部门表格计算公式 * @author K0171746 */ private void addField(List<LiquidReportChart> list, String dept, String busiBigcName, String busiSmlcName, String metricName, String metricValue, String dateDt, String chartId, int rowNum) { LiquidReportChart chart = new LiquidReportChart(); chart.setDataDt(dateDt); chart.setReportCode(debtBusinessDayReport); chart.setChartId(chartId); chart.setRowNum(rowNum); chart.setCellValue1(dept); // 第一列:部门 chart.setCellValue2(busiBigcName); // 第二列:业务大类 chart.setCellValue3(busiSmlcName); // 第三列:业务小类 chart.setCellValue4(metricName); // 业务字段 chart.setCellValue5(metricValue); // 字段值 list.add(chart); } /** * @Description 查询日报 * @author K0171746 */ public LiquidAssetDailyReportResultVO getReport(String dateDt, String department) { return null; } } 这是修改后的,根据这个生成getReport方法
最新发布
10-28
package com.msxf.pai.agent.workflow.application.listeners; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.ObjectUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.google.gson.*; import com.msxf.eyas.thread.MsxfRunnable; import com.msxf.pai.agent.agents.application.service.autoagent.AutoAgentChatItemDetailServiceImpl; import com.msxf.pai.agent.agents.application.service.autoagent.AutoAgentChatItemServiceImpl; import com.msxf.pai.agent.agents.application.service.autoagent.AutoAgentChatServiceImpl; import com.msxf.pai.agent.agents.domain.po.AutoAgentChat; import com.msxf.pai.agent.agents.domain.po.AutoAgentChatItem; import com.msxf.pai.agent.agents.domain.po.AutoAgentChatItemDetail; import com.msxf.pai.agent.common.entity.constant.MessageKeyConstants; import com.msxf.pai.agent.common.thread.ExecutorUtil; import com.msxf.pai.agent.common.utils.MessageUtils; import com.msxf.pai.agent.common.utils.SpringUtils; import com.msxf.pai.agent.common.utils.UuidUtil; import com.msxf.pai.agent.serving.application.util.SSEUtils; import com.msxf.pai.agent.serving.domain.enums.SseResponseEventEnum; import com.msxf.pai.agent.workflow.application.client.dto.autoagent.*; import com.msxf.pai.agent.workflow.domain.enums.AutoAgentChatTypeEnum; import com.msxf.pai.common.domain.dto.SessionUserInfo; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import okhttp3.Response; import okhttp3.sse.EventSource; import okhttp3.sse.EventSourceListener; import org.jetbrains.annotations.NotNull; import javax.annotation.Nullable; import java.util.*; import java.util.concurrent.*; @Slf4j public class AutoAgentChatSSEListener extends EventSourceListener { private final SessionUserInfo userInfo; private final AutoAgentData dto; private final Boolean chatType; private final String reqId; private final CountDownLatch latch; @Getter private Integer runStatus = 1; private final Map<String, List<AutoAgentRagVO>> ragMapLists = new ConcurrentHashMap<>(); private final List<AutoAgentRagVO> ragVOLists = new CopyOnWriteArrayList<>(); private final List<String> events = new CopyOnWriteArrayList<>(); private long eventStartTime = System.currentTimeMillis(); // 添加时间戳变量 private long totalTime; //总耗时 private final ScheduledExecutorService scheduler; private final String chatItemId = UuidUtil.getUUID(); //默认ai回答id public AutoAgentChatSSEListener(SessionUserInfo userInfo, AutoAgentData dto, CountDownLatch latch, ScheduledExecutorService scheduler) { this.reqId = dto.getAgentData().getRequestId(); this.chatType = dto.getAgentData().getDraftMode(); this.userInfo = userInfo; this.dto = dto; this.scheduler = scheduler; this.latch = latch; } @Override public void onOpen(@NotNull EventSource eventSource, @NotNull Response response) { super.onOpen(eventSource, response); log.info("connect to rag success:{}", response); } @Override public void onEvent(@NotNull EventSource eventSource, String id, String type, @NotNull String data) { log.info("auto agent chat rag send requestId:{}, id:{},type:{},data {}:", reqId, id, type, data); if (StringUtils.isNotBlank(data)) { events.add(data); AutoAgentRagVO agentRagVO = new AutoAgentRagVO(); long currentTime = System.currentTimeMillis(); // 计算间隔时间 long time = currentTime - eventStartTime; // 更新时间戳 eventStartTime = currentTime; totalTime = totalTime + time; agentRagVO.setTime(time); agentRagVO.setChatItemId(chatItemId); JsonObject jsonObject = JsonParser.parseString(data).getAsJsonObject(); JsonElement content = null; if (jsonObject.has(AutoAgentChatTypeEnum.CONTENT.getValue()) && !jsonObject.get(AutoAgentChatTypeEnum.CONTENT.getValue()).isJsonNull()) { content = jsonObject.get(AutoAgentChatTypeEnum.CONTENT.getValue()); } getResult(jsonObject, agentRagVO); if (ObjectUtils.isNotEmpty(agentRagVO.getError_message()) || ObjectUtils.isNotEmpty(agentRagVO.getError_code())) { runStatus = 0; if (dto.getStream()) { SSEUtils.pubMsg(reqId, AutoAgentChatTypeEnum.ERROR.getValue(), JSONObject.toJSONString(agentRagVO.getError_message())); } log.info("error_message : {}", JSONObject.toJSONString(agentRagVO.getError_message())); } else { CustomMetadata customMetadata = null; if (jsonObject.has(AutoAgentChatTypeEnum.CUSTOM_METADATA.getValue()) && !jsonObject.get(AutoAgentChatTypeEnum.CUSTOM_METADATA.getValue()).isJsonNull()) { JsonObject customMetadataJsonObject = jsonObject.get(AutoAgentChatTypeEnum.CUSTOM_METADATA.getValue()).getAsJsonObject(); // 使用Gson将JsonObject反序列化为customMetadata类实例 Gson gson = new Gson(); customMetadata = gson.fromJson(customMetadataJsonObject, CustomMetadata.class); } if (jsonObject.has(AutoAgentChatTypeEnum.TIMESTAMP.getValue()) && !jsonObject.get(AutoAgentChatTypeEnum.TIMESTAMP.getValue()).isJsonNull()) { long asLong = jsonObject.get(AutoAgentChatTypeEnum.TIMESTAMP.getValue()).getAsLong(); agentRagVO.setTimestamp(asLong); } agentRagVO.setCustom_metadata(customMetadata); writeRagVo(jsonObject, content, agentRagVO); agentRagVO.setId(ObjectUtils.isEmpty(customMetadata.getId()) ? UuidUtil.getUUID() : customMetadata.getId()); if (dto.getStream()) { List<RagFunctionResponse> functionResponse = agentRagVO.getFunction_response(); if (CollectionUtils.isNotEmpty(functionResponse)) { List<String> errorMessage = new ArrayList<>(); for (RagFunctionResponse ragFunctionResponse : functionResponse) { String error_message = ragFunctionResponse.getResponse().getError_message(); if (ObjectUtils.isNotEmpty(error_message)) { errorMessage.add(error_message); } } if (CollectionUtils.isNotEmpty(errorMessage)) { SSEUtils.pubMsg(reqId, AutoAgentChatTypeEnum.TOOL_ERROR.getValue(), JSONObject.toJSONString(agentRagVO)); } else { pushMessage(customMetadata, agentRagVO); } } else { pushMessage(customMetadata, agentRagVO); } } } ragVOLists.add(agentRagVO); ragMapLists.put(reqId, ragVOLists); } } private void pushMessage(CustomMetadata customMetadata, AutoAgentRagVO agentRagVO) { if (!ObjectUtils.isEmpty(customMetadata.getIs_runner_start()) && customMetadata.getIs_runner_start()) { SSEUtils.pubMsg(reqId, AutoAgentChatTypeEnum.START.getValue(), JSONObject.toJSONString(agentRagVO)); } else if (!ObjectUtils.isEmpty(customMetadata.getIs_runner_final()) && customMetadata.getIs_runner_final()) { SSEUtils.pubMsg(reqId, AutoAgentChatTypeEnum.END.getValue(), JSONObject.toJSONString(agentRagVO)); } else { SSEUtils.pubMsg(reqId, customMetadata.getType(), JSONObject.toJSONString(agentRagVO)); } } @Override public void onClosed(@NotNull EventSource eventSource) { scheduler.shutdown(); if (!dto.getStream()) { latch.countDown(); } else { SSEUtils.complete(reqId); } log.info("****** : sse close : *******"); List<AutoAgentRagVO> ragVO = getRagVO(reqId); if (!CollectionUtils.isEmpty(ragVO) && !chatType) { CompletableFuture.runAsync(new MsxfRunnable(() -> { try { asyncSaveChat(ragVO); } catch (Exception e) { log.error("save autoagent chat data fail ", e); } }), ExecutorUtil.antoAgentChatExecutor); } } @Override public void onFailure(@NotNull EventSource eventSource, @Nullable Throwable t, @Nullable Response response) { scheduler.shutdown(); String s = t != null ? t.getMessage() : response != null ? response.toString() : ""; runStatus = 0; String msg = MessageUtils.getMessage(MessageKeyConstants.MESSAGE_API_APP_SERVING_DSLSSELISTENER_QINGQIU_DUIHUA_JIEKOU_YICHANG_YICHANG_XINXI) + s; log.error("response : {}", response); JSONObject out = new JSONObject(); out.put("message", msg); if (!dto.getStream()) { AutoAgentRagVO agentRagVO = new AutoAgentRagVO(); agentRagVO.setError_message(msg); agentRagVO.setError_code("600"); ragVOLists.add(agentRagVO); ragMapLists.put(reqId, ragVOLists); latch.countDown(); throw new RuntimeException(out.toString()); } else { SSEUtils.pubMsg(reqId, SseResponseEventEnum.ERROR.getValue(), out.toString()); SSEUtils.complete(reqId); } ragVOLists.clear(); ragMapLists.clear(); } private void asyncSaveChat(List<AutoAgentRagVO> ragVO) { String chatId = dto.getAgentData().getChatId(); AutoAgentChatServiceImpl autoAgentChatService = (AutoAgentChatServiceImpl) SpringUtils.getBean("autoAgentChatServiceImpl"); AutoAgentChat autoAgentChat = autoAgentChatService.findByChatId(chatId); if (ObjectUtils.isEmpty(autoAgentChat)) { String value = dto.getAgentData().getQuestion(); if (value.length() > 30) { value = value.substring(0, 30) + "..."; } AutoAgentChat agentChat = AutoAgentChat.builder() .agentId(dto.getAgentId()) .chatId(chatId) .chatTitle(value) .chatSource(dto.getSource()) .createBy(String.valueOf(userInfo.getUserId())) .updateBy(String.valueOf(userInfo.getUserId())) .userId(String.valueOf(userInfo.getUserId())) .userName(userInfo.getUserName()) .createTime(new Date()) .updateTime(new Date()) .teamId(String.valueOf(userInfo.getOrgId())) .tenantId(userInfo.getTenantCode()) .teamName(userInfo.getOrgCode()) .runStatus(runStatus) .agentVersion(dto.getVersion()) .build(); // 保存对话表 autoAgentChatService.save(agentChat); } saveItem(dto, userInfo, ragVO, autoAgentChat); } private void saveItem(AutoAgentData dto, SessionUserInfo userInfo, List<AutoAgentRagVO> ragVO, AutoAgentChat autoAgentChat) { AutoAgentChatItemServiceImpl autoAgentChatItemService = (AutoAgentChatItemServiceImpl) SpringUtils.getBean("autoAgentChatItemServiceImpl"); AutoAgentChatItemDetailServiceImpl autoAgentChatItemDetailService = (AutoAgentChatItemDetailServiceImpl) SpringUtils.getBean("autoAgentChatItemDetailServiceImpl"); String chatId = dto.getAgentData().getChatId(); List<AutoAgentChatItem> items = new ArrayList<>(); List<AutoAgentChatItemDetail> itemDetails = com.google.common.collect.Lists.newArrayList(); String chatItemId = UuidUtil.getUUID(); String traceId = dto.getAgentData().getRequestId(); AutoAgentChatItem itemUser = AutoAgentChatItem.builder() .agentId(dto.getAgentId()) .chatId(chatId) .chatObj("Human") .chatItemId(chatItemId) .traceId(traceId) .chatValue(dto.getAgentData().getQuestion()) .createBy(String.valueOf(userInfo.getUserId())) .updateBy(String.valueOf(userInfo.getUserId())) .userId(String.valueOf(userInfo.getUserId())) .userName(userInfo.getUserName()) .createTime(new Date()) .updateTime(new Date()) .teamId(String.valueOf(userInfo.getOrgId())) .tenantId(userInfo.getTenantCode()) .teamName(userInfo.getOrgCode()) .globalVariables(dto.getVariables()) .runningTime(totalTime) .build(); if (CollectionUtils.isNotEmpty(dto.getFileList())) { itemUser.setChatFileInfo(JSON.parseArray(JSON.toJSONString(dto.getFileList()))); } items.add(itemUser); for (AutoAgentRagVO autoAgentRagVO : ragVO) { CustomMetadata customMetadata = autoAgentRagVO.getCustom_metadata(); if (!ObjectUtils.isEmpty(customMetadata) && !ObjectUtils.isEmpty(customMetadata.getIs_runner_final()) && customMetadata.getIs_runner_final()) { String itemId = autoAgentRagVO.getChatItemId(); AutoAgentChatItem itemAi = BeanUtil.copyProperties(itemUser, AutoAgentChatItem.class); itemAi.setChatObj("AI"); itemAi.setChatValue(autoAgentRagVO.getFinalResult()); itemAi.setChatItemId(itemId); items.add(itemAi); } } if (ragVO.size() == 1) { AutoAgentRagVO agentRagVO = ragVO.get(0); if (ObjectUtil.isNotEmpty(agentRagVO.getError_message())) { String itemId = agentRagVO.getChatItemId(); AutoAgentChatItem itemAi = BeanUtil.copyProperties(itemUser, AutoAgentChatItem.class); itemAi.setChatObj("FAIL"); itemAi.setChatValue(agentRagVO.getError_message()); itemAi.setChatItemId(itemId); items.add(itemAi); } } if (CollectionUtils.isNotEmpty(events)) { for (int i = 0; i < events.size(); i++) { AutoAgentChatItemDetail detail = createAutoAgentChatDetail(userInfo, traceId, chatItemId); detail.setDetailData(events.get(i)); detail.setExecuteTime(ObjectUtils.isEmpty(ragVO.get(i).getTime()) ? 0L : ragVO.get(i).getTime()); itemDetails.add(detail); } } autoAgentChatItemService.saveBatch(items); autoAgentChatItemDetailService.saveBatch(itemDetails); if (ObjectUtil.isNotEmpty(autoAgentChat)) { autoAgentChat.setUpdateTime(new Date()); autoAgentChat.setUpdateBy(String.valueOf(userInfo.getUserId())); } events.clear(); } @NotNull private static AutoAgentChatItemDetail createAutoAgentChatDetail(SessionUserInfo userInfo, String traceId, String chatItemId) { AutoAgentChatItemDetail detail = new AutoAgentChatItemDetail(); detail.setDetailId(IdUtil.fastSimpleUUID()); detail.setCreateBy(String.valueOf(userInfo.getUserId())); detail.setCreateTime(new Date()); detail.setUpdateTime(new Date()); detail.setUpdateBy(String.valueOf(userInfo.getUserId())); detail.setItemId(chatItemId); detail.setTraceId(traceId); return detail; } public List<AutoAgentRagVO> getRagVO(String reqId) { return CollectionUtils.isEmpty(ragMapLists.get(reqId)) ? Collections.emptyList() : ragMapLists.get(reqId); } private static void writeRagVo(JsonObject jsonObject, JsonElement content, AutoAgentRagVO agentRagVO) { if (jsonObject.has(AutoAgentChatTypeEnum.CONTENT.getValue()) && !content.isJsonNull()) { JsonArray parts = content.getAsJsonObject().get(AutoAgentChatTypeEnum.PARTS.getValue()).getAsJsonArray(); List<RagFunctionCall> functionCall = new CopyOnWriteArrayList<>(); List<RagFunctionResponse> functionResponse = new CopyOnWriteArrayList<>(); parts.forEach(o -> { JsonObject part = o.getAsJsonObject(); if (!part.get(AutoAgentChatTypeEnum.FUNCTION_CALL.getValue()).isJsonNull()) { JsonObject asJsonObject = part.get(AutoAgentChatTypeEnum.FUNCTION_CALL.getValue()).getAsJsonObject(); RagFunctionCall functionCall1 = getRagFunctionCall(asJsonObject); functionCall.add(functionCall1); } if (!part.get(AutoAgentChatTypeEnum.FUNCTION_RESPONSE.getValue()).isJsonNull()) { RagFunctionResponse ragFunctionResponse = getRagFunctionResponse(part); functionResponse.add(ragFunctionResponse); } if (!part.get(AutoAgentChatTypeEnum.TEXT.getValue()).isJsonNull() && (!part.get(AutoAgentChatTypeEnum.THOUGHT.getValue()).isJsonNull() && part.get(AutoAgentChatTypeEnum.THOUGHT.getValue()).getAsBoolean())) { agentRagVO.setThinkResult(part.get(AutoAgentChatTypeEnum.TEXT.getValue()).getAsString()); } if (!part.get(AutoAgentChatTypeEnum.TEXT.getValue()).isJsonNull() && part.get(AutoAgentChatTypeEnum.THOUGHT.getValue()).isJsonNull()) { agentRagVO.setFinalResult(part.get(AutoAgentChatTypeEnum.TEXT.getValue()).getAsString()); } }); Optional.of(functionCall).ifPresent(agentRagVO::setFunction_call); Optional.of(functionResponse).ifPresent(agentRagVO::setFunction_response); } } @NotNull private static RagFunctionCall getRagFunctionCall(JsonObject asJsonObject) { RagFunctionCall functionCall1 = new RagFunctionCall(); String id = asJsonObject.get("id").isJsonNull() ? null : asJsonObject.get("id").getAsString(); String name = asJsonObject.get("name").isJsonNull() ? null : asJsonObject.get("name").getAsString(); JsonObject args = asJsonObject.get("args").isJsonNull() ? null : asJsonObject.get("args").getAsJsonObject(); functionCall1.setArgs(args != null ? args.toString() : ""); functionCall1.setName(name); functionCall1.setId(id); return functionCall1; } @NotNull private static RagFunctionResponse getRagFunctionResponse(JsonObject part) { RagFunctionResponse ragFunctionResponse = new RagFunctionResponse(); RagResponse ragResponse = new RagResponse(); JsonObject asJsonObject = part.get(AutoAgentChatTypeEnum.FUNCTION_RESPONSE.getValue()).getAsJsonObject(); String id = asJsonObject.get("id").isJsonNull() ? null : asJsonObject.get("id").getAsString(); String name = asJsonObject.get("name").isJsonNull() ? null : asJsonObject.get("name").getAsString(); String scheduling = asJsonObject.get("scheduling").isJsonNull() ? null : asJsonObject.get("scheduling").getAsString(); String willContinue = asJsonObject.get("will_continue").isJsonNull() ? null : asJsonObject.get("will_continue").getAsString(); JsonObject response = asJsonObject.get(AutoAgentChatTypeEnum.RESPONSE.getValue()).isJsonNull() ? null : asJsonObject.get("response").getAsJsonObject(); String errorMessage = null; String result = null; String toolType = null; if (response != null) { errorMessage = response.get(AutoAgentChatTypeEnum.ERROR_MESSAGE.getValue()).isJsonNull() ? null : response.get("error_message").getAsString(); result = response.get("result").isJsonNull() ? null : response.get("result").getAsString(); toolType = response.get("tool_type").isJsonNull() ? null : response.get("tool_type").getAsString(); } ragFunctionResponse.setId(id); ragFunctionResponse.setName(name); ragFunctionResponse.setScheduling(scheduling); ragFunctionResponse.setWill_continue(willContinue); ragResponse.setError_message(errorMessage); ragResponse.setResult(result); ragResponse.setTool_type(toolType); ragFunctionResponse.setResponse(ragResponse); return ragFunctionResponse; } private static void getResult(JsonObject jsonObject, AutoAgentRagVO agentRagVO) { String errorCode = jsonObject.has(AutoAgentChatTypeEnum.ERROR_CODE.getValue()) && !jsonObject.get(AutoAgentChatTypeEnum.ERROR_CODE.getValue()).isJsonNull() ? jsonObject.get(AutoAgentChatTypeEnum.ERROR_CODE.getValue()).getAsString() : null; agentRagVO.setError_code(errorCode); String error_message = jsonObject.has(AutoAgentChatTypeEnum.ERROR_MESSAGE.getValue()) && !jsonObject.get(AutoAgentChatTypeEnum.ERROR_MESSAGE.getValue()).isJsonNull() ? jsonObject.get(AutoAgentChatTypeEnum.ERROR_MESSAGE.getValue()).getAsString() : null; agentRagVO.setError_message(error_message); } } 这个是我的业务代码,请帮我优化一下代码,减少重复代码并将解析工具统一为gson
10-23
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值