当前位置: 首页 > news >正文

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

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

  • 动态行维度(产品 / 型号 / 项目 任意组合)
  • 动态列维度(月份)
  • a / f 子表头
  • SQL 透视(适合 GaussDB)
  • 查询接口 + EasyExcel 导出接口
  • 可复用报表引擎

整体架构:

Controller ↓ ReportService ↓ PivotEngine(核心透视引擎) ↓ MyBatis ↓ GaussDB

一、数据库示例

表:sales_plan

product model itemmonthtypevalue

示例数据

productmodelitemmonthtypevalue
AA1P11月a10
AA1P12月a20
AA1P13月a30
AA1P14月f40

二、报表请求参数(核心)

publicclassReportRequest{// 行维度privateList<String>rowDims;// 列维度privateStringcolDim;// 指标privateStringmeasure;}

示例:

{"rowDims":["product","model","item"],"colDim":"month","measure":"value"}

三、透视SQL生成引擎

核心类:

PivotEngine
publicclassPivotEngine{

生成透视 SQL:

publicstaticStringbuildPivotSql(Stringtable,List<String>rowDims,StringcolDim,Stringmeasure,List<String>colValues){StringBuildersql=newStringBuilder();sql.append("SELECT ");// 行维度for(Stringr:rowDims){sql.append(r).append(",");}// 透视列for(Stringv:colValues){sql.append("SUM(CASE WHEN ").append(colDim).append("='").append(v).append("' THEN ").append(measure).append(" ELSE 0 END) AS \"").append(v).append("\",");}sql.append("SUM(").append(measure).append(") total ");sql.append("FROM ").append(table);sql.append(" GROUP BY ");for(inti=0;i<rowDims.size();i++){sql.append(rowDims.get(i));if(i<rowDims.size()-1){sql.append(",");}}returnsql.toString();}

生成SQL:

SELECTproduct,model,item,SUM(CASEWHENmonth='1月'THENvalueELSE0END)"1月",SUM(CASEWHENmonth='2月'THENvalueELSE0END)"2月",SUM(CASEWHENmonth='3月'THENvalueELSE0END)"3月",SUM(value)totalFROMsales_planGROUPBYproduct,model,item

四、MyBatis

@MapperpublicinterfaceReportMapper{

查询列维度值:

@Select("SELECT DISTINCT ${col} FROM ${table} ORDER BY ${col}")List<String>queryColValues(@Param("table")Stringtable,@Param("col")Stringcol);

执行透视SQL:

@Select("${sql}")List<Map<String,Object>>queryPivot(@Param("sql")Stringsql);

五、Service

@ServicepublicclassReportService{
@AutowiredReportMappermapper;

核心逻辑:

publicMap<String,Object>report(ReportRequestreq){// 1 查询月份List<String>cols=mapper.queryColValues("sales_plan",req.getColDim());// 2 构建SQLStringsql=PivotEngine.buildPivotSql("sales_plan",req.getRowDims(),req.getColDim(),req.getMeasure(),cols);// 3 执行List<Map<String,Object>>data=mapper.queryPivot(sql);Map<String,Object>result=newHashMap<>();result.put("cols",cols);result.put("data",data);returnresult;}

六、查询接口

@PostMapping("/report/query")publicMap<String,Object>query(@RequestBodyReportRequestreq){returnservice.report(req);}

返回数据:

{"cols":["1月","2月","3月","4月"],"data":[{"product":"A","model":"A1","item":"P1","1月":10,"2月":20,"3月":30,"4月":40,"total":100}]}

七、EasyExcel 动态表头

生成表头:

publicstaticList<List<String>>buildHead(List<String>rowDims,List<String>months,Map<String,String>typeMap){List<List<String>>head=newArrayList<>();for(Stringr:rowDims){head.add(Arrays.asList(r));}for(Stringm:months){head.add(Arrays.asList(m,typeMap.get(m)));}head.add(Arrays.asList("合计"));returnhead;}

八、Excel导出接口

@PostMapping("/report/export")publicvoidexport(@RequestBodyReportRequestreq,HttpServletResponseresponse)throwsException{Map<String,Object>result=service.report(req);List<String>cols=(List<String>)result.get("cols");List<Map<String,Object>>data=(List<Map<String,Object>>)result.get("data");List<List<String>>head=ExcelUtil.buildHead(req.getRowDims(),cols,getTypeMap());List<List<Object>>rows=ExcelUtil.buildRows(req.getRowDims(),cols,data);EasyExcel.write(response.getOutputStream()).head(head).sheet("报表").doWrite(rows);}

九、最终能力

这个报表引擎支持:

能力支持
动态行维度
动态列维度
SQL透视
查询接口
Excel导出
EasyExcel动态表头
百万行导出

十、最终效果(与你图片一样)

产品 型号 项目 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
http://www.cnnetsun.cn/news/1601016.html

相关文章:

  • FireRed-OCR Studio应用场景:高校教务材料批量数字化处理方案
  • 探秘书匠策AI:毕业论文创作的“全能助手”大揭秘
  • 微信小程序如何找“人工客服”
  • nanobot实战:超轻量AI助手在QQ聊天场景中的7大应用
  • Wan2.2-I2V-A14B开发环境搭建:VSCode远程连接与调试教程
  • Vue 3组件通信的‘后悔药’:defineProps与defineEmits的5个高级调试与重构技巧
  • PROJECT MOGFACE与Dify平台集成:快速构建无需编码的AI智能体应用
  • 实战指南:在Vitis 2024.1的lwIP库中集成KSZ9031以太网PHY驱动
  • SpringAI 1.0.0 避坑指南:从ChatClient配置到流式响应乱码,一次讲清楚
  • Qwen3-14B助力出海企业:本地化部署支持小语种翻译与文化适配生成
  • DeepSeek-R1模型1.5B到671B:如何根据应用场景选择合适规模?
  • 用Steam游戏《Turing Complete》手把手教你搭建8位加法器:从半加器到全加器的完整逻辑
  • 新手入门:用FOFA、360Quake、Shodan、ZoomEye这四大网络测绘工具,5分钟快速定位暴露在公网的资产
  • 千问3.5-2B开源可部署实践:镜像体积仅8.2GB,适合带宽受限环境分发
  • 消息保护开源工具:RevokeMsgPatcher 全方位解决方案
  • AD使用技巧之-BGA扇出方法
  • 告别虚拟机!Windows WSL2+GNU Radio玩转HackRF-One无线接收(避坑指南)
  • 从RRT到RRT*:深入解析‘重选父节点’与‘重连’如何让你的机器人路径更丝滑
  • 船舶水动力学与运动控制:从理论建模到工程实践的全栈技术指南
  • UE5蓝图实战:5分钟搞定物品高亮与拾取交互(含后期处理材质避坑指南)
  • RVC模型性能对比测试:不同GPU算力下的推理速度与成本
  • ai辅助开发新体验:让快马平台智能解析与生成你的comfyui工作流
  • 新手入门hnu计算机系统:用快马生成你的第一个简易shell
  • 终极指南:如何用Turbo Boost Switcher轻松掌控Mac性能与温度[特殊字符]
  • 解决403 Forbidden:SmallThinker-3B-Preview模型API访问权限配置教程
  • 从夯到拉,大模型岗位全攻略:程序员转型指南与避坑指南
  • 4大技术维度:如何构建跨平台一致的字体渲染系统
  • 如何用TradingAgents-CN实现AI驱动的股票分析?从部署到应用的完整指南
  • 如何用Audio2Face实现超逼真AI面部动画:从技术到实践
  • OBS Advanced Timer:全场景直播计时神器,让你的直播节奏掌控自如