java-easyExcel导出-合并单元格

该代码段展示了如何使用EasyExcel库在Java中实现Excel模板数据的导出,并结合自定义的`ExcelFillCellMergeStrategy`类处理单元格合并。此策略在数据写入后检查特定列是否需要与上一行进行合并,从而实现特定列的行间数据相同则合并单元格的效果。此外,还处理了最后一行的特定列合并。

实现层:

public ResultDto statisticalBudgetDetailExport(HttpServletResponse response, ReimbursementFormDTO formDTO) {
        List<Map<String, Object>> mapValueList = (List<Map<String, Object>>) formDTO.getParamsMap();

        //获取所需数据
        List<Map<String, Object>> list = new ArrayList<>();
        for (Map<String, Object> mapValue : mapValueList) {
            Map<String, Object> map = new HashMap<>();

            map.put("thirdDept", "");
            
            list.add(map);
        }

        //写入数据
        String fileName = "导出";

        try {
            fileName = URLEncoder.encode(fileName, "UTF-8");
            response.setContentType("application/vnd.ms-excel;charset=utf-8");

            response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");

            ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream())
                    .withTemplate(this.getClass().getClassLoader().getResourceAsStream("templates/statisticalBudgetDetailExport.xlsx"))
                    .registerWriteHandler(new ExcelFillCellMergeStrategy(1,new int[]{0,1}, list.size()))
                    .build();
            FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
            WriteSheet writeSheet = EasyExcel.writerSheet().build();

            // 直接写入数据
            excelWriter.fill(list, fillConfig, writeSheet);

            excelWriter.finish();
        } catch (Exception e) {
            return null;
        }
        return null;
    }

合并策略:

import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import lombok.Data;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;

import java.util.List;

/**
 * 合并单元格
 */
@Data
public class ExcelFillCellMergeStrategy implements CellWriteHandler {
    /**
     * 合并字段的下标
     */
    private int[] mergeColumnIndex;
    /**
     * 合并几行
     */
    private int mergeRowIndex;

    private int lastRow;

    int num = 0;

    public ExcelFillCellMergeStrategy() {
    }

    public ExcelFillCellMergeStrategy(int mergeRowIndex, int[] mergeColumnIndex, int lastRow) {
        this.mergeRowIndex = mergeRowIndex;
        this.mergeColumnIndex = mergeColumnIndex;
        this.lastRow = lastRow;
    }

    @Override
    public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row,
                                 Head head, Integer integer, Integer integer1, Boolean aBoolean) {

    }

    @Override
    public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell,
                                Head head, Integer integer, Boolean aBoolean) {

    }


    public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,
                                       CellData cellData, Cell cell, Head head, Integer integer, Boolean aBoolean) {

    }

    @Override
    public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,
                                 List<CellData> list, Cell cell, Head head, Integer integer, Boolean aBoolean) {
        //当前行
        int curRowIndex = cell.getRowIndex();
        //当前列
        int curColIndex = cell.getColumnIndex();

        if (curRowIndex > mergeRowIndex) {
            for (int i = 0; i < mergeColumnIndex.length; i++) {
                if (curColIndex == mergeColumnIndex[i]) {
                    mergeWithPrevRow(writeSheetHolder, cell, curRowIndex, curColIndex);
                    break;
                }
            }
        }

        //合并最后一行指定列
        if (curRowIndex == lastRow) {
            if (num == 0) {
                // 合并最后一行 1,2 列
                mergeWithPrevCol(writeSheetHolder, cell, curRowIndex, 1);
            }
            num ++;
        }
    }

    private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) {
        //获取当前行的当前列的数据和上一行的当前列列数据,通过上一行数据是否相同进行合并
        Object curData = cell.getCellTypeEnum() == CellType.STRING ? cell.getStringCellValue() :
                cell.getNumericCellValue();
        Cell preCell = cell.getSheet().getRow(curRowIndex - 1).getCell(curColIndex);
        Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() :
                preCell.getNumericCellValue();

        // 比较当前行的第一列的单元格与上一行是否相同,相同合并当前单元格与上一行
        if (curData.equals(preData)) {
            Sheet sheet = writeSheetHolder.getSheet();
            List<CellRangeAddress> mergeRegions = sheet.getMergedRegions();
            boolean isMerged = false;
            for (int i = 0; i < mergeRegions.size() && !isMerged; i++) {
                CellRangeAddress cellRangeAddr = mergeRegions.get(i);
                // 若上一个单元格已经被合并,则先移出原有的合并单元,再重新添加合并单元
                if (cellRangeAddr.isInRange(curRowIndex - 1, curColIndex)) {
                    sheet.removeMergedRegion(i);
                    cellRangeAddr.setLastRow(curRowIndex);
                    sheet.addMergedRegion(cellRangeAddr);
                    isMerged = true;
                }
            }
            // 若上一个单元格未被合并,则新增合并单元
            if (!isMerged) {
                CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex - 1, curRowIndex, curColIndex,
                        curColIndex);
                sheet.addMergedRegion(cellRangeAddress);
            }
        }
    }
    private void mergeWithPrevCol(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) {
        Sheet sheet = writeSheetHolder.getSheet();
        CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex, curRowIndex, curColIndex, curColIndex + 1);
        sheet.addMergedRegion(cellRangeAddress);
    }
}

### Java 使用 EasyExcel导出时实现单元合并及数值相加 #### 实现单元合并 为了在使用 EasyExcel 导出 Excel时实现单元的合并,可以利用 `WriteHandler` 接口来定义自定义处理器。通过继承 `AbstractCellWriteHandler` 类并重写其方法,可以在特定条件下执行单元合并逻辑。 ```java import com.alibaba.excel.write.handler.AbstractCellWriteHandler; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Sheet; public class MergeCellsHandler extends AbstractCellWriteHandler { @Override protected void afterCellDispose(Sheet sheet, List<CellData> cellDataList, Cell cell, Head head) { // 自定义条件判断是否需要在此处进行单元合并操作 int firstRow = 0; // 起始行号 int lastRow = 5; // 结束行号 int columnIndex = 0; // 列索引 if (/* 条件 */) { sheet.addMergedRegion(new CellRangeAddress(firstRow, lastRow, columnIndex, columnIndex)); } } } ``` 此代码片段展示了如何创建一个名为 `MergeCellsHandler` 的类用于处理单元合并[^1]。 #### 进行数值相加 对于数值相加的操作,在 EasyExcel 中可以通过编写业务逻辑来自动生成合计值,并将其作为新行插入到工作表中。这里提供了一个简单的例子: ```java import java.util.ArrayList; import java.util.List; // 假设有一个实体类 DataModel 存储要写出的数据项 class DataModel { private String name; private double value; public DataModel(String name, double value) { this.name = name; this.value = value; } // getter 和 setter 方法... } public static void main(String[] args) throws Exception { // 准备数据列表 List<DataModel> dataList = new ArrayList<>(); // 添加一些测试数据 dataList.add(new DataModel("Item A", 100.0)); dataList.add(new DataModel("Item B", 200.0)); // 计算总和 Double sumValue = dataList.stream().mapToDouble(DataModel::getValue).sum(); // 将总计信息加入集合最后位置 dataList.add(new DataModel("Total:", sumValue)); // 创建 ExcelWriter 对象并将上述数据写出至指定路径下的文件 try (EasyExcel.WriterBuilder writerBuilder = EasyExcel.write("/path/to/output.xlsx")) { WriteSheet writeSheet = EasyExcel.writerSheet("Sheet1").build(); // 注册自定义处理器以支持单元合并功能 writerBuilder.registerWriteHandler(new MergeCellsHandler()); // 开始写入过程 writerBuilder.sheet(writeSheet); writerBuilder.doWrite(dataList); } } ``` 这段程序先准备了一组带有名称和金额的对象列表,接着计算这些对象所代表金额之和,并最终把它们连同汇总结果一起保存到了一个新的 Excel 文件里。
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值