利用EasyPOI實(shí)現(xiàn)多sheet和列數(shù)的動(dòng)態(tài)生成
一、背景
公司有個(gè)報(bào)表需求是根據(jù)指定日期范圍導(dǎo)出指定數(shù)據(jù),并且要根據(jù)不同邏輯生成兩個(gè)Sheet,這個(gè)日期影響的是列數(shù)而不是行數(shù),即行的數(shù)量和列的數(shù)量都是動(dòng)態(tài)變化的,根據(jù)用戶的選擇動(dòng)態(tài)生成的,這個(gè)問題花了不少時(shí)間才解決的,這邊記下筆記。
二、效果圖
動(dòng)態(tài)生成30個(gè)列,兩張Sheet

動(dòng)態(tài)生成1個(gè)列,兩張Sheet

三 、準(zhǔn)備
我們公司使用的版本是3.2.0,我們項(xiàng)目沒有引入所有模塊,只用到了base和annotation
<dependency> <groupId>cn.afterturn</groupId> <artifactId>easypoi-base</artifactId> <version>3.2.0</version> <exclusions> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> </exclusion> <exclusion> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>cn.afterturn</groupId> <artifactId>easypoi-annotation</artifactId> <version>3.2.0</version> </dependency>
四、詳細(xì)步驟
定義表格樣式
/**
* 定義表格樣式
*
* @param start 查詢起始日期
* @param end 查詢結(jié)束日期
* @return java.util.List<cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity>
* @author huan
* @date 2019/6/21
* @since 2.8.2
*/
private List<ExcelExportEntity> setExportExcelStyle(DateTime start, DateTime end) {
//定義表格列名,該集合存放的就是表格的列明,每個(gè)對(duì)象就是表格中的一列
List<ExcelExportEntity> modelList = new ArrayList<ExcelExportEntity>();
//該對(duì)象就是定義列屬性的對(duì)象
ExcelExportEntity excelentity = null;
//定義第一個(gè)列
excelentity = new ExcelExportEntity("企業(yè)全稱", "companyName");
excelentity.setWidth(20);
excelentity.setHeight(10);
modelList.add(excelentity);
//定義第二個(gè)列
excelentity = new ExcelExportEntity("企業(yè)簡(jiǎn)稱", "companyShortName");
excelentity.setWidth(20);
excelentity.setHeight(10);
modelList.add(excelentity);
//定義第三個(gè)列,這里指定了日期顯示格式
excelentity = new ExcelExportEntity("認(rèn)證日期", "openDate");
excelentity.setWidth(20);
excelentity.setHeight(10);
excelentity.setFormat("yyyy-MM-dd");
modelList.add(excelentity);
//定義第四個(gè)列,這邊就是動(dòng)態(tài)生成的,跟用用戶選擇的日期范圍,動(dòng)態(tài)生成列的數(shù)量
excelentity = new ExcelExportEntity(null, "recordDate");
//設(shè)置一個(gè)集合,存放動(dòng)態(tài)生成的列
List<ExcelExportEntity> modelListChild = new ArrayList<ExcelExportEntity>();
start = DateUtils.getDateZeroTime(start);
while (start.isBefore(end)) {
String date = start.toString("yyyy-MM-dd");
modelListChild.add(new ExcelExportEntity(date, date, 15));
start = start.plusDays(1);
}
//日期按從小到大順序排序,這里用了最簡(jiǎn)單的冒泡排序
for (int i = 0; i < modelListChild.size(); i++) {
for (int j = 0; j < modelListChild.size(); j++) {
String e1 = modelListChild.get(i).getKey().toString();
String e2 = modelListChild.get(j).getKey().toString();
if (e1.compareTo(e2) < 0) {
ExcelExportEntity x1 = modelListChild.get(i);
ExcelExportEntity x2 = modelListChild.get(j);
modelListChild.set(j, x1);
modelListChild.set(i, x2);
}
}
}
//將定義好的字列放到父列中
excelentity.setList(modelListChild);
modelList.add(excelentity);
//定義第五個(gè)列
excelentity = new ExcelExportEntity("應(yīng)當(dāng)使用天數(shù)", "shouldUseDay");
excelentity.setWidth(20);
excelentity.setHeight(10);
modelList.add(excelentity);
//定義第六個(gè)列
excelentity = new ExcelExportEntity("實(shí)際使用天數(shù)", "actualUseDay");
excelentity.setWidth(20);
excelentity.setHeight(10);
modelList.add(excelentity);
//定義第七個(gè)列
excelentity = new ExcelExportEntity("使用率", "rate");
excelentity.setWidth(20);
excelentity.setHeight(10);
modelList.add(excelentity);
//定義第八個(gè)列
excelentity = new ExcelExportEntity("推薦人", "commandMan");
excelentity.setWidth(20);
excelentity.setHeight(10);
modelList.add(excelentity);
//定義第九個(gè)列
excelentity = new ExcelExportEntity("拓客", "tk");
excelentity.setWidth(20);
excelentity.setHeight(10);
modelList.add(excelentity);
//定義第十個(gè)列
excelentity = new ExcelExportEntity("對(duì)接人", "connector");
excelentity.setWidth(20);
excelentity.setHeight(10);
modelList.add(excelentity);
return modelList;
}
定義表格數(shù)據(jù)
private List<Map<String, Object>> getData(AnalyseStockQuery analyseStockQuery, boolean type) {
//獲取數(shù)據(jù)源
ArrayList<AnalyseStockExportDto> dtoList = listDetailDataWithNum(analyseStockQuery, type);
List<Map<String, Object>> dataList = new ArrayList<>();
//存儲(chǔ)沒一行中的日期數(shù)據(jù)
List<Map<String, Object>> dataListChild = null;
//存儲(chǔ)表格中的每一行數(shù)據(jù)
Map<String, Object> mapParent = null;
//數(shù)據(jù)排序
dtoList.sort(new ExportComparator());
//定義表格數(shù)據(jù)
for (AnalyseStockExportDto dto : dtoList) {
mapParent = new HashMap(7);
//這邊只要和定義表格樣式的時(shí)候 名稱一致就行 我這邊因?yàn)橛腥齻€(gè)字段不需要我這邊后臺(tái)生成,所以就沒有設(shè)置默認(rèn)值了
mapParent.put("companyName", dto.getCompanyName());
mapParent.put("companyShortName", dto.getCompanyShortName());
mapParent.put("openDate", dto.getOpenDate());
mapParent.put("shouldUseDay", dto.getShouldUseDay());
mapParent.put("actualUseDay", dto.getActualUseDay());
mapParent.put("rate", dto.getRate());
Map<String, Object> map = dto.getDateList();
dataListChild = new ArrayList<>();
dataListChild.add(map);
mapParent.put("recordDate", dataListChild);
dataList.add(mapParent);
}
return dataList;
}
主體方法
/**
* 報(bào)表導(dǎo)出
*
* @param analyseStockQuery analyseStockQuery
* @param response response
* @return javax.servlet.http.HttpServletResponse
* @author huan
* @date 2019/6/21
* @since 2.8.2
*/
public HttpServletResponse exportStock(AnalyseStockQuery analyseStockQuery, HttpServletResponse response) {
try {
//設(shè)置默認(rèn)查詢?nèi)掌?
analyseStockQuery = setDefaultQueryDate(analyseStockQuery);
//參數(shù)校驗(yàn)
checkListDetailDataParam(analyseStockQuery);
//日期格式化
DateTime start = new DateTime().withDate(new LocalDate(analyseStockQuery.getQueryStartDate()));
DateTime end = new DateTime().withDate(new LocalDate(analyseStockQuery.getQueryLastDate()));
//定義表格樣式
List<ExcelExportEntity> modelList = setExportExcelStyle(start, end);
//定義表格名稱
String fileName = URLEncoder.encode("客戶庫存使用統(tǒng)計(jì)表-" + start.toString("yyyy年MM月dd日") + "~" + end.toString("yyyy年MM月dd日"), "utf-8");
// Sheet1樣式
ExportParams sheet1ExportParams = new ExportParams();
// 設(shè)置sheet得名稱
sheet1ExportParams.setSheetName("入庫統(tǒng)計(jì)");
// 創(chuàng)建sheet1使用得map
Map<String, Object> sheet1ExportMap = new HashMap<>();
// title的參數(shù)為ExportParams類型,目前僅僅在ExportParams中設(shè)置了sheetName
sheet1ExportMap.put("title", sheet1ExportParams);
//sheet1樣式
sheet1ExportMap.put("entityList", modelList);
//sheet1中要填充得數(shù)據(jù),true表示查詢?nèi)霂鞌?shù)據(jù),false表示查詢易簽待入庫數(shù)據(jù)
sheet1ExportMap.put("data", getData(analyseStockQuery, true));
//Sheet2設(shè)置
ExportParams sheet2ExportParams = new ExportParams();
sheet2ExportParams.setSheetName("易簽待入庫統(tǒng)計(jì)");
Map<String, Object> sheet2ExportMap = new HashMap<>();
sheet2ExportMap.put("title", sheet2ExportParams);
sheet2ExportMap.put("entityList", modelList);
sheet2ExportMap.put("data", getData(analyseStockQuery, false));
// 將sheet1、sheet2使用得map進(jìn)行包裝
List<Map<String, Object>> sheetsList = new ArrayList<>();
sheetsList.add(sheet1ExportMap);
sheetsList.add(sheet2ExportMap);
// 執(zhí)行方法
Workbook workBook = exportExcel(sheetsList, ExcelType.HSSF);
//設(shè)置response
response.setHeader("content-disposition", "attachment;filename=" + fileName + ".xls");
//設(shè)置編碼格式
response.setCharacterEncoding("GBK");
//將表格內(nèi)容寫到輸出流中并刷新緩存
@Cleanup ServletOutputStream out = response.getOutputStream();
workBook.write(out);
out.flush();
workBook.close();
} catch (FileNotFoundException e) {
log.debug("FileNotFoundException:{}", e.getMessage());
} catch (UnsupportedEncodingException e) {
log.debug("UnsupportedEncodingException:{}", e.getMessage());
} catch (IOException e) {
log.debug("IOException:{}", e.getMessage());
}
return response;
}
導(dǎo)出Excel
/**
* 導(dǎo)出Ecel
*
* @return org.apache.poi.ss.usermodel.Workbook
* @author zhuyongsheng
* @date 2019/11/6
*/
private static Workbook exportExcel(List<Map<String, Object>> list) {
Workbook workbook = new HSSFWorkbook();
for (Map<String, Object> map : list) {
MyExcelExportService service = new MyExcelExportService();
service.createSheetWithList(workbook, (ExportParams) map.get("title"), ExportParams.class,
(List<ExcelExportEntity>) map.get("entityList"), (Collection<?>) map.get("data"));
}
return workbook;
}
自定義導(dǎo)出邏輯
package com.ccb.service.analyse;
import cn.afterturn.easypoi.excel.annotation.ExcelTarget;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import cn.afterturn.easypoi.excel.export.ExcelExportService;
import cn.afterturn.easypoi.exception.excel.ExcelExportException;
import cn.afterturn.easypoi.exception.excel.enums.ExcelExportEnum;
import cn.afterturn.easypoi.util.PoiPublicUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* 自定義下導(dǎo)出邏輯
* @author huan
* @version 2.8.2
* @date 2019/7/5
*/
@Slf4j
public class MyExcelExportService extends ExcelExportService {
public void createSheetWithList(Workbook workbook, ExportParams entity, Class<?> pojoClass, List<ExcelExportEntity> entityList, Collection<?> dataSet) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Excel export start ,class is {}", pojoClass);
LOGGER.debug("Excel version is {}",
entity.getType().equals(ExcelType.HSSF) ? "03" : "07");
}
if (workbook == null || entity == null || pojoClass == null || dataSet == null) {
throw new ExcelExportException(ExcelExportEnum.PARAMETER_ERROR);
}
try {
List<ExcelExportEntity> excelParams = entityList;
// 得到所有字段
Field[] fileds = PoiPublicUtil.getClassFields(pojoClass);
ExcelTarget etarget = pojoClass.getAnnotation(ExcelTarget.class);
String targetId = etarget == null ? null : etarget.value();
getAllExcelField(entity.getExclusions(), targetId, fileds, excelParams, pojoClass,
null, null);
//獲取所有參數(shù)后,后面的邏輯判斷就一致了
createSheetForMap(workbook, entity, excelParams, dataSet);
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
throw new ExcelExportException(ExcelExportEnum.EXPORT_ERROR, e.getCause());
}
}
}以上就是利用EasyPOI實(shí)現(xiàn)多sheet和列數(shù)的動(dòng)態(tài)生成的詳細(xì)內(nèi)容,更多關(guān)于EasyPOI生成多sheet和列數(shù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
HttpUtils 發(fā)送http請(qǐng)求工具類(實(shí)例講解)
下面小編就為大家?guī)硪黄狧ttpUtils 發(fā)送http請(qǐng)求工具類(實(shí)例講解)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-07-07
Spring Boot 緩存管理與優(yōu)化實(shí)例教程
本文介紹了SpringBoot緩存管理與優(yōu)化的核心概念與使用方法,文中通過示例介紹了如何使用SpringCache進(jìn)行集成,并給出了一些常見的緩存策略,感興趣的朋友跟隨小編一起看看吧2026-04-04
Java算法練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(2)
方法下面小編就為大家?guī)硪黄狫ava算法的一道練習(xí)題(分享)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧,希望可以幫到你2021-07-07
springboot?整合?dubbo?的實(shí)現(xiàn)組聚合詳情
這篇文章主要介紹了springboot整合dubbo的實(shí)現(xiàn)組聚合詳情,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-07-07
Spring Boot通過Redis實(shí)現(xiàn)防止重復(fù)提交
表單提交是一個(gè)非常常見的功能,如果不加控制,容易因?yàn)橛脩舻恼`操作或網(wǎng)絡(luò)延遲導(dǎo)致同一請(qǐng)求被發(fā)送多次,本文主要介紹了Spring Boot通過Redis實(shí)現(xiàn)防止重復(fù)提交,具有一定的參考價(jià)值,感興趣的可以了解一下2024-06-06

