震撼!我用 Spring Boot 封裝了一個通殺全場的 Excel 導出神器,任何數據一鍵搞定!
在企業(yè)開發(fā)中,“導出 Excel” 一直是個繞不過去的痛點。 每次換個表結構、改個字段名,就得新建 DTO、調整注解、修模板、測樣式——不僅繁瑣,還極易出錯。
前陣子,組里一位同事小王又被這問題折磨得抓耳撓腮:“有沒有那種不用寫注解、隨便傳數據都能導出的 Excel 工具?。课疫@邊二十張表,全長得不一樣?!?nbsp;聽完我直接笑出聲 —— 誰還沒被這種需求折磨過?于是我干脆擼了個“通用型 Excel 導出神器”,能自動識別數據結構、自動生成表頭、自動輸出 Excel, 無論你傳的是 List<Object> 還是 List<Map>,都能輕松搞定,一次封裝,全場通殺。
設計思路
核心思想其實非常樸素: 通過反射分析傳入對象的字段結構,用 EasyExcel(或 Apache POI)寫出 Excel 文件。 關鍵點在于“自動推斷表頭”,也就是說,不用再寫注解或者 DTO,工具會自動識別字段名并生成 Excel 頭部。
- 如果傳入的是
List<User>:反射獲取字段名(如id,name,age); - 如果傳入的是
List<Map>:以第一條記錄的key作為表頭。
思路清晰明了,下面直接看代碼。
工具類實現
文件路徑:
/src/main/java/com/icoderoad/excel/util/ExcelExportUtil.java代碼如下 :
package com.icoderoad.excel.util;
import com.alibaba.excel.EasyExcel;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.*;
/**
* 通用 Excel 導出工具類
* 支持 List<Object> 與 List<Map> 數據格式
*/
public class ExcelExportUtil {
/**
* 通用導出方法
* @param response 響應對象
* @param data 導出數據
* @param fileName 導出文件名
*/
public static <T> void export(HttpServletResponse response, List<T> data, String fileName) throws IOException {
if (data == null || data.isEmpty()) {
throw new IllegalArgumentException("導出數據不能為空");
}
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.setCharacterEncoding("utf-8");
response.setHeader(HttpHeaders.CONTENT_DISPOSITION,
"attachment;filename=" + URLEncoder.encode(fileName, "UTF-8") + ".xlsx");
// 判斷類型:Map 或 普通對象
if (data.get(0) instanceof Map) {
writeMapData(response, (List<Map<String, Object>>) data);
} else {
writeObjectData(response, data);
}
}
/** 處理 List<Map> 數據導出 */
private static void writeMapData(HttpServletResponse response, List<Map<String, Object>> list) throws IOException {
List<List<String>> head = new ArrayList<>();
List<List<Object>> rows = new ArrayList<>();
Set<String> headers = list.get(0).keySet();
headers.forEach(k -> head.add(Collections.singletonList(k)));
for (Map<String, Object> row : list) {
List<Object> line = new ArrayList<>();
for (String k : headers) {
line.add(row.getOrDefault(k, ""));
}
rows.add(line);
}
EasyExcel.write(response.getOutputStream())
.head(head)
.sheet("Sheet1")
.doWrite(rows);
}
/** 處理 List<Object> 數據導出 */
private static <T> void writeObjectData(HttpServletResponse response, List<T> list) throws IOException {
Class<?> clazz = list.get(0).getClass();
List<List<String>> head = new ArrayList<>();
List<Field> fields = Arrays.asList(clazz.getDeclaredFields());
fields.forEach(f -> head.add(Collections.singletonList(f.getName())));
List<List<Object>> rows = new ArrayList<>();
for (T t : list) {
List<Object> row = new ArrayList<>();
for (Field f : fields) {
f.setAccessible(true);
try {
row.add(Optional.ofNullable(f.get(t)).orElse(""));
} catch (IllegalAccessException e) {
row.add("");
}
}
rows.add(row);
}
EasyExcel.write(response.getOutputStream())
.head(head)
.sheet("Sheet1")
.doWrite(rows);
}
}實體類與 Controller 示例
路徑:
/src/main/java/com/icoderoad/excel/controller/ExportController.java
package com.icoderoad.excel.controller;
import com.icoderoad.excel.util.ExcelExportUtil;
import lombok.Data;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
/**
* Excel 導出控制器
*/
@RestController
public class ExportController {
@Data
public static class User {
private Long id;
private String name;
private Integer age;
public User(Long id, String name, Integer age) {
this.id = id;
this.name = name;
this.age = age;
}
}
/** 示例1:導出固定結構對象 */
@GetMapping("/export")
public void export(HttpServletResponse response) throws IOException {
List<User> users = Arrays.asList(
new User(1L, "張三", 20),
new User(2L, "李四", 25)
);
ExcelExportUtil.export(response, users, "用戶信息");
}
/** 示例2:導出動態(tài)結構 Map 數據 */
@GetMapping("/exportDynamic")
public void exportDynamic(HttpServletResponse response) throws IOException {
List<Map<String, Object>> list = new ArrayList<>();
Map<String, Object> row1 = new LinkedHashMap<>();
row1.put("姓名", "小王");
row1.put("部門", "研發(fā)部");
row1.put("薪資", 18000);
list.add(row1);
Map<String, Object> row2 = new LinkedHashMap<>();
row2.put("姓名", "小李");
row2.put("部門", "測試部");
row2.put("薪資", 15000);
list.add(row2);
ExcelExportUtil.export(response, list, "員工薪資表");
}
}細節(jié)與擴展優(yōu)化
在后續(xù)使用中,我還為這個工具做了幾處增強優(yōu)化:
- 字段排序控制 可以通過注解(如 `@ExcelColumn(order = 1))控制導出列順序。
- 日期格式化 對于
Date類型字段,默認格式化為yyyy-MM-dd HH:mm:ss,避免直接輸出時間戳。 - 空值處理 自動將
null轉為空字符串,防止出現NPE異常。 - 中文表頭映射 支持自定義表頭注解,如
@ExcelColumn("用戶名"),導出時自動映射成中文列名。 - 緩存字段定義 當導出超大數據量時,可緩存字段元數據結構,減少反射次數,提高性能。
總結
這套導出工具目前已經在多個項目中穩(wěn)定運行,支持幾乎所有常見導出場景。 無論是動態(tài)結構的前端數據,還是固定結構的 Java Bean,只要傳入 List,都能一鍵生成 Excel。
更重要的是:
不用再維護 DTO、注解、模板,告別字段對不上、列順序亂、手工測試累的問題。
如果你也經常被導出 Excel 折騰,不妨嘗試這樣的通用思路。簡單、穩(wěn)健、可維護——這才是工程化實踐的真正魅力。






























