Easyexcel(6-单位格合并)

打印 上一主题 下一主题

主题 994|帖子 994|积分 2982

注解

@ContentLoopMerge

用于设置合并单位格的注解,作用于字段上

  • eachRow:每隔几行合并
  • columnExtend:合并列的下标
  1. @AllArgsConstructor
  2. @NoArgsConstructor
  3. @Data
  4. public class User {
  5.     @ContentLoopMerge(eachRow = 2, columnExtend = 1)
  6.     @ExcelProperty(value = "用户Id")
  7.     private Integer userId;
  8.     @ExcelProperty(value = "姓名")
  9.     private String name;
  10.     @ExcelProperty(value = "手机")
  11.     private String phone;
  12.     @ExcelProperty(value = "邮箱")
  13.     private String email;
  14.     @ExcelProperty(value = "创建时间")
  15.     private Date createTime;
  16. }
复制代码
@OnceAbsoluteMerge

用于指定位置的单位格合并,作用于类上

  • firstRowIndex:第一行下标
  • lastRowIndex:最后一行下标
  • firstColumnIndex:第一列下标
  • lastColumnIndex:最后一列下标
  1. @OnceAbsoluteMerge(firstColumnIndex = 0, lastColumnIndex = 0, firstRowIndex = 1, lastRowIndex = 2)
  2. @AllArgsConstructor
  3. @NoArgsConstructor
  4. @Data
  5. public class User {
  6.     @ExcelProperty(value = "用户Id")
  7.     private Integer userId;
  8.     @ExcelProperty(value = "姓名")
  9.     private String name;
  10.     @ExcelProperty(value = "手机")
  11.     private String phone;
  12.     @ExcelProperty(value = "邮箱")
  13.     private String email;
  14.     @ExcelProperty(value = "创建时间")
  15.     private Date createTime;
  16. }
复制代码
类方法

LoopMergeStrategy

源码查看
  1. public class LoopMergeStrategy implements RowWriteHandler {
  2.     // 每隔几行合并
  3.     private final int eachRow;
  4.     // 合并几列
  5.     private final int columnExtend;
  6.     // 合并列
  7.     private final int columnIndex;
  8.     public LoopMergeStrategy(int eachRow, int columnIndex) {
  9.         this(eachRow, 1, columnIndex);
  10.     }
  11.     public LoopMergeStrategy(int eachRow, int columnExtend, int columnIndex) {
  12.         if (eachRow < 1) {
  13.             throw new IllegalArgumentException("EachRows must be greater than 1");
  14.         }
  15.         if (columnExtend < 1) {
  16.             throw new IllegalArgumentException("ColumnExtend must be greater than 1");
  17.         }
  18.         if (columnExtend == 1 && eachRow == 1) {
  19.             throw new IllegalArgumentException("ColumnExtend or eachRows must be greater than 1");
  20.         }
  21.         if (columnIndex < 0) {
  22.             throw new IllegalArgumentException("ColumnIndex must be greater than 0");
  23.         }
  24.         this.eachRow = eachRow;
  25.         this.columnExtend = columnExtend;
  26.         this.columnIndex = columnIndex;
  27.     }
  28.     public LoopMergeStrategy(LoopMergeProperty loopMergeProperty, Integer columnIndex) {
  29.         this(loopMergeProperty.getEachRow(), loopMergeProperty.getColumnExtend(), columnIndex);
  30.     }
  31.     @Override
  32.     public void afterRowDispose(RowWriteHandlerContext context) {
  33.         // 判断是否为表头
  34.         if (context.getHead() || context.getRelativeRowIndex() == null) {
  35.             return;
  36.         }
  37.         // 循环进行单元格合并
  38.         if (context.getRelativeRowIndex() % eachRow == 0) {
  39.             CellRangeAddress cellRangeAddress = new CellRangeAddress(context.getRowIndex(),
  40.                 context.getRowIndex() + eachRow - 1,
  41.                 columnIndex, columnIndex + columnExtend - 1);
  42.             context.getWriteSheetHolder().getSheet().addMergedRegionUnsafe(cellRangeAddress);
  43.         }
  44.     }
  45. }
复制代码
根本使用

通过 registerWriteHandler 方法设置单位格合并策略,用于指定某几列每相差几行进行单位格合并

  • 指定单列合并
  1. @GetMapping("/download1")
  2. public void download1(HttpServletResponse response) {
  3.     try {
  4.         response.setContentType("application/vnd.ms-excel");
  5.         response.setCharacterEncoding("utf-8");
  6.         // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
  7.         String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");
  8.         response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xls");
  9.         User user1 = new User();
  10.         user1.setUserId(123);
  11.         user1.setName("as");
  12.         user1.setPhone("15213");
  13.         user1.setEmail("5456");
  14.         user1.setCreateTime(new Date());
  15.         User user2 = new User();
  16.         user2.setUserId(123);
  17.         user2.setName("asbnm");
  18.         user2.setPhone("15213");
  19.         user2.setEmail("5456");
  20.         user2.setCreateTime(new Date());
  21.         User user3 = new User();
  22.         user3.setUserId(123);
  23.         user3.setName("as");
  24.         user3.setPhone("46543213");
  25.         user3.setEmail("5456");
  26.         user3.setCreateTime(new Date());
  27.         
  28.         // 第1列每隔2行合并一次
  29.         LoopMergeStrategy loopMergeStrategy = new LoopMergeStrategy(2, 0);
  30.         EasyExcel.write(response.getOutputStream(), User.class)
  31.                 .registerWriteHandler(loopMergeStrategy)
  32.                 .sheet("模板")
  33.                 .doWrite(Arrays.asList(user1, user2, user3));
  34.     } catch (Exception e) {
  35.         e.printStackTrace();
  36.     }
  37. }
复制代码


  • 指定多列合并
  1. @GetMapping("/download1")
  2. public void download1(HttpServletResponse response) {
  3.     try {
  4.         response.setContentType("application/vnd.ms-excel");
  5.         response.setCharacterEncoding("utf-8");
  6.         // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
  7.         String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");
  8.         response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xls");
  9.         User user1 = new User();
  10.         user1.setUserId(123);
  11.         user1.setName("as");
  12.         user1.setPhone("15213");
  13.         user1.setEmail("5456");
  14.         user1.setCreateTime(new Date());
  15.         User user2 = new User();
  16.         user2.setUserId(123);
  17.         user2.setName("asbnm");
  18.         user2.setPhone("15213");
  19.         user2.setEmail("5456");
  20.         user2.setCreateTime(new Date());
  21.         User user3 = new User();
  22.         user3.setUserId(123);
  23.         user3.setName("as");
  24.         user3.setPhone("46543213");
  25.         user3.setEmail("5456");
  26.         user3.setCreateTime(new Date());
  27.         // 第2列开始每隔2行合并一次,从第2列开始的两列进行合并
  28.         LoopMergeStrategy loopMergeStrategy = new LoopMergeStrategy(2, 2, 2);
  29.         EasyExcel.write(response.getOutputStream(), User.class)
  30.                 .registerWriteHandler(loopMergeStrategy)
  31.                 .sheet("模板")
  32.                 .doWrite(Arrays.asList(user1, user2, user3));
  33.     } catch (Exception e) {
  34.         e.printStackTrace();
  35.     }
  36. }
复制代码

OnceAbsoluteMergeStrategy

源码查看
  1. public class OnceAbsoluteMergeStrategy implements SheetWriteHandler {
  2.     // 第一行
  3.     private final int firstRowIndex;
  4.     // 最后一行
  5.     private final int lastRowIndex;
  6.     // 第一列
  7.     private final int firstColumnIndex;
  8.     // 最后一列
  9.     private final int lastColumnIndex;
  10.     public OnceAbsoluteMergeStrategy(int firstRowIndex, int lastRowIndex, int firstColumnIndex, int lastColumnIndex) {
  11.         if (firstRowIndex < 0 || lastRowIndex < 0 || firstColumnIndex < 0 || lastColumnIndex < 0) {
  12.             throw new IllegalArgumentException("All parameters must be greater than 0");
  13.         }
  14.         this.firstRowIndex = firstRowIndex;
  15.         this.lastRowIndex = lastRowIndex;
  16.         this.firstColumnIndex = firstColumnIndex;
  17.         this.lastColumnIndex = lastColumnIndex;
  18.     }
  19.     public OnceAbsoluteMergeStrategy(OnceAbsoluteMergeProperty onceAbsoluteMergeProperty) {
  20.         this(onceAbsoluteMergeProperty.getFirstRowIndex(), onceAbsoluteMergeProperty.getLastRowIndex(),
  21.             onceAbsoluteMergeProperty.getFirstColumnIndex(), onceAbsoluteMergeProperty.getLastColumnIndex());
  22.     }
  23.     @Override
  24.     public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
  25.         CellRangeAddress cellRangeAddress =
  26.             new CellRangeAddress(firstRowIndex, lastRowIndex, firstColumnIndex, lastColumnIndex);
  27.         writeSheetHolder.getSheet().addMergedRegionUnsafe(cellRangeAddress);
  28.     }
  29. }
复制代码
根本使用

通过 registerWriteHandler 方法设置单位格合并策略,用于指定一个区域内的单位格进行合并
  1. @GetMapping("/download2")
  2. public void download2(HttpServletResponse response) {
  3.     try {
  4.         response.setContentType("application/vnd.ms-excel");
  5.         response.setCharacterEncoding("utf-8");
  6.         // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
  7.         String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");
  8.         response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xls");
  9.         User user1 = new User();
  10.         user1.setUserId(123);
  11.         user1.setName("as");
  12.         user1.setPhone("15213");
  13.         user1.setEmail("5456");
  14.         user1.setCreateTime(new Date());
  15.         User user2 = new User();
  16.         user2.setUserId(123);
  17.         user2.setName("asbnm");
  18.         user2.setPhone("15213");
  19.         user2.setEmail("5456");
  20.         user2.setCreateTime(new Date());
  21.         User user3 = new User();
  22.         user3.setUserId(123);
  23.         user3.setName("as");
  24.         user3.setPhone("46543213");
  25.         user3.setEmail("5456");
  26.         user3.setCreateTime(new Date());
  27.         // 从第1行第3列合并到第3行第3列
  28.         OnceAbsoluteMergeStrategy onceAbsoluteMergeStrategy = new OnceAbsoluteMergeStrategy(0, 2, 2, 2);
  29.         EasyExcel.write(response.getOutputStream(), User.class)
  30.                 .registerWriteHandler(onceAbsoluteMergeStrategy)
  31.                 .sheet("模板")
  32.                 .doWrite(Arrays.asList(user1, user2, user3));
  33.     } catch (Exception e) {
  34.         e.printStackTrace();
  35.     }
  36. }
复制代码

合并单位格工具类

AbstractMergeStrategy

根本思路


  • 继续 AbstractMergeStrategy 抽象合并策略,重写 merge 方法
  • 传入要合并的数据列表,循环判定上下行是否是相同的数据,如果是则为同一个组,否则为另一个组,使用 List 生存每个组的数目
  • 单位格渲染时,循环遍历每个组的值后,计算要合并的单位格的上下标
使用
  1. /**
  2. * 自定义合并策略 该类继承了AbstractMergeStrategy抽象合并策略,需要重写merge()方法
  3. */
  4. public class CustomMergeStrategy extends AbstractMergeStrategy {
  5.     /**
  6.      * 分组,每几行合并一次
  7.      */
  8.     private List<Integer> exportFieldGroupCountList;
  9.     /**
  10.      * 目标合并列index
  11.      */
  12.     private Integer targetColumnIndex;
  13.     /**
  14.      * 需要开始合并单元格的首行index
  15.      */
  16.     private Integer rowIndex;
  17.     public CustomMergeStrategy(List<String> exportDataList, Integer targetColumnIndex, Integer rowIndex) {
  18.         this.exportFieldGroupCountList = getGroupCountList(exportDataList, rowIndex);
  19.         this.targetColumnIndex = targetColumnIndex;
  20.         this.rowIndex = rowIndex;
  21.     }
  22.     // 该方法将目标列根据值是否相同连续可合并,存储可合并的行数
  23.     private List<Integer> getGroupCountList(List<String> exportDataList, Integer rowIndex) {
  24.         if (CollectionUtils.isEmpty(exportDataList)) {
  25.             return new ArrayList<>();
  26.         }
  27.         List<Integer> groupCountList = new ArrayList<>();
  28.         int count = 1;
  29.         for (int i = rowIndex + 1, len = exportDataList.size(); i < len; i++) {
  30.             // 判断上一列和当前列的值是否相同
  31.             if (exportDataList.get(i).equals(exportDataList.get(i - 1))) {
  32.                 count++;
  33.             } else {
  34.                 groupCountList.add(count);
  35.                 count = 1;
  36.             }
  37.         }
  38.         // 处理完最后一条后
  39.         groupCountList.add(count);
  40.         return groupCountList;
  41.     }
  42.     @Override
  43.     protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {
  44.         if (null == rowIndex) {
  45.             rowIndex = cell.getRowIndex();
  46.         }
  47.         // 仅从首行以及目标列的单元格开始合并,忽略其他
  48.         if (cell.getRowIndex() == rowIndex + 1 && cell.getColumnIndex() == targetColumnIndex) {
  49.             mergeGroupColumn(sheet);
  50.         }
  51.     }
  52.     private void mergeGroupColumn(Sheet sheet) {
  53.         int rowCount = rowIndex + 1;
  54.         for (Integer count : exportFieldGroupCountList) {
  55.             if (count == 1) {
  56.                 rowCount += count;
  57.                 continue;
  58.             }
  59.             // 合并单元格
  60.             CellRangeAddress cellRangeAddress = new CellRangeAddress(rowCount, rowCount + count - 1, targetColumnIndex, targetColumnIndex);
  61.             sheet.addMergedRegionUnsafe(cellRangeAddress);
  62.             rowCount += count;
  63.         }
  64.     }
  65. }
复制代码

  • 从首行开始合并单位格
  1. @GetMapping("/download3")
  2. public void download3(HttpServletResponse response) {
  3.     try {
  4.         response.setContentType("application/vnd.ms-excel");
  5.         response.setCharacterEncoding("utf-8");
  6.         // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
  7.         String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");
  8.         response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xls");
  9.         User user1 = new User();
  10.         user1.setUserId(123);
  11.         user1.setName("as");
  12.         user1.setPhone("15213");
  13.         user1.setEmail("5456");
  14.         user1.setCreateTime(new Date());
  15.         User user2 = new User();
  16.         user2.setUserId(123);
  17.         user2.setName("asbnm");
  18.         user2.setPhone("15213");
  19.         user2.setEmail("5456");
  20.         user2.setCreateTime(new Date());
  21.         User user3 = new User();
  22.         user3.setUserId(123);
  23.         user3.setName("as");
  24.         user3.setPhone("46543213");
  25.         user3.setEmail("5456");
  26.         user3.setCreateTime(new Date());
  27.         List<User> userList = Arrays.asList(user1, user2, user3);
  28.         CustomMergeStrategy customMergeStrategy = new CustomMergeStrategy(userList.stream().map(e ->
  29.                 String.valueOf(e.getUserId())).collect(Collectors.toList()), 0, 0);
  30.         EasyExcel.write(response.getOutputStream(), User.class)
  31.                 .registerWriteHandler(customMergeStrategy)
  32.                 .sheet("模板")
  33.                 .doWrite(userList);
  34.     } catch (Exception e) {
  35.         e.printStackTrace();
  36.     }
  37. }
复制代码


  • 从指定行开始合并单位格
  1. @GetMapping("/download3")
  2. public void download3(HttpServletResponse response) {
  3.     try {
  4.         response.setContentType("application/vnd.ms-excel");
  5.         response.setCharacterEncoding("utf-8");
  6.         // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
  7.         String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");
  8.         response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xls");
  9.         User user1 = new User();
  10.         user1.setUserId(123);
  11.         user1.setName("as");
  12.         user1.setPhone("15213");
  13.         user1.setEmail("5456");
  14.         user1.setCreateTime(new Date());
  15.         User user2 = new User();
  16.         user2.setUserId(123);
  17.         user2.setName("asbnm");
  18.         user2.setPhone("15213");
  19.         user2.setEmail("5456");
  20.         user2.setCreateTime(new Date());
  21.         User user3 = new User();
  22.         user3.setUserId(123);
  23.         user3.setName("as");
  24.         user3.setPhone("46543213");
  25.         user3.setEmail("5456");
  26.         user3.setCreateTime(new Date());
  27.         List<User> userList = Arrays.asList(user1, user2, user3);
  28.         CustomMergeStrategy customMergeStrategy = new CustomMergeStrategy(userList.stream().map(e ->
  29.                 String.valueOf(e.getUserId())).collect(Collectors.toList()), 0, 1);
  30.         EasyExcel.write(response.getOutputStream(), User.class)
  31.                 .registerWriteHandler(customMergeStrategy)
  32.                 .sheet("模板")
  33.                 .doWrite(userList);
  34.     } catch (Exception e) {
  35.         e.printStackTrace();
  36.     }
  37. }
复制代码

CellWriteHandler

根本思路


  • 实现 CellWriteHandler 类的 afterCellDispose 方法,在每个单位格完全创建完之后执行合并单位格操作
  • 判定当前列是否为要合并的列,且当前行是否已经到达要操作的行数
  • 如果是,则判定上一行和当前行的数据是否一致,且序号是否一致
  • 如果是,则进行合并单位格操作,如果上一行已经被合并过了,则进行移除,然后再重新合并单位格
使用

[code]/** * excel合并单位格导出工具类 */public class EasyExcelUtil implements CellWriteHandler {    /**     * 需要合并的列     */    private int[] mergeColumnIndex;    /**     * 从哪一行开始合并     */    private int mergeRowIndex;    public EasyExcelUtil() {    }    public EasyExcelUtil(int mergeRowIndex, int[] mergeColumnIndex) {        this.mergeRowIndex = mergeRowIndex;        this.mergeColumnIndex = mergeColumnIndex;    }    /**     * 创建每个单位格之前执行     *     * @param writeSheetHolder     * @param writeTableHolder     * @param row     * @param head     * @param columnIndex     * @param relativeRowIndex     * @param isHead     */    @Override    public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row,                                 Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {        CellWriteHandler.super.beforeCellCreate(writeSheetHolder, writeTableHolder, row, head, columnIndex, relativeRowIndex, isHead);    }    /**     * 每个单位格数据内容渲染之后执行     *     * @param writeSheetHolder     * @param writeTableHolder     * @param cellData     * @param cell     * @param head     * @param relativeRowIndex     * @param isHead     */    @Override    public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, WriteCellData cellData,                                       Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {        CellWriteHandler.super.afterCellDataConverted(writeSheetHolder, writeTableHolder, cellData, cell, head, relativeRowIndex, isHead);    }    /**     * 每个单位格完全创建完之后执行     *     * @param writeSheetHolder     * @param writeTableHolder     * @param cellDataList     * @param cell     * @param head     * @param relativeRowIndex     * @param isHead     */    @Override    public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

饭宝

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表