在 Spring Boot 中结合 EasyExcel 实现动态表头导出(无实体类,表头和字段(前端传表名,字段值动态查询,返回List<Map<String,Object>>)由前端传递)可以通过以下步骤实现。以下是完整示例:
1. 前端请求数据结构
假设前端传递的 JSON 格式如下:
{
"headers": [
{"title": "姓名", "field": "name"},
{"title": "年龄", "field": "age"},
{"title": "城市", "field": "city"}
],
"data": [
{"name": "张三", "age": 25, "city": "北京"},
{"name": "李四", "age": 30, "city": "上海"}
]
}
2. 后端 DTO 定义
定义接收参数的 DTO 类:
@Data
public class ExportRequest {
private List<Header> headers;
private List<Map<String, Object>> data;
@Data
public static class Header {
private String title; // 表头名称
private String field; // 数据字段名
}
}
3. Controller 层接口
处理导出请求:
@RestController
public class ExportController {
@Autowired
private ExportService exportService;
@PostMapping("/export")
public void exportExcel(@RequestBody ExportRequest request, HttpServletResponse response) {
exportService.export(request, response);
}
}
4. Service 层实现
核心导出逻辑:
@Service
public class ExportService {
public void export(ExportRequest request, HttpServletResponse response) {
try {
// 设置响应头
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("UTF-8");
String fileName = URLEncoder.encode("动态导出.xlsx", "UTF-8");
response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
// 获取输出流
OutputStream outputStream = response.getOutputStream();
// 动态构建表头和数据
WriteSheet writeSheet = EasyExcel.writerSheet("Sheet1").build();
ExcelWriter excelWriter = EasyExcel.write(outputStream).build();
// 动态添加表头
WriteTable writeTable = new WriteTable();
List<List<String>> head = buildHead(request.getHeaders());
writeTable.setHead(head);
// 动态填充数据
List<List<Object>> data = buildData(request.getHeaders(), request.getData());
excelWriter.write(data, writeSheet, writeTable);
// 关闭流
excelWriter.finish();
outputStream.flush();
} catch (IOException e) {
throw new RuntimeException("导出失败", e);
}
}
// 构建表头
private List<List<String>> buildHead(List<ExportRequest.Header> headers) {
List<List<String>> head = new ArrayList<>();
for (ExportRequest.Header header : headers) {
List<String> columnHead = Collections.singletonList(header.getTitle());
head.add(columnHead);
}
return head;
}
// 构建数据行
private List<List<Object>> buildData(List<ExportRequest.Header> headers, List<Map<String, Object>> dataList) {
List<List<Object>> data = new ArrayList<>();
for (Map<String, Object> rowData : dataList) {
List<Object> row = new ArrayList<>();
for (ExportRequest.Header header : headers) {
row.add(rowData.get(header.getField()));
}
data.add(row);
}
return data;
}
}
5. 关键点说明
-
动态表头
- 通过
buildHead()
方法将前端传递的headers
转换为 EasyExcel 需要的List<List<String>>
格式。
- 通过
-
动态数据
- 通过
buildData()
方法,根据headers
中定义的field
字段顺序,从data
中提取对应值,构建数据行。
- 通过
-
流式导出
- 使用
ExcelWriter
直接操作输出流,避免内存溢出(适合大数据量)。
- 使用
6. 测试与验证
使用 Postman 发送请求:
-
URL:
POST http://localhost:8080/export
-
Body(JSON):
{ "headers": [ {"title": "姓名", "field": "name"}, {"title": "年龄", "field": "age"}, {"title": "城市", "field": "city"} ], "data": [ {"name": "张三", "age": 25, "city": "北京"}, {"name": "李四", "age": 30, "city": "上海"} ] }
-
响应:浏览器自动下载
动态导出.xlsx
,内容如下:姓名 年龄 城市 张三 25 北京 李四 30 上海
7. 扩展优化
- 字段校验:确保前端传递的
field
在data
中存在对应值。 - 大数据量分页:如果数据量过大,可分页查询后分批写入。
- 自定义样式:通过
WriteHandler
动态设置单元格样式(如字体、颜色)。
通过这种方式,无需定义实体类即可实现完全动态的 Excel 导出功能,表头和字段完全由前端控制。