@Data
public class FastExcelUtils<T, R, E> {
private Class<R> resultType;
private Class<E> excelType;
private Function<R, E> resultDtoToExcelDtoConvertor;
private static final int MAX_LOOP_TIMES = 10000;
private static final WebQHLogger LOG = WebQHLogger.getLogger(FastExcelUtils.class);
public void exportData(
@NotNull final HttpServletResponse response,
final String fileName,
@NotNull T queryParam,
@NotNull Function<T, ListResult<R>> query,
@NotNull Consumer<T> updateQueryParam) throws BizzException {
setResponseHeader(response, fileName);
LOG.info("开始导出数据");
int loop = 0;
try (ExcelWriter writer = FastExcel
.write(response.getOutputStream())
.head(excelType)
.autoCloseStream(true)
.build()) {
final WriteSheet sheet = FastExcel.writerSheet().build();
ListResult<R> listResult;
do {
listResult = query.apply(queryParam);
if (listResult == null) {
throw new BizzException("导出数据失败,返回为null");
}
final List<E> excelDtos = resultDtoToExcelDto(listResult.getResult());
writer.write(excelDtos, sheet);
updateQueryParam.accept(queryParam);
} while (BooleanUtils.isTrue(listResult.getHasMore()) && ++loop < MAX_LOOP_TIMES);
} catch (BizzException e) {
LOG.warn("导出数据异常", e);
throw e;
} catch (Exception e) {
LOG.error("导出数据异常", e);
throw new BizzException("导出数据失败");
}
if (loop >= MAX_LOOP_TIMES) {
LOG.warn("导出数据异常,循环次数超过限制");
throw new BizzException("导出数据异常,超出循环次数");
}
LOG.info("导出数据结束");
}
private void setResponseHeader(HttpServletResponse response, final String fileName) {
String exportFileName = StringUtils.defaultIfBlank(fileName, "export");
exportFileName = StringUtils.endsWithIgnoreCase(exportFileName, ".xlsx") ?
exportFileName : (exportFileName + ".xlsx");
try {
exportFileName = URLEncoder.encode(exportFileName, StandardCharsets.UTF_8.toString());
} catch (UnsupportedEncodingException e) {
LOG.warn("URLEncoder.encode fail", e);
}
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-disposition", "attachment;filename=" + exportFileName);
response.setCharacterEncoding("utf8");
response.setHeader("Cache-Control", "no-store");
response.addHeader("Cache-Control", "max-age=0");
}
private E resultDtoToExcelDto(R resultDto) {
if (this.resultDtoToExcelDtoConvertor != null) {
return this.resultDtoToExcelDtoConvertor.apply(resultDto);
}
return BeanConvertUtils.convert(resultDto, this.resultType, this.excelType);
}
private List<E> resultDtoToExcelDto(List<R> resultDto) {
return resultDto.stream().map(this::resultDtoToExcelDto).collect(Collectors.toList());
}
}