leniu-tengyun-core 合计行(Total Line)规范
项目特征
特征 说明
包名前缀 net.xnzn.core.*
JDK 版本 21
双库切换 默认商户库,Executors.doInSystem() 切换系统库
分页工具 PageMethod.startPage()
结果封装 ReportBaseTotalVO<T>
分页封装 PageVO.of()
核心原则
合计行SQL只返回需要合计的数值字段,不返回非数值字段(如日期、名称、ID等)。
Service层实现
带合计行的分页查询
import net.xnzn.core.common.page.PageMethod; import net.xnzn.core.common.page.PageVO; import net.xnzn.core.common.vo.ReportBaseTotalVO; import cn.hutool.core.collection.CollUtil;
// ⚠️ 系统默认在商户库执行,业务查询无需 Executors.readInSystem() // Executors.readInSystem() 仅用于需要访问系统库的场景(如全局配置、商户管理)
public ReportBaseTotalVO<XxxVO> pageWithTotal(XxxPageParam param) { ReportBaseTotalVO<XxxVO> result = new ReportBaseTotalVO<>();
// 1. 导出时不查询合计行(避免不必要的性能开销)
if (CollUtil.isEmpty(param.getExportCols())) {
XxxVO totalLine = mapper.getSummaryTotal(param);
result.setTotalLine(totalLine);
}
// 2. 开启分页
PageMethod.startPage(param.getPage());
// 3. 查询数据
List<XxxVO> list = mapper.getSummaryList(param);
// 4. 封装分页结果
result.setResultPage(PageVO.of(list));
return result;
}
单独的合计行查询方法
public XxxVO getSummaryTotal(XxxPageParam param) { // 默认在商户库执行,无需 Executors 包装 return mapper.getSummaryTotal(param); }
Mapper XML规范
错误示例:返回非数值字段
<!-- ❌ 不要这样做 --> <select id="getSummaryTotal" resultType="XxxVO"> SELECT '合计' AS dateMonth, <!-- ❌ 不要返回字符串 --> NULL AS schoolId, <!-- ❌ 不要返回ID --> NULL AS schoolName, <!-- ❌ 不要返回名称 --> SUM(staffCount) AS staffCount, SUM(amount) AS amount FROM xxx_table </select>
正确示例:只返回数值字段
<!-- ✅ 正确做法 --> <select id="getSummaryTotal" resultType="XxxVO"> SELECT SUM(staff_count) AS staffCount, SUM(basic_salary) AS basicSalary, SUM(overtime_salary) AS overtimeSalary, SUM(personal_actual_amount) AS personalActualAmount, CASE WHEN SUM(staff_count) = 0 THEN 0 ELSE SUM(avg_salary) / COUNT(DISTINCT tenant_id) END AS avgSalary FROM xxx_table <where> del_flag = 2 <if test="startDate != null"> AND crtime >= #{startDate} </if> <if test="endDate != null"> AND crtime <= #{endDate} </if> </where> </select>
常见合计字段类型
字段类型 示例 合计方式
数量 staff_count , order_count
SUM()
金额 amount , salary
SUM()
百分比 discount_rate
AVG() 或 SUM() / COUNT()
计数 COUNT(DISTINCT id)
直接使用
特殊处理:平均值
<!-- 简单平均值 --> SELECT AVG(amount) AS avgAmount
<!-- 加权平均值 --> SELECT CASE WHEN SUM(count) = 0 THEN 0 ELSE SUM(amount * count) / SUM(count) END AS weightedAvgAmount
<!-- 按维度平均 --> SELECT CASE WHEN COUNT(DISTINCT tenant_id) = 0 THEN 0 ELSE SUM(total_amount) / COUNT(DISTINCT tenant_id) END AS avgByTenant
Controller层实现
@PostMapping("/page") @ApiOperation("分页查询(带合计)") @RequiresAuthentication public ReportBaseTotalVO<XxxVO> page(@RequestBody LeRequest<XxxParam> request) { XxxParam param = request.getContent(); return xxxService.pageWithTotal(param); }
@GetMapping("/total") @ApiOperation("单独查询合计行") @RequiresAuthentication public XxxVO getTotal(XxxParam param) { return xxxService.getSummaryTotal(param); }
导出时合计行处理
public void exportExcel(XxxParam param, HttpServletResponse response) { // 导出时需要查询合计行 XxxVO totalLine = mapper.getSummaryTotal(param);
// 分页查询所有数据(不分页)
param.getPage().setSize(Integer.MAX_VALUE);
List<XxxVO> list = mapper.getSummaryList(param);
// 将合计行添加到列表末尾
list.add(totalLine);
// 导出
exportService.export(list, response);
}
注意事项
-
合计SQL只返回数值字段,不返回字符串、ID、名称等
-
业务查询默认在商户库执行,无需 Executors 包装;仅访问系统库数据时才使用 Executors.doInSystem()
-
导出时通过 exportCols 判断是否需要合计行
-
金额字段类型与 Entity 保持一致:订单模块用 BigDecimal ,钱包模块用 Long (详见 leniu-java-amount-handling)