• Java根据excel模版导出Excel(easyexcel、poi)——含项目测试例子拿来即用


    1. 前言

    1.1 关于Excel的一般导出

    2.2 关于easyexcel的根据模版导出

    • 如果使用easy Excel的话,下面就不用看了,这个官网关于怎么使用以及例子提供的非常详细,git上还能下载源码,官网如下,使用不再介绍,具体看官网即可:
      Easy Excel 之 填充excel.

    2. 先看效果

    2.1 模版

    • 静态填充简单模版如下:
      在这里插入图片描述
    • 动态填充简单模版:
      • 单个list:
        在这里插入图片描述
      • 多个list:
        在这里插入图片描述
      • 单个list单条数据:
        在这里插入图片描述

    2.2 效果

    • 静态填充效果如下:
      在这里插入图片描述
    • 动态填充效果如下:
      • 单个list:
        在这里插入图片描述
      • 多个list:
        在这里插入图片描述
      • 单个list单条数据:
        在这里插入图片描述

    3. 代码实现(核心代码)

    3.1 项目代码结构

    • 如下:
      在这里插入图片描述

    3.2 静态填充例子代码

    • 工具类代码已封装,所以调用很简单即可实现,如下:
      在这里插入图片描述

    3.3 动态list填充代码

    • 单个list:
      在这里插入图片描述
    • 多个list
      在这里插入图片描述
    • 单个list单条数据:
      在这里插入图片描述

    3.4 附核心代码

    3.4.1 object转map工具类

    • MapObjectUtil.java 如下:
      package com.liu.susu.excel.template.poi.common;
      
      import com.alibaba.fastjson.JSONObject;
      import com.liu.susu.excel.template.poi.example.data.DogEntity2;
      import org.apache.commons.beanutils.BeanMap;
      
      import java.lang.reflect.Field;
      import java.util.ArrayList;
      import java.util.HashMap;
      import java.util.List;
      import java.util.Map;
      
      /**
       * @Description
       * @Author susu
       * @Date 2024/2/19
       */
      public class MapObjectUtil {
      
          /**
          * @description: 将object的list数据 转换成 map的list(如:List>)
          * @param objDataList
          * @return java.util.List>
          * @author susu
          */
          public static List<Map<String, Object>> objListToMapList(List<?> objDataList){
              List<Map<String, Object>> dataList = new ArrayList<>();
              if (objDataList==null || objDataList.size()<1){
                  return null;
              }
              objDataList.forEach(obj->{
                  try {
                      Map<String, Object> map = MapObjectUtil.objectToMap(obj);
                      dataList.add(map);
                  } catch (IllegalAccessException e) {
                      throw new RuntimeException(e);
                  }
              });
              return dataList;
          }
      
          /**
          * @description: 将object数据转换成map数据
          * @param obj
          * @return java.util.Map
          * @author susu
          */
          public static Map<String, Object> objectToMap(Object obj) throws IllegalAccessException {
              Map<String, Object> map = new HashMap();
              Class<?> cla = obj.getClass();
              Field[] fields = cla.getDeclaredFields();
              for (Field field : fields) {
                  field.setAccessible(true);
                  String keyName = field.getName();
                  Object value = field.get(obj);
                  if (value == null)
                      value = "";
                  map.put(keyName, value);
              }
              return map;
          }
      
          /**
          * @description: 使用 JSONObject 将object转换成map
          * @param obj
          * @return java.util.Map
          * @author susu
          */
          public static Map<?, ?> objectToMap2(Object obj) {
              if (obj == null)
                  return null;
              return JSONObject.parseObject(JSONObject.toJSONString(obj),Map.class);
          }
      
          /**
          * @description: 使用BeanMap将object转换成map
          * @param obj
          * @return java.util.Map
          * @author susu
          */
          public static Map<?, ?> objectToMap3(Object obj) {
              if (obj == null)
                  return null;
              return new BeanMap(obj);
          }
      
      
          public static void main(String[] args) {
              DogEntity2 dog = new DogEntity2();
              dog.setDogId("A-1001");
              dog.setDogAge(3);
              dog.setDogName("aaa");
      //        Map map = JSONObject.parseObject(JSONObject.toJSONString(dog),Map.class);
              Map map = objectToMap2(dog);
              System.out.println(map);
          }
      
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
      • 71
      • 72
      • 73
      • 74
      • 75
      • 76
      • 77
      • 78
      • 79
      • 80
      • 81
      • 82
      • 83
      • 84
      • 85
      • 86
      • 87
      • 88
      • 89
      • 90
      • 91
      • 92
      • 93
      • 94
      • 95
      • 96
      • 97
      • 98

    3.4.2 根据模版导出Excel程序代码

    • ExcelTemplateProc.java 如下:
      package com.liu.susu.excel.template.poi.common;
      
      import org.apache.commons.lang3.StringUtils;
      import org.apache.poi.ss.usermodel.CellCopyPolicy;
      import org.apache.poi.ss.usermodel.Workbook;
      import org.apache.poi.xssf.usermodel.XSSFCell;
      import org.apache.poi.xssf.usermodel.XSSFRow;
      import org.apache.poi.xssf.usermodel.XSSFSheet;
      import org.apache.poi.xssf.usermodel.XSSFWorkbook;
      import org.springframework.util.ResourceUtils;
      
      
      import java.io.*;
      import java.util.List;
      import java.util.Map;
      
      /**
       * @Description 根据模版导出Excel程序
       * @Author susu
       * @Date 2024/2/19
       */
      public class ExcelTemplateProc {
      
          /**
           * @param templateFileName
           * @param exportFilePathAndName
           * @param staticDataMap
           * @param dynamicDataMappingList
           * @return void
           * @description: 根据模版导出Excel入口
           * @author susu
           * @date 2024/2/20
           */
          public static void doExportExcelByTemplateProc(String templateFileName, String exportFilePathAndName,
                                                         Map<String, Object> staticDataMap,
                                                         List<DynamicDataMapping> dynamicDataMappingList) throws IOException {
              /**
               * 1. 从resources下加载模板并替换
               *    使用 ResourceUtils 加载文件
               */
              File file = ResourceUtils.getFile("classpath:"+templateFileName);
              InputStream inputStream = new FileInputStream(file);
      
              Workbook workbook = dealFirstSheetByTemplate(inputStream, staticDataMap, dynamicDataMappingList);
              // 2. 保存到本地
              saveExportFile(workbook, exportFilePathAndName);
          }
      
          /**
           * @param workbook
           * @param excelFilePath
           * @return void
           * @description: 保存导出的Excel文件到服务器
           * @author susu
           * @date 2024/2/20
           */
          public static void saveExportFile(Workbook workbook, String excelFilePath) throws IOException {
              FileOutputStream outputStream = new FileOutputStream(excelFilePath);
              executeWorkBookWrite(workbook, outputStream);
          }
      
          /**
           * @param workbook
           * @param outputStream
           * @return void
           * @description: 数据输出
           * @author susu
           * @date 2024/2/20
           */
          public static void executeWorkBookWrite(Workbook workbook, OutputStream outputStream) throws IOException {
              workbook.write(outputStream);
              outputStream.flush();
              outputStream.close();
              workbook.close();
          }
      
          /**
           * @param inputStream
           * @param staticDataMap
           * @param dynamicDataMappingList
           * @return org.apache.poi.ss.usermodel.Workbook
           * @description: 处理只有一个sheet页的模版
           * @author susu
           * @date 2024/2/20
           */
          public static Workbook dealFirstSheetByTemplate(InputStream inputStream,
                                                          Map<String, Object> staticDataMap,
                                                          List<DynamicDataMapping> dynamicDataMappingList) throws IOException {
              XSSFWorkbook workbook = new XSSFWorkbook(inputStream);
              XSSFSheet sheet = workbook.getSheetAt(0);
              // 按模板处理sheet页
              dealSheetDataByTemplate(sheet, staticDataMap, dynamicDataMappingList);
              return workbook;
          }
      
          /**
           * @param sheet
           * @param staticDataMap
           * @param dynamicDataMappingList
           * @return void
           * @description: 按模板处理sheet页里的数据
           * @author susu
           * @date 2024/2/19
           */
          private static void dealSheetDataByTemplate(XSSFSheet sheet, Map<String, Object> staticDataMap, List<DynamicDataMapping> dynamicDataMappingList) {
              // 循环sheet里每一行
              for (int i = sheet.getFirstRowNum(); i <= sheet.getLastRowNum(); i++) {
                  XSSFRow row = sheet.getRow(i);
                  DynamicDataMapping dynamicDataMapping = getDynamicRowDataByMatch(row, dynamicDataMappingList);
                  if (dynamicDataMapping != null) {
                      i = getTemplateLastRowIndexAfterDealTemplate(sheet, i, dynamicDataMapping);
                  } else {
                      dealTemplateDataRow(row, null, staticDataMap);
                  }
              }
          }
      
          /**
           * @param row
           * @param dataMap
           * @param dataPrefix
           * @return void
           * @description: 循环处理模版中每行的数据
           * @author susu
           * @date 2024/2/20
           */
          private static void dealTemplateDataRow(XSSFRow row, String dataPrefix, Map<String, Object> dataMap) {
              if (dataMap == null) {
                  return;
              }
              for (int i = row.getFirstCellNum(); i < row.getLastCellNum(); i++) {
                  XSSFCell cell = row.getCell(i);
                  fillInTemplateCellDataValue(cell, dataPrefix, dataMap);
              }
          }
      
          /**
           * @param cell
           * @param dataPrefix
           * @param dataMap
           * @return void
           * @description: 填充模版里单元格的值
           * @author susu
           * @date 2024/2/20
           */
          private static void fillInTemplateCellDataValue(XSSFCell cell, String dataPrefix, Map<String, Object> dataMap) {
              if (cell == null) {
                  return;
              }
              String cellValue = cell.getStringCellValue();//获取模版里设置的数据
              if (StringUtils.isEmpty(cellValue)) {
                  return;
              }
              boolean flag = false;
              dataPrefix = StringUtils.isEmpty(dataPrefix) ? "" : (dataPrefix + ".");
              for (Map.Entry<String, Object> entry : dataMap.entrySet()) {
                  // 循环所有,因为可能一行有多个占位符
                  String cellTemplateStr = "{{" + dataPrefix + entry.getKey() + "}}";
                  if (cellValue.contains(cellTemplateStr)) {
                      // 替换模版中单元格的数据
                      cellValue = cellValue.replace(cellTemplateStr, entry.getValue() == null ? "" : entry.getValue().toString());
                      flag = true;
                  }
              }
              if (flag) {
                  cell.setCellValue(cellValue);
              }
          }
      
          /**
           * @param row
           * @param dynamicDataMappingList
           * @return com.liu.susu.excel.template.poi.common.DynamicDataMapping
           * @description: 通过模版sheet中的行数据 与 动态数据匹配,获取此行需要填充的动态数据
           * @author susu
           * @date 2024/2/21
           */
          private static DynamicDataMapping getDynamicRowDataByMatch(XSSFRow row, List<DynamicDataMapping> dynamicDataMappingList) {
              if (dynamicDataMappingList == null || dynamicDataMappingList.size() < 1) {
                  return null;
              }
              for (int j = row.getFirstCellNum(); j < row.getLastCellNum(); j++) {
                  XSSFCell cell = row.getCell(j);
                  String value = cell.getStringCellValue();
                  if (value != null) {
                      for (DynamicDataMapping dynamicData : dynamicDataMappingList) {
                          if (value.startsWith("{{" + dynamicData.getDataId() + ".")) {
                              return dynamicData;
                          }
                      }
                  }
              }
              return null;
          }
      
          /**
           * @param sheet
           * @param rowIndex
           * @param dynamicDataMapping
           * @return int
           * @description: 根据动态数据的条数动态复制模版行,每处理一个类型的list返回最后的行数,进而处理下一个类型的list
           * @author susu
           * @date 2024/2/20
           */
          private static int getTemplateLastRowIndexAfterDealTemplate(XSSFSheet sheet, int rowIndex, DynamicDataMapping dynamicDataMapping) {
              if (dynamicDataMapping == null) {
                  return rowIndex;
              }
              int dataRows = dynamicDataMapping.getDataList().size();
              // 需要拷贝的行数(因为模板行本身占1行,所以-1)
              int copyRows = dataRows - 1;
              if (copyRows > 0) {
                  /**
                   * shiftRows: 从动态数据模版行(rowIndex)到最后一行,这些全部行都向下移copyRows行
                   *            相当于模版行上面插入n行空行(n=copyRows)
                   */
                  sheet.shiftRows(rowIndex, sheet.getLastRowNum(), copyRows, true, false);
                  // 拷贝策略
                  CellCopyPolicy cellCopyPolicy = makeCellCopyPolicy();
                  // 因为从模版行开始向下平移了copyRows行,所以这里 模板行=rowIndex + copyRows,
                  int templateDataRow = rowIndex + copyRows;
                  // 因为模版行上新增了空行,所以要把模板所在行的模版 拷贝到上面新增的空行
                  for (int i = 0; i < copyRows; i++) {
                      //templateDataRow-模版行数据   rowIndex + i循环的当前空行
                      sheet.copyRows(templateDataRow, templateDataRow, rowIndex + i, cellCopyPolicy);
                  }
              }
              // 循环模版行:动态替换模版行(将模版行里的模版替换成动态数据)
              for (int j = rowIndex; j < rowIndex + dataRows; j++) {
                  Map<String, Object> dataMap = dynamicDataMapping.getDataList().get(j - rowIndex);
                  dealTemplateDataRow(sheet.getRow(j), dynamicDataMapping.getDataId(), dataMap);
              }
              return rowIndex + copyRows;
          }
      
          /**
           * @param
           * @return org.apache.poi.ss.usermodel.CellCopyPolicy
           * @description: 拷贝策略
           * @author susu
           * @date 2024/2/20
           */
          public static CellCopyPolicy makeCellCopyPolicy() {
              CellCopyPolicy cellCopyPolicy = new CellCopyPolicy();
              cellCopyPolicy.setCopyCellValue(true);
              cellCopyPolicy.setCopyCellStyle(true);
              return cellCopyPolicy;
          }
      
      
      }
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
      • 71
      • 72
      • 73
      • 74
      • 75
      • 76
      • 77
      • 78
      • 79
      • 80
      • 81
      • 82
      • 83
      • 84
      • 85
      • 86
      • 87
      • 88
      • 89
      • 90
      • 91
      • 92
      • 93
      • 94
      • 95
      • 96
      • 97
      • 98
      • 99
      • 100
      • 101
      • 102
      • 103
      • 104
      • 105
      • 106
      • 107
      • 108
      • 109
      • 110
      • 111
      • 112
      • 113
      • 114
      • 115
      • 116
      • 117
      • 118
      • 119
      • 120
      • 121
      • 122
      • 123
      • 124
      • 125
      • 126
      • 127
      • 128
      • 129
      • 130
      • 131
      • 132
      • 133
      • 134
      • 135
      • 136
      • 137
      • 138
      • 139
      • 140
      • 141
      • 142
      • 143
      • 144
      • 145
      • 146
      • 147
      • 148
      • 149
      • 150
      • 151
      • 152
      • 153
      • 154
      • 155
      • 156
      • 157
      • 158
      • 159
      • 160
      • 161
      • 162
      • 163
      • 164
      • 165
      • 166
      • 167
      • 168
      • 169
      • 170
      • 171
      • 172
      • 173
      • 174
      • 175
      • 176
      • 177
      • 178
      • 179
      • 180
      • 181
      • 182
      • 183
      • 184
      • 185
      • 186
      • 187
      • 188
      • 189
      • 190
      • 191
      • 192
      • 193
      • 194
      • 195
      • 196
      • 197
      • 198
      • 199
      • 200
      • 201
      • 202
      • 203
      • 204
      • 205
      • 206
      • 207
      • 208
      • 209
      • 210
      • 211
      • 212
      • 213
      • 214
      • 215
      • 216
      • 217
      • 218
      • 219
      • 220
      • 221
      • 222
      • 223
      • 224
      • 225
      • 226
      • 227
      • 228
      • 229
      • 230
      • 231
      • 232
      • 233
      • 234
      • 235
      • 236
      • 237
      • 238
      • 239
      • 240
      • 241
      • 242
      • 243
      • 244
      • 245
      • 246
      • 247
      • 248
      • 249
      • 250
      • 251
      • 252

    3.4.3 导出工具类入口代码

    • ExportExcelByTemplateUtils.java 如下:
      package com.liu.susu.excel.template.poi.common;
      
      import java.util.HashMap;
      import java.util.List;
      import java.util.Map;
      
      /**
       * @Description 根据模版导出Excel工具类
       * @Author susu
       * @Date 2024/2/19
       */
      public class ExportExcelByTemplateUtils {
      
          /**
          * @description: 根据模版导出Excel入口(单个list数据)
          * @param templateFileName
          * @param exportFilePathAndName
          * @param staticDataMap
          * @param dataId
          * @param originDataList
          * @return void
          * @author susu
          * @date 2024/2/21
          */
          public static void doExportExcelOneListByTemplate(String templateFileName, String exportFilePathAndName,
                                                            Map<String, Object> staticDataMap,
                                                            String dataId,
                                                            List<?> originDataList) throws Exception{
      
              List<Map<String, Object>> exportDataList = MapObjectUtil.objListToMapList(originDataList);
              // 只有一个list数据
              List<DynamicDataMapping> dynamicDataMappingList = DynamicDataMapping.createOneDataList(dataId, exportDataList);
              // 导出
              ExcelTemplateProc.doExportExcelByTemplateProc(templateFileName,exportFilePathAndName,staticDataMap,dynamicDataMappingList);
      
          }
      
          /**
          * @description: 根据模版导出Excel入口(多个list数据)
          * @param templateFileName
          * @param exportFilePathAndName
          * @param staticSource
          * @param originDataMapList
          * @return void
          * @author susu
          * @date 2024/2/20
          */
          public static void doExportExcelMoreListByTemplate(String templateFileName,
                                                     String exportFilePathAndName,
                                                     Map<String, Object> staticSource,
                                                     Map<String, List<?>> originDataMapList) throws Exception{
      
              Map<String,List<Map<String, Object>>> transMap = new HashMap<>();
              originDataMapList.forEach((dataId,originDataList)->{
                  List<Map<String, Object>> transDataList = MapObjectUtil.objListToMapList(originDataList);
                  transMap.put(dataId,transDataList);
              });
              // 多个list类型数据
              List<DynamicDataMapping> dynamicDataMappingList = DynamicDataMapping.createMorDataList(transMap);
              // 导出
              ExcelTemplateProc.doExportExcelByTemplateProc(templateFileName,exportFilePathAndName,staticSource,dynamicDataMappingList);
      
          }
      
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65

    4. 附项目

    4.1 一般导出项目代码

    4.2 根据模版导出项目代码

  • 相关阅读:
    微服务架构九大特性
    深⼊理解指针(5)【深入理解指针,体会大厂的笔试题】
    这些功能要是没有,我大 Pro 还怎么出来混!
    牛客前端刷题(五)—— CSS相关概念
    【Java 进阶篇】创建 HTML 注册页面
    【Aseprite】2D像素人物制作
    ROS2/DDS/QoS/主题的记录
    数字滤波器分析---零极点分析
    LVGL 之 windows 上 lvgl 模拟器基于 Visual Studio 搭建方法的简单整理
    【JQ _DOM】DOM
  • 原文地址:https://blog.csdn.net/suixinfeixiangfei/article/details/136295131