1:依赖(Maven)
XML
<!-- FastExcel 官网最新版 -->
<dependency>
<groupId>cn.idev.excel</groupId>
<artifactId>fastexcel</artifactId>
<version>1.0.0</version>
</dependency>
2:导出 + ZIP 工具类
java
@SneakyThrows
@Override
public void dataListExport(TargetIndexDataListExportDto dto, HttpServletResponse response) {
// 获取有权限的门店集合
Map<String, StoreInfoListVO> storeMap = getStoreList(new ArrayList<>());
List<String> storeList = new ArrayList<>(storeMap.keySet());
TargetIndexPageListDto dtoFilter = new TargetIndexPageListDto();
dtoFilter.setIndexList(dto.getIndicatorListId());
dtoFilter.setYearList(dto.getYearList());
response.setContentType("application/zip");
response.setCharacterEncoding("utf-8");
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("年度目标汇总.zip", StandardCharsets.UTF_8));
// 使用 try-with-resources 确保流正确关闭
try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
// 查询各指标年度目标
List<TargetIndexPageListVo> yearPageList = this.baseMapper.getYearList(dtoFilter);
// 获取各个指标门店目标信息
List<String> indexList = yearPageList.stream().map(TargetIndexPageListVo::getId).distinct().collect(Collectors.toList());
List<TargetStoreListVo> storeTargetList = CollUtil.isNotEmpty(storeMap) ? this.baseMapper.getStoreTargetList(indexList, new ArrayList<>(storeMap.keySet())) : List.of();
Map<String, TargetStoreListVo> storeTargetMap = CollUtil.isNotEmpty(storeTargetList) ? storeTargetList.stream()
.collect(Collectors.toMap(TargetStoreListVo::getIndexId, Function.identity())) : new HashMap<>();
yearPageList.forEach(vo -> {
if (!storeTargetMap.containsKey(vo.getId())) {
vo.setApprovalInfo("无");
return;
}
TargetStoreListVo storeListVo = storeTargetMap.get(vo.getId());
vo.setStoreIds(Arrays.asList(storeListVo.getStoreIdsStr().split(",")));
vo.setTotalTarget(storeListVo.getTotalTarget());
vo.setApprovalInfo(storeListVo.getApprovalInfo());
vo.setUpdateTime(storeListVo.getUpdateTime());
});
// 计算指标完成率方法
calculateIndexCompletionRate(yearPageList);
int minYear = yearPageList.stream().mapToInt(TargetIndexPageListVo::getYear).min().orElse(0);
int maxYear = yearPageList.stream().mapToInt(TargetIndexPageListVo::getYear).max().orElse(0);
String fileNamePrefix = minYear != maxYear ? minYear + "~" + maxYear : String.valueOf(maxYear);
// 生成指标年度汇总文件
TargetCalculateUtils.generateIndexStaExcelFile(zipOut, fileNamePrefix, yearPageList);
// 查询各门店各指标月目标
List<TargetIndexStoreMonthVo> storeMonthList = CollUtil.isNotEmpty(storeList) ? this.baseMapper.getStoreMonthList(dtoFilter, storeList) : List.of();
// 获取门店指标年度完成率
Map<String, List<StoreIndexYearStaVo>> storeTargetYearMap = TargetCalculateUtils.getStoreYearTargetMap(storeMonthList);
getAndSetStoreYearTarget(storeTargetYearMap);
// 获取门店指标月度目标
Map<String, List<StoreIndexMonthStaVo>> storeMonthTargetMap = TargetCalculateUtils.getStoreMonthTargetMap(storeMonthList);
// 获取门店指标月度目标完成率
getAndSetStoreMonthTarget(storeMonthTargetMap);
// 指标项id集合
List<String> indexItemList = yearPageList.stream().map(TargetIndexPageListVo::getIndexId).distinct().collect(Collectors.toList());
// 获取涉及到的指标集合
List<IndicatorsTypeEnums> typeEnums = IndicatorsTypeEnums.getIndicatorsStrListEnum(indexItemList);
Map<String, List<TargetIndexPageListVo>> indexMao = yearPageList.stream().collect(Collectors.groupingBy(TargetIndexPageListVo::getIndexId));
// 生成门店年度汇总以及月度汇总文件
for (IndicatorsTypeEnums enums : typeEnums) {
if (!indexMao.containsKey(enums.getField())) {
continue;
}
minYear = indexMao.get(enums.getField()).stream().mapToInt(TargetIndexPageListVo::getYear).min().orElse(0);
maxYear = indexMao.get(enums.getField()).stream().mapToInt(TargetIndexPageListVo::getYear).max().orElse(0);
fileNamePrefix = minYear != maxYear ? minYear + "~" + maxYear : String.valueOf(maxYear);
TargetCalculateUtils.generateSingleIndexStaExcelFile(zipOut, fileNamePrefix, storeTargetYearMap.getOrDefault(enums.getField(), new ArrayList<>()),
storeMonthTargetMap.getOrDefault(enums.getField(), new ArrayList<>()), enums, storeMap);
}
zipOut.finish();
} catch (IOException e) {
throw new RuntimeException("生成ZIP文件失败", e);
}
}
java
/**
* 生成指标年度汇总文件
*
* @param zipOut ZIP输出流
* @param fileNamePrefix 文件名前缀
* @param yearPageList 列表数据
* @throws IOException 抛出的异常
*/
public static void generateIndexStaExcelFile(ZipOutputStream zipOut, String fileNamePrefix, List<TargetIndexPageListVo> yearPageList) throws IOException {
ZipEntry zipEntry = new ZipEntry(fileNamePrefix + "年度年目标.xlsx");
zipOut.putNextEntry(zipEntry);
try (ExcelWriter indexStaExcelWriter = EasyExcel.write(zipOut).autoCloseStream(false).build()) {
WriteSheet userBasicSheet = EasyExcel.writerSheet(0, fileNamePrefix + "年目标")
.head(TargetIndexExportStaVo.class)
.build();
List<TargetIndexExportStaVo> yearPageListVoList = yearPageList.stream().map(item -> {
TargetIndexExportStaVo vo = new TargetIndexExportStaVo();
BeanUtils.copyProperties(item, vo);
vo.setTotalTarget(Objects.nonNull(item.getTotalTarget()) ? item.getTotalTarget().stripTrailingZeros().toPlainString() + item.getIndexUnit() : "-");
vo.setProgress(Objects.nonNull(item.getProgress()) ? item.getProgress().stripTrailingZeros().toPlainString() + item.getIndexUnit() : "-");
vo.setFinishRate(Objects.nonNull(item.getYearFinishRate()) ? item.getYearFinishRate().stripTrailingZeros().toPlainString() + "%" : "-");
return vo;
}).collect(Collectors.toList());
indexStaExcelWriter.write(yearPageListVoList, userBasicSheet);
indexStaExcelWriter.finish();
} catch (Exception e) {
try {
zipOut.closeEntry();
} catch (IOException ignored) {
}
throw e;
}
zipOut.closeEntry();
}
/**
* 按单个指标生成年度-月度汇总数据
*
* @param zipOut ZIP输出流
* @param fileNamePrefix 文件名前缀
* @param storeTargetYearList 门店年目标集合
* @param storeMonthTargetList 门店月目标集合
* @param enums 指标
* @param storeMap 门店集合
* @throws IOException 抛出的异常
*/
public static void generateSingleIndexStaExcelFile(ZipOutputStream zipOut, String fileNamePrefix, List<StoreIndexYearStaVo> storeTargetYearList,
List<StoreIndexMonthStaVo> storeMonthTargetList, IndicatorsTypeEnums enums,
Map<String, StoreInfoListVO> storeMap) throws IOException {
ZipEntry zipEntry = new ZipEntry(enums.getName() + "门店" + fileNamePrefix + "目标汇总.xlsx");
zipOut.putNextEntry(zipEntry);
try (ExcelWriter excelWriter = EasyExcel.write(zipOut).autoCloseStream(false).build()) {
// Sheet1: 门店指标年目标汇总
WriteSheet yearSheet = EasyExcel.writerSheet(0, enums.getName() + "门店年目标")
.head(TargetIndexExportStoreStaVo.class)
.registerWriteHandler(new CustomHeaderWriteHandler(Objects.nonNull(enums.getUnit()) ? enums.getName() + "(" + enums.getUnit() + ")" : enums.getName()))
.build();
excelWriter.write(getYearSheetData(enums, storeTargetYearList, storeMap), yearSheet);
// Sheet2: 门店指标月目标汇总
for (int month = 1; month <= 12; month++) {
WriteSheet monthSheet = EasyExcel.writerSheet(month, "门店" + month + "月目标")
.head(TargetIndexExportStoreMonthStaVo.class)
.registerWriteHandler(new CustomMonthHeaderWriteHandler(Objects.nonNull(enums.getUnit()) ?
enums.getName() + "(" + enums.getUnit() + ")" : enums.getName(), month))
.build();
excelWriter.write(getMonthSheetDataByMonth(enums, storeMonthTargetList, month, storeMap), monthSheet);
}
excelWriter.finish();
} catch (Exception e) {
try {
zipOut.closeEntry();
} catch (IOException ignored) {
}
throw e;
}
zipOut.closeEntry();
}
private static List<TargetIndexExportStoreStaVo> getYearSheetData(IndicatorsTypeEnums enums, List<StoreIndexYearStaVo> storeTargetYearList,
Map<String, StoreInfoListVO> storeMap) {
return storeTargetYearList.stream().map(item -> {
TargetIndexExportStoreStaVo vo = new TargetIndexExportStoreStaVo();
BeanUtils.copyProperties(item, vo);
if (storeMap.containsKey(item.getStoreId())) {
vo.setStoreName(storeMap.get(item.getStoreId()).getName());
}
vo.setTotalTarget(Objects.nonNull(item.getTotalTarget()) ? item.getTotalTarget().stripTrailingZeros().toPlainString() + enums.getUnit() : "-");
vo.setProgress(Objects.nonNull(item.getProgress()) ? item.getProgress().stripTrailingZeros().toPlainString() + enums.getUnit() : "-");
vo.setFinishRate(Objects.nonNull(item.getFinishRate()) ? item.getFinishRate().stripTrailingZeros().toPlainString() + "%" : "-");
return vo;
}).collect(Collectors.toList());
}
/**
* 获取指定月份的月度数据
*
* @param enums 指标枚举
* @param storeMonthTargetList 月度目标数据集合
* @param month 指定月份
* @param storeMap 门店集合
* @return 指定月份的数据列表
*/
private static List<TargetIndexExportStoreMonthStaVo> getMonthSheetDataByMonth(IndicatorsTypeEnums enums, List<StoreIndexMonthStaVo> storeMonthTargetList,
int month, Map<String, StoreInfoListVO> storeMap) {
List<StoreIndexMonthStaVo> result = new ArrayList<>();
storeMonthTargetList.stream().filter(item -> item.getMonth() != null && item.getMonth() == month).forEach(result::add);
return result.stream().map(item -> {
TargetIndexExportStoreMonthStaVo vo = new TargetIndexExportStoreMonthStaVo();
BeanUtils.copyProperties(item, vo);
if (storeMap.containsKey(item.getStoreId())) {
vo.setStoreName(storeMap.get(item.getStoreId()).getName());
}
vo.setTotalTarget(Objects.nonNull(item.getTotalTarget()) ? item.getTotalTarget().stripTrailingZeros().toPlainString() + enums.getUnit() : "-");
vo.setProgress(Objects.nonNull(item.getProgress()) ? item.getProgress().stripTrailingZeros().toPlainString() + enums.getUnit() : "-");
vo.setFinishRate(Objects.nonNull(item.getFinishRate()) ? item.getFinishRate().stripTrailingZeros().toPlainString() + "%" : "-");
return vo;
}).collect(Collectors.toList());
}
