EasyExcel動(dòng)態(tài)表頭基礎(chǔ)用法及最佳實(shí)踐詳解
什么是動(dòng)態(tài)表頭?
動(dòng)態(tài)表頭是指在運(yùn)行時(shí)根據(jù)業(yè)務(wù)需求動(dòng)態(tài)生成Excel表格的列標(biāo)題,而不是在代碼中預(yù)先定義固定的表頭結(jié)構(gòu)。這在以下場(chǎng)景中非常有用:
根據(jù)用戶選擇的字段生成不同的報(bào)表
處理數(shù)據(jù)庫中動(dòng)態(tài)字段的導(dǎo)出
生成多級(jí)復(fù)雜表頭
實(shí)現(xiàn)可配置的數(shù)據(jù)導(dǎo)出功能
基礎(chǔ)用法
1. 簡(jiǎn)單動(dòng)態(tài)表頭
public class DynamicHeaderExample {
public void writeWithDynamicHeader() {
String fileName = "dynamic_header.xlsx";
// 動(dòng)態(tài)構(gòu)建表頭
List<List<String>> head = new ArrayList<>();
head.add(Arrays.asList("姓名"));
head.add(Arrays.asList("年齡"));
head.add(Arrays.asList("郵箱"));
head.add(Arrays.asList("部門"));
// 準(zhǔn)備數(shù)據(jù)
List<List<Object>> dataList = new ArrayList<>();
dataList.add(Arrays.asList("張三", 25, "zhangsan@example.com", "技術(shù)部"));
dataList.add(Arrays.asList("李四", 30, "lisi@example.com", "產(chǎn)品部"));
dataList.add(Arrays.asList("王五", 28, "wangwu@example.com", "設(shè)計(jì)部"));
// 寫入Excel
EasyExcel.write(fileName)
.head(head)
.sheet("員工信息")
.doWrite(dataList);
}
}2. 多級(jí)表頭
public void writeWithMultiLevelHeader() {
String fileName = "multi_level_header.xlsx";
// 構(gòu)建多級(jí)表頭
List<List<String>> head = new ArrayList<>();
// 第一列:基本信息->個(gè)人信息->姓名
head.add(Arrays.asList("基本信息", "個(gè)人信息", "姓名"));
// 第二列:基本信息->個(gè)人信息->年齡
head.add(Arrays.asList("基本信息", "個(gè)人信息", "年齡"));
// 第三列:基本信息->聯(lián)系方式->郵箱
head.add(Arrays.asList("基本信息", "聯(lián)系方式", "郵箱"));
// 第四列:基本信息->聯(lián)系方式->電話
head.add(Arrays.asList("基本信息", "聯(lián)系方式", "電話"));
// 第五列:工作信息->部門
head.add(Arrays.asList("工作信息", "部門"));
// 第六列:工作信息->職位
head.add(Arrays.asList("工作信息", "職位"));
// 準(zhǔn)備數(shù)據(jù)
List<List<Object>> dataList = new ArrayList<>();
dataList.add(Arrays.asList("張三", 25, "zhangsan@example.com", "13800138000", "技術(shù)部", "Java工程師"));
dataList.add(Arrays.asList("李四", 30, "lisi@example.com", "13900139000", "產(chǎn)品部", "產(chǎn)品經(jīng)理"));
EasyExcel.write(fileName)
.head(head)
.sheet("員工詳細(xì)信息")
.doWrite(dataList);
}高級(jí)應(yīng)用
1. 根據(jù)數(shù)據(jù)庫字段動(dòng)態(tài)生成表頭
@Service
public class DynamicExportService {
@Autowired
private FieldConfigService fieldConfigService;
public void exportUserData(List<String> selectedFields) {
String fileName = "user_export_" + System.currentTimeMillis() + ".xlsx";
// 根據(jù)選中字段構(gòu)建表頭
List<List<String>> head = buildDynamicHeader(selectedFields);
// 獲取數(shù)據(jù)
List<List<Object>> dataList = buildDataList(selectedFields);
EasyExcel.write(fileName)
.head(head)
.sheet("用戶數(shù)據(jù)")
.doWrite(dataList);
}
private List<List<String>> buildDynamicHeader(List<String> selectedFields) {
List<List<String>> head = new ArrayList<>();
for (String fieldCode : selectedFields) {
FieldConfig config = fieldConfigService.getByCode(fieldCode);
if (config != null) {
// 支持分組表頭
if (config.getGroupName() != null) {
head.add(Arrays.asList(config.getGroupName(), config.getFieldName()));
} else {
head.add(Arrays.asList(config.getFieldName()));
}
}
}
return head;
}
private List<List<Object>> buildDataList(List<String> selectedFields) {
List<User> users = userService.getAllUsers();
List<List<Object>> dataList = new ArrayList<>();
for (User user : users) {
List<Object> row = new ArrayList<>();
for (String fieldCode : selectedFields) {
Object value = getFieldValue(user, fieldCode);
row.add(value);
}
dataList.add(row);
}
return dataList;
}
private Object getFieldValue(User user, String fieldCode) {
// 使用反射或Map方式獲取字段值
switch (fieldCode) {
case "name": return user.getName();
case "age": return user.getAge();
case "email": return user.getEmail();
case "department": return user.getDepartment();
case "createTime": return user.getCreateTime();
default: return "";
}
}
}
?
// 字段配置實(shí)體
@Data
public class FieldConfig {
private String fieldCode;
private String fieldName;
private String groupName;
private Integer sortOrder;
}2. 配置化動(dòng)態(tài)表頭
@Component
public class ConfigurableDynamicHeader {
public void exportWithConfig(ExportConfig config) {
String fileName = config.getFileName() + ".xlsx";
// 根據(jù)配置構(gòu)建表頭
List<List<String>> head = buildHeaderFromConfig(config);
// 根據(jù)配置獲取數(shù)據(jù)
List<List<Object>> dataList = buildDataFromConfig(config);
// 應(yīng)用樣式
HorizontalCellStyleStrategy styleStrategy = buildStyleFromConfig(config);
EasyExcel.write(fileName)
.head(head)
.registerWriteHandler(styleStrategy)
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
.sheet(config.getSheetName())
.doWrite(dataList);
}
private List<List<String>> buildHeaderFromConfig(ExportConfig config) {
List<List<String>> head = new ArrayList<>();
for (HeaderConfig headerConfig : config.getHeaders()) {
List<String> headerPath = new ArrayList<>();
// 支持多級(jí)表頭
if (headerConfig.getLevel1() != null) {
headerPath.add(headerConfig.getLevel1());
}
if (headerConfig.getLevel2() != null) {
headerPath.add(headerConfig.getLevel2());
}
if (headerConfig.getLevel3() != null) {
headerPath.add(headerConfig.getLevel3());
}
head.add(headerPath);
}
return head;
}
}
?
// 導(dǎo)出配置類
@Data
public class ExportConfig {
private String fileName;
private String sheetName;
private List<HeaderConfig> headers;
private StyleConfig styleConfig;
}
?
@Data
public class HeaderConfig {
private String fieldCode;
private String level1;
private String level2;
private String level3;
private Integer width;
}3. 動(dòng)態(tài)表頭與數(shù)據(jù)驗(yàn)證結(jié)合
public class DynamicHeaderWithValidation {
public void writeWithValidation() {
String fileName = "validated_dynamic.xlsx";
// 構(gòu)建表頭
List<List<String>> head = Arrays.asList(
Arrays.asList("姓名"),
Arrays.asList("年齡"),
Arrays.asList("郵箱"),
Arrays.asList("手機(jī)號(hào)")
);
// 準(zhǔn)備數(shù)據(jù)
List<List<Object>> dataList = new ArrayList<>();
dataList.add(Arrays.asList("張三", 25, "zhangsan@example.com", "13800138000"));
dataList.add(Arrays.asList("李四", 30, "lisi@example.com", "13900139000"));
// 創(chuàng)建下拉選擇處理器
DropDownWriteHandler dropDownHandler = new DropDownWriteHandler();
EasyExcel.write(fileName)
.head(head)
.registerWriteHandler(dropDownHandler)
.sheet("帶驗(yàn)證的數(shù)據(jù)")
.doWrite(dataList);
}
}
?
// 自定義下拉選擇處理器
public class DropDownWriteHandler implements SheetWriteHandler {
@Override
public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder,
WriteSheetHolder writeSheetHolder) {
Sheet sheet = writeSheetHolder.getSheet();
Workbook workbook = writeWorkbookHolder.getWorkbook();
// 創(chuàng)建數(shù)據(jù)驗(yàn)證規(guī)則
DataValidationHelper validationHelper = sheet.getDataValidationHelper();
// 為年齡列添加數(shù)字驗(yàn)證(假設(shè)年齡在B列)
CellRangeAddressList ageRange = new CellRangeAddressList(1, 1000, 1, 1);
DataValidationConstraint ageConstraint = validationHelper
.createIntegerConstraint(DataValidationConstraint.OperatorType.BETWEEN, "0", "150");
DataValidation ageValidation = validationHelper.createValidation(ageConstraint, ageRange);
ageValidation.setErrorStyle(DataValidation.ErrorStyle.STOP);
ageValidation.createErrorBox("年齡錯(cuò)誤", "年齡必須在0-150之間");
sheet.addValidationData(ageValidation);
}
}實(shí)際應(yīng)用場(chǎng)景
1. 報(bào)表系統(tǒng)中的可配置導(dǎo)出
@RestController
@RequestMapping("/api/export")
public class ExportController {
@Autowired
private DynamicExportService exportService;
@PostMapping("/users")
public ResponseEntity<String> exportUsers(@RequestBody ExportRequest request) {
try {
String fileName = exportService.exportUserData(
request.getSelectedFields(),
request.getStartDate(),
request.getEndDate()
);
return ResponseEntity.ok(fileName);
} catch (Exception e) {
return ResponseEntity.badRequest().body("導(dǎo)出失?。? + e.getMessage());
}
}
}
?
@Data
public class ExportRequest {
private List<String> selectedFields;
private LocalDate startDate;
private LocalDate endDate;
private String groupBy;
}2. 動(dòng)態(tài)報(bào)表生成
public class DynamicReportGenerator {
public void generateReport(ReportTemplate template, Map<String, Object> params) {
String fileName = template.getName() + "_" +
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss")) +
".xlsx";
// 根據(jù)模板構(gòu)建表頭
List<List<String>> head = buildHeaderFromTemplate(template);
// 根據(jù)參數(shù)查詢數(shù)據(jù)
List<List<Object>> dataList = queryDataByTemplate(template, params);
// 應(yīng)用模板樣式
List<WriteHandler> handlers = buildWriteHandlers(template);
ExcelWriterBuilder builder = EasyExcel.write(fileName).head(head);
// 注冊(cè)所有處理器
for (WriteHandler handler : handlers) {
builder.registerWriteHandler(handler);
}
builder.sheet(template.getSheetName()).doWrite(dataList);
}
}最佳實(shí)踐
1. 性能優(yōu)化
public class OptimizedDynamicExport {
public void exportLargeData(List<String> fields) {
String fileName = "large_data_export.xlsx";
// 構(gòu)建表頭
List<List<String>> head = buildHeader(fields);
// 使用ExcelWriter進(jìn)行流式寫入
try (ExcelWriter excelWriter = EasyExcel.write(fileName).head(head).build()) {
WriteSheet writeSheet = EasyExcel.writerSheet("數(shù)據(jù)").build();
// 分批處理大量數(shù)據(jù)
int pageSize = 10000;
int pageNum = 1;
List<List<Object>> batchData;
do {
batchData = queryDataByPage(fields, pageNum, pageSize);
if (!batchData.isEmpty()) {
excelWriter.write(batchData, writeSheet);
}
pageNum++;
} while (batchData.size() == pageSize);
}
}
}2. 錯(cuò)誤處理
public class SafeDynamicExport {
public void safeExport(List<String> fields) {
try {
validateFields(fields);
List<List<String>> head = buildHeader(fields);
List<List<Object>> dataList = buildData(fields);
EasyExcel.write("safe_export.xlsx")
.head(head)
.sheet("數(shù)據(jù)")
.doWrite(dataList);
} catch (IllegalArgumentException e) {
log.error("字段驗(yàn)證失?。簕}", e.getMessage());
throw new BusinessException("導(dǎo)出字段配置錯(cuò)誤");
} catch (Exception e) {
log.error("導(dǎo)出過程中發(fā)生錯(cuò)誤:", e);
throw new BusinessException("數(shù)據(jù)導(dǎo)出失敗");
}
}
private void validateFields(List<String> fields) {
if (fields == null || fields.isEmpty()) {
throw new IllegalArgumentException("導(dǎo)出字段不能為空");
}
List<String> validFields = getValidFields();
for (String field : fields) {
if (!validFields.contains(field)) {
throw new IllegalArgumentException("無效的字段:" + field);
}
}
}
}總結(jié)
EasyExcel的動(dòng)態(tài)表頭功能非常強(qiáng)大,主要優(yōu)勢(shì)包括:
靈活性強(qiáng):可根據(jù)運(yùn)行時(shí)條件動(dòng)態(tài)生成表頭
支持多級(jí):能夠創(chuàng)建復(fù)雜的多級(jí)表頭結(jié)構(gòu)
易于擴(kuò)展:可與其他功能(樣式、驗(yàn)證等)結(jié)合使用
性能優(yōu)良:即使處理大量數(shù)據(jù)也能保持良好性能
在實(shí)際使用中,建議:
合理設(shè)計(jì)表頭結(jié)構(gòu),避免過于復(fù)雜
注意數(shù)據(jù)類型匹配,確保數(shù)據(jù)與表頭對(duì)應(yīng)
對(duì)用戶輸入進(jìn)行驗(yàn)證,防止惡意或錯(cuò)誤的字段配置
在處理大量數(shù)據(jù)時(shí)使用分批處理機(jī)制
通過動(dòng)態(tài)表頭功能,可以輕松實(shí)現(xiàn)靈活的數(shù)據(jù)導(dǎo)出需求,大大提升系統(tǒng)的可配置性和用戶體驗(yàn)。
到此這篇關(guān)于EasyExcel動(dòng)態(tài)表頭基礎(chǔ)用法及最佳實(shí)踐的文章就介紹到這了,更多相關(guān)EasyExcel動(dòng)態(tài)表頭內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java利用EasyExcel解析動(dòng)態(tài)表頭及導(dǎo)出實(shí)現(xiàn)過程
- Java如何利用Easyexcel動(dòng)態(tài)導(dǎo)出表頭列
- Java使用EasyExcel生成動(dòng)態(tài)表頭和多Sheet數(shù)據(jù)的Excel實(shí)例
- SpringBoot3整合EasyExcel動(dòng)態(tài)實(shí)現(xiàn)表頭重命名
- EasyExcel如何導(dǎo)出多級(jí)且動(dòng)態(tài)的表頭
- springboot結(jié)合easyexcel實(shí)現(xiàn)動(dòng)態(tài)表頭的實(shí)踐
相關(guān)文章
Java實(shí)戰(zhàn)之在線寄查快遞系統(tǒng)的實(shí)現(xiàn)
這篇文章主要介紹了如何利用Java制作一個(gè)在線寄查快遞系統(tǒng),文中采用的技術(shù)有java、SpringBoot、FreeMarker、Mysql,需要的可以參考一下2022-02-02
RestTemplate發(fā)送Post請(qǐng)求報(bào)錯(cuò):414 URI Too Long問題及解決
本文介紹了使用RestTemplate發(fā)送POST請(qǐng)求時(shí)遇到414 URITooLong錯(cuò)誤的原因,并提供了幾種解決方法,如使用LinkedMultiValueMap處理表單數(shù)據(jù)或?qū)?shù)拼接到URI上,同時(shí),強(qiáng)調(diào)了不要使用GET方法發(fā)送POST請(qǐng)求,并避免在URL中拼接參數(shù)2026-01-01
tio-http-server打包為二進(jìn)制文件的實(shí)現(xiàn)及優(yōu)勢(shì)詳解
這篇文章主要為大家介紹了tio-http-server打包為二進(jìn)制文件實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12
springboot的application.yml配置port不生效的解決方案
這篇文章主要介紹了springboot的application.yml配置port不生效的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07
Java并發(fā)編程中的生產(chǎn)者與消費(fèi)者模型簡(jiǎn)述
這篇文章主要介紹了Java并發(fā)編程中的生產(chǎn)者與消費(fèi)者模型簡(jiǎn)述,多線程并發(fā)是Java編程中最終要的部分之一,需要的朋友可以參考下2015-07-07
springmvc使用REST出現(xiàn):Request?method?'PUT'?not?sup
這篇文章主要介紹了springmvc使用REST出現(xiàn):Request?method?'PUT'?not?supported問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02

