java的EasyExcel導出表頭不固定、表頭寬度自適應、根據某列進行合並行單元格


1、先看效果圖

 

2、表頭自適應類

根據自己的業務需求來寫,下面只是個例子

public class RwhzCustemhandler extends AbstractColumnWidthStyleStrategy {
    private static final int MAX_COLUMN_WIDTH = 255;
    //the maximum column width in Excel is 255 characters

    public RwhzCustemhandler() {
    }

    @Override
    protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
        if (isHead) {
            int columnWidth = cell.getStringCellValue().getBytes().length;
            if (columnWidth > MAX_COLUMN_WIDTH) {
                columnWidth = MAX_COLUMN_WIDTH;
            } else {
                if (cell.getColumnIndex() == 1) {
                    columnWidth = columnWidth + 10;
                } else {
                    columnWidth = columnWidth + 3;
                }

            }
            writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), columnWidth * 256);
        }
    }
}

 

3、根據某些列來合並相同內容的行單元格類

public class RwhzMergeCell implements CellWriteHandler {

    //需要哪些列的行進行合並
    private int[] mergeColumnIndex;
    //從哪一行開始,表頭如果是只有一行,數據從第二行開始,即索引1開始
    private int mergeRowIndex;

    public RwhzMergeCell() {
    }

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

    @Override
    public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {

    }

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

    }

    @Override
    public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {

    }

    @Override
    public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
        //當前行
        int curRowIndex = cell.getRowIndex();
        //當前列
        int curColIndex = cell.getColumnIndex();
        if (curRowIndex > mergeRowIndex) {
            for (int columnIndex : mergeColumnIndex) {
                if (curColIndex == columnIndex) {
                    //符合條件,調用自定義合並函數
                    mergeWithPrevRow(writeSheetHolder, cell, curRowIndex, curColIndex);
                    break;
                }
            }
        }
    }

    private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) {
        //獲取當前行當前列的單元格的值,可能是String類型,也可能是數值
        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 (preData.equals(curData)) {
            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);
            }
        }
    }

}

 

4、API接口方法

@GetMapping("/exportExcel")
    public void exportExcel(@RequestParam(value = "ztId") int ztId,
                            @RequestParam(value = "rwszId") int rwszId,
                            @RequestParam(value = "bmId", required = false, defaultValue = "") Integer bmId,
                            @RequestParam(value = "qjszId") int qjszId,
                            @RequestParam(value = "sbzt", required = false, defaultValue = "") Boolean sbzt,
                            @RequestParam(value = "wsjbxs") boolean wsjbxs,
                            @RequestParam(value = "wcqk") boolean wcqk,
                            HttpServletResponse response) throws IOException {

        //獲取內容集合
        List<RwhzView> rwhzViews = getRwhzViews(ztId, rwszId, bmId, qjszId, sbzt, wsjbxs, wcqk);
        //獲取表頭集合
        List<RwhzHead> heads = setRwhzHeads(rwszId);
        response.setHeader("Content-Disposition", "attachment; filename=rwhz.xls");
        // 響應類型,編碼
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");

        //因為我業務的表頭是不固定的,而且順序也是按業務規則排序的,可以隨緣改變表頭的位置,我要合並的列是“工作內容”表頭對應的數據,一下是找到“工作內容”所處的位置index
        int index = 0;
        for (int i = 0; i < heads.size(); i++) {
            if ("工作內容".equals(heads.get(i).getXmmc())) {
                index = i;
                break;
            }
        }
        //因為表頭需要額外加上一列序號、任務、期間,那么此時工作內容的位置應該往后移3,工作內容相同的需要也相同,序號也需要合並相同的
        int[] mergeColumnIndex = {0, index + 3};
        //自定義獲取需要導出的數據,根據自己的業務需求來
        List<List<Object>> exportData = getExportData(heads, rwhzViews, index);
        EasyExcel.write(response.getOutputStream())
                .registerWriteHandler(new RwhzCustemhandler())
                .registerWriteHandler(new RwhzMergeCell(1, mergeColumnIndex))
                .sheet("任務匯總導出模板").head(getExcelHeader(heads)).doWrite(exportData);
    }

private List<List<String>> getExcelHeader(List<RwhzHead> heads) {//...}

 

5、重要的是那兩個類

不確定表頭主要是head(List<List<String>>).doWrite( List<List<Object>>)

(1)對於head的List<List<String>>

外面的List的每一個元素List<String>代表每一列表頭,里面的List的每一個元素String代表每一行的表頭,比如

   List<List<String>>heads=new ArrayList<>();
     List<String> list1 = Arrays.asList("AAA", "aaa");
     List<String> list2 = Arrays.asList("AAA", "bbb");
     List<String> list3 = Arrays.asList("AAA", "ccc");
     heads.add(list1 );
     heads.add(list2 );
     heads.add(list3 );

 形成的表頭如下圖所示

 

圖片畫的不夠標准,大概是那樣。

(2)對於數據的List<List<Object>>

外面的List的每一個元素List<Object>代表一行數據,里面List的每一個元素Object代表當前行每一列的數據。

 

合並單元格參考網址:https://blog.csdn.net/weixin_50067580/article/details/111559637

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM