package com.walker.di.excel; import com.alibaba.excel.EasyExcelFactory; import com.alibaba.excel.ExcelWriter; import com.alibaba.excel.write.builder.ExcelWriterBuilder; import com.alibaba.excel.write.metadata.WriteSheet; import com.walker.di.AbstractTemplateGenerator; import com.walker.di.Constants; import com.walker.di.TemplateException; import com.walker.infrastructure.utils.FileCopyUtils; import com.walker.infrastructure.utils.StringUtils; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * EasyExcel 实现的(导入)模板生成器对象。 * @author 时克英 * @date 2023-02-10 */ public abstract class ExcelTemplateGenerator extends AbstractTemplateGenerator { @Override protected File writeContent(List> data, Object option) throws TemplateException { logger.debug(data.toString()); logger.debug(option.toString()); String templatePath = this.acquireWriteFilePath(option); if(StringUtils.isEmpty(templatePath)){ throw new TemplateException("无法获取模板写入路径: acquireWriteFilePath() = null!", null); } File templateFile = new File(templatePath); logger.info("生成的模板文件:" + templateFile.getAbsolutePath()); InputStream templateFileStream = this.getClass().getClassLoader().getResourceAsStream(Constants.IMPORT_ERROR_FILE_TEMPLATE); OutputStream outputStream = null; try { outputStream = new BufferedOutputStream(new FileOutputStream(templateFile)); // 根据已有 Excel 模板文件,生成一个新导入模板,这样单元格都是已设置为文本。 FileCopyUtils.copy(templateFileStream, outputStream); // 这里拷贝完模板后,outputStream 已自动关闭,所以需要重新创建新输出流供写入 outputStream = new BufferedOutputStream(new FileOutputStream(templateFile)); ExcelWriterBuilder writer = EasyExcelFactory.write(outputStream); WriteSheet writeSheet = new WriteSheet(); writeSheet.setSheetName(Constants.EXCEL_SHEET_NAME); // 仅写入标题头,没有其他内容,data中只有一行数据 List> header = this.getHeader(data); writer.head(header); ExcelWriter excelWriter = writer.build(); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // List> content = new ArrayList<>(); // List testRow = new ArrayList<>(); // // 2023-02-07 data集合是每个字段信息,map中只有一个字段:字段id -> 描述 // for(int i=0; i< data.size(); i++){ // testRow.add(StringUtils.EMPTY_STRING); // logger.debug("写入空列一次:"); // } // logger.debug("data.get(0) = {}", data.get(0)); // content.add(testRow); //// content.add(StringUtils.asList(new String[]{"123","shikeying","1233889746596"})); // 写入测试数据,否则文档为空。 excelWriter.write(this.getEmptyRow(data), writeSheet); // 关闭文件 excelWriter.finish(); excelWriter.close(); return templateFile; } catch (Exception ex){ throw new TemplateException("写入模板内容错误:" + ex.getMessage() + ", templatePath=" + templatePath, ex); } finally { if(outputStream != null){ try { outputStream.close(); logger.debug("outputStream 已关闭"); } catch (IOException e) {} } } } /** * 写入一行空数据,否则不能触发Excel写入动作,会导致生成的Excel文件是空的。 * @param headers * @date 2023-02-08 * @return */ private List> getEmptyRow(List> headers){ List> content = new ArrayList<>(); List testRow = new ArrayList<>(); // 2023-02-07 data集合是每个字段信息,map中只有一个字段:字段id -> 描述 for(int i=0; i< headers.size(); i++){ testRow.add(StringUtils.EMPTY_STRING); // logger.debug("写入空列一次:"); } // logger.debug("data.get(0) = {}", headers.get(0)); content.add(testRow); return content; } /** * 目前仅支持list中第一条数据写入表头,其他行暂不支持。 *
     *     1)List 中是多个字段集合
     *     2)Map 中只有一个字段信息,如: id --> 人员编号
     * 
* @param headers 提供的原始列名称集合 * @return 返回 EasyExcel 需要用的列集合格式 */ private List> getHeader(List> headers){ // Map map = headers.get(0); List> headerList = new ArrayList<>(); // for(Map.Entry entry : map.entrySet()){ // headers.add(StringUtils.asList(new String[]{entry.getValue(), entry.getKey()})); // } for(Map oneFieldInfo : headers){ // 每个map中只有一个字段 for(Map.Entry entry : oneFieldInfo.entrySet()){ headerList.add(StringUtils.asList(new String[]{entry.getValue(), entry.getKey()})); } } return headerList; } /** * 获取要写入模板文件的具体路径,如: d:/demo/template/123.xlsx * @param option * @return */ protected abstract String acquireWriteFilePath(Object option); }