skills/xu-cell/ai-engineering-init/leniu-java-total-line

leniu-java-total-line

SKILL.md

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 &lt;= #{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)
Weekly Installs
3
GitHub Stars
8
First Seen
7 days ago
Installed on
gemini-cli3
github-copilot3
codex3
kimi-cli3
cursor3
amp3