EasyExcel自定义合并单元格导出

问题

根据业务需求会有导出中需要合并的功能,但是当根据数据合并时又不能使用注解来进行合并,只能自定义合并,根据官网中介绍可以使用第二种方式,官网地址https://www.yuque.com/easyexcel/doc/write#cac25459

导出的格式:

 

解决思路

实际上是使用此类中重写 afterCellDispose() 方法;

RowMergeStrategy类:

import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.AbstractCellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;

import java.util.List;
import java.util.Map;

public class RowMergeStrategy extends AbstractCellWriteHandler {

    private Map<String, List<MergeRowBean>> strategyMap;
    private Sheet sheet;

    public RowMergeStrategy(Map<String, List<MergeRowBean>> strategyMap) {
        this.strategyMap = strategyMap;
    }

    @Override
    public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
        if (isHead.booleanValue()) {
            return;
        }
        merge(writeSheetHolder.getSheet(), cell, head, relativeRowIndex);
    }

    protected void merge(Sheet sheet, Cell cell, Head head, Integer integer) {
        this.sheet = sheet;
        if (cell.getRowIndex() == 2 && cell.getColumnIndex() == 0) {
            /**
             * 保证每个cell被合并一次,如果不加上面的判断,因为是一个cell一个cell操作的,
             * 例如合并A2:A3,当cell为A2时,合并A2,A3,但是当cell为A3时,又是合并A2,A3,
             * 但此时A2,A3已经是合并的单元格了
             */
            for (Map.Entry<String, List<MergeRowBean>> entry : strategyMap.entrySet()) {
                Integer columnIndex = Integer.valueOf(entry.getKey());
                entry.getValue().forEach(rowRange -> {
                    //添加一个合并请求
                    sheet.addMergedRegionUnsafe(new CellRangeAddress(rowRange.getFirstRow(),
                            rowRange.getLastRow(), columnIndex, columnIndex));
                });
            }
        }
    }
}
MergeRowBean类:
public class MergeRowBean {
    /**
     * 起始行
     */
    private int firstRow;
    /**
     * 结束行
     */
    private int lastRow;



    public MergeRowBean(int firstRow, int lastRow) {
        this.firstRow = firstRow;
        this.lastRow = lastRow;
    }

    public int getFirstRow() {
        return firstRow;
    }

    public void setFirstRow(int firstRow) {
        this.firstRow = firstRow;
    }

    public int getLastRow() {
        return lastRow;
    }

    public void setLastRow(int lastRow) {
        this.lastRow = lastRow;
    }
}

 ExcelUtil类:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ExcelUtil {

    /**
     * 添加
     * @param excelDtoList 要导出的集合
     * @return
     */
    public static Map<String, List<MergeRowBean>> addMerStrategy(List<ThirdTypeTableExcelResponseBean> excelDtoList) {
        Map<String, List<MergeRowBean>> strategyMap = new HashMap<>();

        ThirdTypeTableExcelResponseBean preExcelDto = null;
        //行坐标
        int startRow = 0;
        for (int i = 0; i < excelDtoList.size(); i++) {
            ThirdTypeTableExcelResponseBean currDto = excelDtoList.get(i);
            if (preExcelDto != null) {
                if (currDto.getFirstTypeId() != null) {
                    //当firstTypeId相同时
                    if (currDto.getFirstTypeId().equals(preExcelDto.getFirstTypeId())) {
                        fillStrategyMap(strategyMap, "0", i + startRow);
                    }
                    //当secondTypeId相同时
                    if (currDto.getSecondTypeId().equals(preExcelDto.getSecondTypeId())) {
                        fillStrategyMap(strategyMap, "1", i + startRow);
                    }
                }
            }
            preExcelDto = currDto;
        }

        return strategyMap;
    }

    /**
     * 合并
     *
     * @param strategyMap Map
     * @param key         列
     * @param index       行坐标
     */
    private static void fillStrategyMap(Map<String, List<MergeRowBean>> strategyMap, String key, int index) {
        List<MergeRowBean> rowRangeDtoList = strategyMap.get(key) == null ? new ArrayList<>() : strategyMap.get(key);
        boolean flag = false;
        for (MergeRowBean dto : rowRangeDtoList) {
            //分段list中是否有end索引是上一行索引的,如果有,则索引+1
            if (dto.getLastRow() == index) {
                dto.setLastRow(index + 1);
                flag = true;
            }
        }
        //如果没有,则新增分段
        if (!flag) {
            rowRangeDtoList.add(new MergeRowBean(index, index + 1));
        }
        strategyMap.put(key, rowRangeDtoList);
    }

}

代码中可以看到思路为比较上一个类和当前类中同属性是否相同,如果相同则合并

导出代码:

//要导出的集合
List<ThirdTypeTableExcelResponseBean> thirdTypeTableExcelResponseBeans = BeanUtil.listObjToListObj(thirdTypeListByDate, ThirdTypeTableExcelResponseBean.class);
//设置表名
        StringBuilder title = new StringBuilder();
        title.append("xxx")
                .append(statisticsQueryRequestBean.getStartTime())
                .append("至")
                .append(statisticsQueryRequestBean.getEndTime())
                .append(".xlsx");
        try {
            String encodeFileName = URLEncoder.encode(title.toString(), "utf-8");
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            response.setCharacterEncoding(StandardCharsets.UTF_8.name());
            response.setHeader("Content-disposition", "attachment;filename=" + encodeFileName + "");
            response.setContentType("application/octet-stream;charset=utf-8");
            response.setHeader("Access-Control-Expose-Headers", title.toString());
            response.setHeader("fileName", encodeFileName);
            //设置合并规则
            Map<String, List<MergeRowBean>> stringListMap = ExcelUtil.addMerStrategy(thirdTypeTableExcelResponseBeans);
            ExcelWriter excelWriter = EasyExcelFactory.write(response.getOutputStream(), xxx.class).registerWriteHandler(new RowMergeStrategy(stringListMap)).build();
            /* 这里注意 如果同一个sheet只要创建一次 */
            WriteSheet writeSheet = EasyExcelFactory.writerSheet("xxx").build();
            excelWriter.write(thirdTypeTableExcelResponseBeans, writeSheet);
            excelWriter.finish();
        } catch (Exception e) {
            log.error("导出失败 {}", e.getMessage());
            response.reset();
            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
            response.setCharacterEncoding(StandardCharsets.UTF_8.name());
            Map<String, String> map = new HashMap<>(8);
            map.put("status", "failure");
            map.put("message", "导出失败" + e.getMessage());
            response.getWriter().println(JSON.toJSONString(map));
        }

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
EasyExcel中,自定义合并单元格策略可以通过实现`com.alibaba.excel.metadata.CellStrategy`接口来实现。可以参考上面提到的技术斩博主的自定义策略进行优化。 具体步骤如下: 1. 创建一个类,实现`CellStrategy`接口,并重写`merge(CellRangeAddress cellRangeAddress, Sheet sheet)`方法。 2. 在`merge()`方法中,根据自定义合并单元格规则,通过`cellRangeAddress`参数来确定需要合并的单元格范围,然后通过`sheet`对象进行单元格合并操作。 3. 根据需要,在自定义策略中添加其他的处理逻辑,例如设置合并后单元格的样式等。 4. 在使用EasyExcel进行导出时,通过`excelWriter.setCustomCellWriteHandler()`方法来设置自定义合并单元格策略。 请注意,以上步骤仅是一种实现自定义合并单元格策略的方法,具体的实现方式可能会因项目需求而有所不同。<span class="em">1</span><span class="em">2</span> #### 引用[.reference_title] - *1* [利用easyExcel导出上万条数据,自定义策略合并单元格](https://download.csdn.net/download/qq_32734167/13408705)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [EasyExcel合并单元格,通过注解方式实现自定义合并策略](https://blog.csdn.net/q1468051413/article/details/127832071)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值