动态透视报表 + 查询接口 + Excel导出

下面给你一套 企业报表常用的 EasyExcel 完整样式方案 ,在你现在的
SpringBoot + MyBatis + GaussDB + EasyExcel + SQL透视 的基础上增加:

实现效果:

  • ✔ 动态表头
  • ✔ a / f 子表头
  • ✔ 最后一行合计(Java计算)
  • ✔ 合计单元格合并
  • ✔ 合计居中
  • ✔ 表头居中
  • ✔ 自动列宽
  • ✔ 冻结表头
  • ✔ 数值千分位
  • ✔ 导出 Excel 类似数据透视表效果

一、Excel导出效果

最终 Excel:

复制代码
产品  型号  项目  1月  2月  3月  4月  5月  合计
               a   a   a   f   f
A     A1   P1  10  20  30  40  50  150
B     B1   P1  20  40  60  80 100  300
合计           30  60  90 120 150  450

特点:

  • 前三列合并为"合计"
  • 数值自动格式
  • 表头冻结

二、合计行计算(Java)

java 复制代码
public static List<Object> buildTotalRow(
        List<String> rowDims,
        List<String> cols,
        List<Map<String,Object>> data){

    List<Object> row = new ArrayList<>();

    for(int i=0;i<rowDims.size();i++){
        row.add("");
    }

    row.set(0,"合计");

    Map<String,Double> sum=new HashMap<>();

    for(String c:cols){
        sum.put(c,0.0);
    }

    double total=0;

    for(Map<String,Object> r:data){

        for(String c:cols){

            double v = r.get(c)==null ?
                    0 : Double.parseDouble(r.get(c).toString());

            sum.put(c,sum.get(c)+v);
        }

        total += Double.parseDouble(r.get("total").toString());
    }

    for(String c:cols){
        row.add(sum.get(c));
    }

    row.add(total);

    return row;
}

三、合计行单元格合并

创建合并策略:

java 复制代码
public class TotalMergeStrategy extends AbstractMergeStrategy {

    private int totalRow;
    private int mergeCol;

    public TotalMergeStrategy(int totalRow,int mergeCol){
        this.totalRow=totalRow;
        this.mergeCol=mergeCol;
    }

    @Override
    protected void merge(
            Sheet sheet,
            Cell cell,
            Head head,
            Integer relativeRowIndex){

        if(cell.getRowIndex()==totalRow
                && cell.getColumnIndex()==0){

            CellRangeAddress region =
                    new CellRangeAddress(
                            totalRow,
                            totalRow,
                            0,
                            mergeCol);

            sheet.addMergedRegion(region);
        }
    }
}

四、表头居中样式

java 复制代码
public class HeadStyleStrategy
        extends AbstractCellStyleStrategy {

    @Override
    protected void setHeadCellStyle(
            CellWriteHandlerContext context){

        CellStyle style =
                context.getCell()
                .getSheet()
                .getWorkbook()
                .createCellStyle();

        style.setAlignment(HorizontalAlignment.CENTER);
        style.setVerticalAlignment(VerticalAlignment.CENTER);

        Font font =
                context.getCell()
                .getSheet()
                .getWorkbook()
                .createFont();

        font.setBold(true);

        style.setFont(font);

        context.getCell().setCellStyle(style);
    }
}

五、数值千分位格式

java 复制代码
public class NumberStyleStrategy
        extends AbstractCellStyleStrategy {

    @Override
    protected void setContentCellStyle(
            CellWriteHandlerContext context){

        if(context.getCell().getColumnIndex()>2){

            CellStyle style =
                    context.getCell()
                    .getSheet()
                    .getWorkbook()
                    .createCellStyle();

            style.setDataFormat(
                    context.getCell()
                    .getSheet()
                    .getWorkbook()
                    .createDataFormat()
                    .getFormat("#,##0"));

            style.setAlignment(HorizontalAlignment.RIGHT);

            context.getCell().setCellStyle(style);
        }
    }
}

六、自动列宽

EasyExcel自带策略:

java 复制代码
LongestMatchColumnWidthStyleStrategy

使用:

java 复制代码
.registerWriteHandler(
    new LongestMatchColumnWidthStyleStrategy()
)

七、冻结表头

java 复制代码
public class FreezePaneHandler
        implements SheetWriteHandler {

    @Override
    public void afterSheetCreate(
            WriteWorkbookHolder holder,
            WriteSheetHolder sheetHolder){

        sheetHolder.getSheet()
                .createFreezePane(0,2);
    }
}

说明:

复制代码
冻结前2行表头

八、完整导出代码

java 复制代码
@PostMapping("/export")
public void export(HttpServletResponse response) throws Exception{

    Map<String,Object> result = service.query();

    List<String> cols =
            (List<String>)result.get("cols");

    List<Map<String,Object>> data =
            (List<Map<String,Object>>)result.get("rows");

    List<List<String>> head =
            ExcelBuilder.buildHead(rowDims,cols,typeMap);

    List<List<Object>> rows =
            ExcelBuilder.buildRows(rowDims,cols,data);

    rows.add(buildTotalRow(rowDims,cols,data));

    int totalRowIndex = rows.size()+1;

    EasyExcel.write(response.getOutputStream())
            .head(head)
            .registerWriteHandler(
                    new LongestMatchColumnWidthStyleStrategy())
            .registerWriteHandler(
                    new FreezePaneHandler())
            .registerWriteHandler(
                    new HeadStyleStrategy())
            .registerWriteHandler(
                    new NumberStyleStrategy())
            .registerWriteHandler(
                    new TotalMergeStrategy(
                            totalRowIndex,
                            rowDims.size()-1))
            .sheet("报表")
            .doWrite(rows);
}

九、最终报表能力

功能 支持
动态表头
a/f子表头
SQL透视
Java合计
合计单元格合并
自动列宽
冻结表头
数值格式
Excel导出

十、企业级再升级(非常推荐)

很多 BI 报表还会加:

1️⃣ 分组小计

复制代码
产品A
   型号1
      项目1
      项目2
   小计

2️⃣ 动态排序

3️⃣ 百万行导出

4️⃣ 分页查询 + 全量导出

5️⃣ 动态筛选条件


如果你需要,我可以再给你一套 真正企业 BI 报表级方案

  • 动态行分组(产品→型号→项目)自动合并单元格
  • 自动生成小计
  • 类似 Excel 数据透视表
  • EasyExcel 完整实现

代码大约 400 行核心代码,很多公司报表系统都是这样实现的。

相关推荐
卷无止境4 分钟前
Python 异常处理:从入门到工程实践
后端·python
garuda herb7 分钟前
生成专题页Blog--建立并返回 MySQL 数据库连接
python·mysql
ONE_SIX_MIX11 分钟前
qwenpaw-plugin-file-tools QwenPaw增强文件工具 更新 v1.1.1
python·qwenpaw
AOwhisky14 分钟前
Python 学习笔记(第五期)——组合数据类型:列表、元组、集合与字典精讲——核心知识点自测与详解
开发语言·笔记·python·学习·云计算
码农学院33 分钟前
GEO与SEO协同:从传统搜索到生成式搜索的平滑迁移路径
服务器·前端·python
程序员羽痕33 分钟前
基于 Django + PyTorch 的中文字体识别系统
pytorch·python·django
灯澜忆梦9 小时前
GO_并发编程---定时器
开发语言·后端·golang
-银雾鸢尾-10 小时前
C#中的StringBuilder相关方法
开发语言·c#
-银雾鸢尾-10 小时前
C#中结构体与类的区别;抽象类与接口的区别
开发语言·c#
广州灵眸科技有限公司10 小时前
xfce桌面触摸校准:基于灵眸科技EASY-EAl-Orin-Nano
数据库·windows·科技