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

# 【Java + EasyExcel 实战】动态列 + 公式备注 Excel 模板导出全流程(附完整代码)

## 📚 目录
1. [前言](#前言)
2. [需求与目标](#需求与目标)
3. [整体方案设计](#整体方案设计)
4. [核心功能拆解](#核心功能拆解)
- [1. 表头构造](#1-表头构造)
- [2. 数据行构造](#2-数据行构造)
- [3. 字典值转换](#3-字典值转换)
- [4. 备注公式生成](#4-备注公式生成)
- [5. 列号转字母](#5-列号转字母)
- [6. 导出主流程](#6-导出主流程)
5. [完整工具类代码](#完整工具类代码)
6. [公式写入处理器](#公式写入处理器)
7. [Controller 示例接口](#controller-示例接口)
8. [总结与优化方向](#总结与优化方向)

---

## 前言

在 **监控告警系统**、**规则引擎**、**数据计算配置** 等场景中,我们经常需要导出“规则模板 Excel”,让用户在表格里填写参数后再回传。

这个 Excel 模板的特点是:
- 固定字段(规则编码、名称、类型等)
- 动态字段(根据规则描述自动提取的变量 x1、y1、n 等)
- 备注列(通过 Excel 公式动态替换变量值)

> ⚡ 本文将演示如何用 **EasyExcel** 实现“动态列 + 公式备注”的模板导出,最终效果是用户在 Excel 中输入变量值后,备注列会**实时更新**。

---

## 需求与目标

### 目标 Excel 结构

| 规则编码 | 规则名称 | 规则类型 | 规则等级 | 描述 | x1 | y1 | n | 备注 |
| -------- | -------- | -------- | -------- | ---- | -- | -- | - | ---- |
| R001     | 浆液循环泵告警 | 高级告警 | 1 | 当 x1 大于 y1 持续 n 分钟时告警 | 10 | 20 | 5 | 当 10 大于 20 持续 5 分钟时告警 |

其中:
- **x1、y1、n** 是根据 `描述` 自动识别出的变量
- **备注列** 是公式生成:`=SUBSTITUTE(SUBSTITUTE(SUBSTITUTE($E$2,"x1",F2),"y1",G2),"n",H2)`

---

## 整体方案设计

1. **提取变量**  
- 使用正则匹配 `x\d+`、`y\d+` 等模式  
- 额外匹配 `n`(Z次/Z分钟等)

2. **构造表头**  
- 固定列(从实体类注解读取)
- 动态列(变量)
- 备注列

3. **构造数据行**  
- 固定字段填充
- 动态列占位
- 备注列写公式字符串

4. **写出 Excel**  
- 用 EasyExcel 写入
- 注册公式处理器(防止公式变成普通文本)
- 列宽自适应

---

## 核心功能拆解

### 1. 表头构造

```java
public static List<List<String>> buildDynamicHeader(Class<?> clazz, List<String> dynamicHeaders) {
List<List<String>> headers = new ArrayList<>();
// 固定列
for (Field field : clazz.getDeclaredFields()) {
ExcelProperty prop = field.getAnnotation(ExcelProperty.class);
if (prop != null && prop.value().length > 0) {
headers.add(Collections.singletonList(prop.value()[0]));
}
}
// 动态列
for (String dynamic : dynamicHeaders) {
headers.add(Collections.singletonList(dynamic));
}
// 备注列
headers.add(Collections.singletonList("备注"));
return headers;
}

2. 数据行构造

public static List<Object> buildRowFromEntity(RuleExcelTemplate.ExportTemplate rule, int dynamicColSize) {List<Object> row = new ArrayList<>();row.add(rule.getRuleCode());row.add(rule.getRuleName());row.add(convertDict(CustomConstant.ALARM_TYPE, rule.getRuleType()));row.add(rule.getRuleLevel());row.add(rule.getDescription());// 动态列占位for (int i = 0; i < dynamicColSize; i++) {row.add("");}// 备注列公式row.add(buildRemarkFormula(rule.getDescription()));return row;
}

3. 字典值转换

private static String convertDict(String dictKey, String rawValue) {List<DictModel> dictList = CustomUtils.dictModelList(dictKey);if (CollectionUtils.isEmpty(dictList)) {return rawValue;}for (DictModel item : dictList) {if (Objects.equals(item.getId(), rawValue)) {return item.getName();}}return rawValue;
}

4. 备注公式生成

public static String buildRemarkFormula(String description) {if (description == null || description.isEmpty()) {return "";}LinkedHashSet<String> variables = new LinkedHashSet<>();Matcher xyMatcher = CustomConstant.XY_PATTERN.matcher(description);while (xyMatcher.find()) {variables.add(xyMatcher.group());}if (CustomConstant.Z_PATTERN.matcher(description).find()) {variables.add("n");}String formula = "$E$2"; // 描述列int colIndex = 5; // 从F列开始for (String var : variables) {String colLetter = getExcelColLetter(colIndex++);formula = String.format("SUBSTITUTE(%s,\"%s\",%s2)", formula, var, colLetter);}return "=" + formula;
}

5. 列号转字母

public static String getExcelColLetter(int colIndex) {StringBuilder sb = new StringBuilder();while (colIndex >= 0) {sb.insert(0, (char) ('A' + (colIndex % 26)));colIndex = colIndex / 26 - 1;}return sb.toString();
}

6. 导出主流程

public static void exportRuleExcel(RuleExcelTemplate.ExportTemplate rule, List<String> dynamicHeaders, HttpServletResponse response) throws Exception {List<List<String>> headList = buildDynamicHeader(RuleExcelTemplate.ExportTemplate.class, dynamicHeaders);List<Object> dataRow = buildRowFromEntity(rule, dynamicHeaders.size());String fileName = URLEncoder.encode(rule.getRuleName() + "模板导出.xlsx", StandardCharsets.UTF_8);try (OutputStream out = getOutputStream(fileName, response)) {ExcelWriter writer = EasyExcel.write(out).registerWriteHandler(new RemarkFormulaCellHandler()).registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).excelType(ExcelTypeEnum.XLSX).build();WriteSheet sheet = EasyExcel.writerSheet("规则导出").head(headList).build();writer.write(Collections.singletonList(dataRow), sheet);writer.finish();}
}

总结与优化方向

  • ✅ 动态列生成公式,变量替换即时可见

  • ✅ 支持字典映射,提升可读性

  • ✅ 列宽自适应,表头固定 + 动态可扩展

可优化点:

  1. 动态列映射缓存,保证批量导出一致性

  2. 多规则多 Sheet 导出

  3. 前端进度提示 & 异步导出

  4. 支持 Excel 模板反向导入

http://www.dtcms.com/a/315457.html

相关文章:

  • 前端实现Excel文件的在线预览效果
  • 【学习笔记】FTP库函数学习
  • 文件编译、调试及库制作
  • 人工智能领域、图欧科技、IMYAI智能助手2025年2月更新月报
  • pyspark中的kafka的读和写案例操作
  • Goby 漏洞安全通告| NestJS DevTools /inspector/graph/interact 命令执行漏洞(CVE-2025-54782)
  • libpq库使用
  • PDF转图片工具技术文档(命令行版本)
  • 【taro react】 ---- useModel 数据双向绑定 hook 实现
  • vue和react的框架原理
  • 基于PD控制器的四旋翼无人机群飞行控制系统simulink建模与仿真
  • SpringBoot原理揭秘--BeanFactory和ApplicationContext
  • day 46 神经网络-简版
  • 2025年渗透测试面试题总结-01(题目+回答)
  • 什么是压接孔?压接孔PCB制造流程
  • Zabbix 企业级高级应用
  • AI赋能复合材料与智能增材制造:前沿技术研修重磅
  • 【MATLAB】(八)矩阵
  • 盟接之桥说制造:价格战与品质:制造企业可持续发展的战略思考
  • 智能融合:增材制造多物理场AI建模与工业应用实战
  • PHP:历经岁月仍熠熠生辉的服务器端脚本语言
  • Spring 的 ioc 控制反转
  • 无人设备遥控器之信号切换技术篇
  • Guava 与 Caffeine 本地缓存系统详解
  • jQuery DOM节点操作详解
  • stm32F407 硬件COM事件触发六步换相
  • AI医疗革命:十大应用场景如何重塑未来医疗
  • 手绘风格制图新选择:如何用Excalidraw+cpolar构建你的视觉化工作流?
  • windos10 安装CentOS7 虚拟机笔记
  • Datawhale AI夏令营 第三期 task2