EasyExcel導出小結:動態標題、標題格式、相同值合並


1. 實列相關依賴

     <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>2.2.6</version>
     </dependency>
     <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <version>1.9.3</version>
     </dependency>

2.EasyExcel導出常見的兩種方式:

1.根據路徑保存到磁盤:
2.響應Response,用戶直接網頁下載:
正常分為三個步驟:
(1)構建一個ExcelWriter對象。
(2)再次通過write方法寫入數據。
(3)調用EasyExcel的finish

根據路徑保存示例:

     private ExcelWriter excelWriter;    
     public EasyExcelHelper(String path) {
        excelWriter = EasyExcel.write(path).build();
        //固定的excel標題:
        //Class類的屬性必須使用`ExcelProperty`注解修飾。
        //EasyExcel.write(path, Class).build()
    }
    //保存到本地磁盤
    excelWriter.finish();

響應Respones示例:

    private ExcelWriter excelWriter;

    public EasyExcelHelper() {
        excelWriter = new ExcelWriterBuilder()
                    .excelType(ExcelTypeEnum.XLSX)
                    .needHead(true)
                    .build();
    }
    public void export(HttpServletResponse response,String fileName ) {
        final String exportName = fileName + ExcelTypeEnum.XLSX.getValue();
        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
        try {
            excelWriter.finish();
            response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + URLEncoder.encode(exportName, StandardCharsets.UTF_8.name()));
            response.setHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(dataBytes.length));
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            throw new ApiException(ErrorEnum.DOWNLOAD_ERROR);
        }
    }  

3.EaxyExcel動態標題

   /**
     * @param sheetStartNum 默認為0即可
     * @param sheetName     sheet名稱
     * @param headList      動態標題,格式:List<List<String>>
     * @param list          數據,格式List<List<Object>>;
     */
  public void createSheet(Integer sheetStartNum, String sheetName, List headList, List list) {
        WriteSheet sheet= EasyExcel.writerSheet(sheetStartNum, sheetName).build();
        WriteTable table = new WriteTable();
        table.setTableNo(0);
        table.setHead(headList);
        excelWriter.write(list, sheet, table);
    }

4.EaxyExcel標題格式 策略設置

這里我使用兩個策略,分別是defaultStyle、CustomerColumnWidthStyleStrategy。同時啟用兩個策略時,如果我們創建的excel文件有標題defaultStyle將會生效。不存在標題時,直接存入數據時,CustomerColumnWidthStyleStrategy將會適當調整excel寬度。在上面構建WriteSheet的時候我們可以添加這些策略:

 EasyExcel.writerSheet(sheetStartNum, sheetName).
                    registerWriteHandler(defaultStyle()).
                    registerWriteHandler(new CustomerColumnWidthStyleStrategy()).build();
 /**
     * 設置頭部樣式
     *
     * @return
     */
    private HorizontalCellStyleStrategy defaultStyle() {
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        //頭部樣式
        headWriteCellStyle.setFillForegroundColor(IndexedColors.LIME.getIndex());
        WriteFont headWriteFont = new WriteFont();
        headWriteFont.setFontHeightInPoints((short) 12);
        headWriteFont.setFontName("Arial");
        headWriteFont.setBold(Boolean.FALSE);
        headWriteFont.setColor(IndexedColors.WHITE.getIndex());
        headWriteCellStyle.setWriteFont(headWriteFont);
        headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        headWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        headWriteCellStyle.setWrapped(Boolean.FALSE);
        headWriteCellStyle.setBorderRight(BorderStyle.NONE);
        headWriteCellStyle.setBorderLeft(BorderStyle.NONE);
        //內容樣式
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        return new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
    }

    /**
     * 列寬設置
     * memo:當數據不存在標題時,defaultStyle頭部樣式將失效,該設置將會生效
     */
    private class CustomerColumnWidthStyleStrategy extends AbstractColumnWidthStyleStrategy {

        private static final int MAX_COLUMN_WIDTH = 7000;

        @Override
        protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<CellData> cellDataList, Cell cell, Head head,
                                      Integer relativeRowIndex, Boolean isHead) {
            writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), MAX_COLUMN_WIDTH);
        }

    }

5.EaxyExcel 同值合並策略

上面我們添加了excel標題策略,現在我們再添加一個同值合並策略。筆者當前遇到一個需求,需要根據數據中一個字段的集合拆分成多條數據,拆分出來的數據相同值需要合並,所以添加了下面的策略。策略的添加方式與上面一致。
參數說明:
mergeRowIndex:合並開始的位置,第一行為0,正常是標題行,一般我們從1開始。
eachRow:多少行合並一次,假設我們現在根據某個屬性將一條數據拆分成3條,如果我們不希望這3條以外的數據發生相同值合並,那么可以設置為3。
mergeColumnIndex:合並列的下標數據,第一列為0,假設等於[0,1,3],那么就意味着只有這3列會發生合並。
這三個參數配合使用,可以達到這樣的效果:從x行開始,每y條數據發生合並,合並z[z1,z2,z3]的列。

/**
     * 相同值合並策略
     */
    public class ExcelMergeStrategy implements CellWriteHandler {
        /**
         * 合並起始行
         */
        private int mergeRowIndex;

        /**
         * 多少行合並一次
         */
        private int eachRow;
        /**
         * 合並字段的下標
         */
        private int[] mergeColumnIndex;

        public ExcelMergeStrategy(int mergeRowIndex, int[] mergeColumnIndex, int eachRow) {
            if (mergeRowIndex < 0) {
                throw new IllegalArgumentException("mergeRowIndex must be greater than 0");
            }
            if (eachRow < 0) {
                throw new IllegalArgumentException("eachRow must be greater than 0");
            }
            this.mergeRowIndex = mergeRowIndex;
            this.mergeColumnIndex = mergeColumnIndex;
            this.eachRow = eachRow;
        }

        @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) {
            int curRowIndex = cell.getRowIndex();
            //當前列
            int curColIndex = cell.getColumnIndex();
            //合並條件:
            //1.當前行>合並起始行,默認標題行(0)不參加合並
            //2.間隔行(eachRow)的上下兩條不參加合並
            //2.1間隔行(eachRow)==0時,不設置間隔
            if (isMerge(curRowIndex)) {
                IntStream.range(0, mergeColumnIndex.length).anyMatch(i -> {
                    if (curColIndex == mergeColumnIndex[i]) {
                        mergeWithPrevRow(writeSheetHolder, cellData, cell, curRowIndex, curColIndex);
                        return true;
                    }
                    return false;
                });
            }
        }

        @Override
        public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {

        }

        /**
         * 判斷是否合並
         * 1.當前位置必須大於開始位置:curRowIndex > mergeRowIndex
         * 2.根據eachRow 判斷數據分割的間隔
         * 2.1如果根據eachRow=0,默認不合並
         * 2.2如果1如果根據eachRow>0,分割后的第一條數據不會與之前的合並:(curRowIndex-mergeRowIndex)%eachRow==0
         *
         * @return
         */
        private boolean isMerge(Integer curRowIndex) {

            if ((curRowIndex > mergeRowIndex) && eachRow > 0) {
                if ((curRowIndex - mergeRowIndex) % eachRow == 0) {
                    return false;
                }
                return true;
            }

            return false;
        }

        private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, CellData cellData, Cell cell, int curRowIndex, int curColIndex) {
            //獲取當前行的當前列的數據和上一行的當前列列數據,通過上一行數據是否相同進行合並
            Object curData = cellData.getType() == CellDataTypeEnum.STRING ? cellData.getStringValue() : cellData.getNumberValue();
            Cell preCell = cell.getSheet().getRow(curRowIndex - 1).getCell(curColIndex);
            Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() :
                    preCell.getNumericCellValue();
            // 比較當前行的第一列的單元格與上一行是否相同,相同合並當前單元格與上一行
            if (Objects.equals(curData, 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);
                }
            }
        }
    }

6.動態標題拓展(自定義動態標題注解與工具類)

使用場景:當我們需要動態設置excel標題時,但存在部分標題是固定的情況時,我們可以創建一個DemoVO對象使用DynamicColumn修飾這些屬性。通過調用conver方法將DemoVO轉換成一個ColumnData對象的集合。
然后通過commons-beanutils包的BeanUtils.describe()方法將查詢的集合數據映射成Map。

  List<DemoVO> data = query();
  List<ColumnData> columnList = conver(DemoVO.class);
  
  //excel數據
  List<List<Object>> excelData = Lists.newArrayList();
     for (DemoVO o : data) {
                //對象轉map
                Map<String,String> oMap = BeanUtils.describe(o);
                List<Object> baseList = Lists.newArrayList();
                for (ColumnData columnData : columnList) {
                    //按照標題順序設置值
                    baseList.add(oMap.get(columnData.getFieldName()));
                }
                excelData.add(baseList);
     }

1.自定義動態excel注解

@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DynamicColumn {
    String name();//excel標題

    int index(); //標題順序

}

@Data
public class DemoVO {
    @DynamicColumn(name = "庫存", index = 0)
    private String stockState;

    @DynamicColumn(name = "編碼", index = 1)
    private String skuCode;

    @DynamicColumn(name = "描述", index = 2)
    private String skuDesc;
    //動態拆分成多個標題
    private List<String> address;
}

2.注解對應對象

@Builder
@Data
public class ColumnData {

    /**
     * excel 標題
     */
    private String columnName;

    /**
     * 字段 屬性
     */
    private String fieldName;

    /**
     * 排序
     */
    private int index;
}



3.注解轉對象工具類

 public static <R> List<ColumnData> conver(final Class<R> clazz) {
        List<ColumnData> list = Lists.newArrayList();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            DynamicColumn annotation = field.getAnnotation(DynamicColumn.class);
            if (!Objects.isNull(annotation)) {
                ColumnData columnData = ColumnData.builder().
                        columnName(annotation.name()).
                        index(annotation.index()).
                        fieldName(field.getName()).
                        build();
                list.add(columnData);
            }
        }
        list.sort(Comparator.comparingInt(ColumnData :: getIndex));
        return list;
    }

7.實際使用

 public void export() throws Exception {
        String path = "D:/mytest/mycase.xlsx";
        new File(path).createNewFile();
        EasyExcelHelper easyExcelHelper = new EasyExcelHelper(path);

        List<DemoVO> results=query();
        //獲取注解定義的標題
        List<ColumnData> columnList = DynamicColumnUtil.conver(DemoVO.class);
        //設置標題,數據
        List<List<String>> titles = Lists.newArrayList();
        columnList.stream().forEach(c -> titles.add(Lists.newArrayList(c.getColumnName())));
 
        List<List<Object>> excelData = Lists.newArrayList();

        //設置合並策略
        int[] mergeColumnIndex = columnList.stream().mapToInt(ColumnData :: getIndex).toArray();
        easyExcelHelper.mergeStrategy(1, mergeColumnIndex, 5);

        boolean isFirst = true;//第一次需要設置動態標題
        for (DemoVO o : data) {
            //對象轉map
            Map<String,String> oMap = BeanUtils.describe(o);
            List<Object> baseList = Lists.newArrayList();
            for (ColumnData columnData : columnList) {
                //按照標題順序設置值
                baseList.add(oMap.get(columnData.getFieldName()));
            
            
           if (isFirst) {
                    for (String address : o.getAddress()) {
                          titles.add(address);
                    }
                  isFirst=false;  
                }
            //設置值
            for (String address : o.getAddress()) {
                List<Object> row = Lists.newArrayList();
                row.addAll(baseList);//公共部分
                row.add(address));
                excelData.add(row);
            }

        }
        easyExcelHelper.createSheet(0, "測試", titles, excelData);
        easyExcelHelper.getExcelWriter().finish();
    }

8.EasyExcelHelper工具類完整代碼

EasyExcelHelper實際是以上Eaxyexcel功能的封裝,部分代碼上面均有展示,下方直接給出,方便大家參考:

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.enums.CellDataTypeEnum;
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.WriteSheet;
import com.alibaba.excel.write.metadata.WriteTable;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
import lombok.Data;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;

import java.util.List;
import java.util.Objects;
import java.util.stream.IntStream;

/**
 * @author penggaofeng
 * @date 2021/1/25 13:41
 * @description:1.輔助實現動態標題;2.實現行數據合並
 * @modified By:
 * @version: 1.0
 */
@Data
public class EasyExcelHelper {

    private ExcelWriter excelWriter;

    private ExcelMergeStrategy excelMergeStrategy;

    public EasyExcelHelper(String path) {
        excelWriter = EasyExcel.write(path).build();
    }

    /**
     * 動態插入
     *
     * @param sheetStartNum
     * @param sheetName     sheet名稱
     * @param headList      動態標題,格式:List<List<String>>
     * @param list          數據
     */
    public void createSheet(Integer sheetStartNum, String sheetName, List headList, List list) {
        WriteSheet sheet;
        if (Objects.isNull(excelMergeStrategy)) {
            sheet = EasyExcel.writerSheet(sheetStartNum, sheetName).
                    registerWriteHandler(defaultStyle()).
                    registerWriteHandler(new CustomerColumnWidthStyleStrategy()).build();
        } else {
            sheet = EasyExcel.writerSheet(sheetStartNum, sheetName).
                    registerWriteHandler(defaultStyle()).
                    registerWriteHandler(excelMergeStrategy).
                    registerWriteHandler(new CustomerColumnWidthStyleStrategy()).build();
        }

        WriteTable table = new WriteTable();
        table.setTableNo(0);
        table.setHead(headList);
        excelWriter.write(list, sheet, table);
    }

    /**
     * 創建合並策略
     *
     * @param mergeRowIndex    合並開始行 (從1開始,忽略標題)
     * @param mergeColumnIndex 合並列(列下標,從0開始)
     * @param eachRow          合並間隔,指定幾條數據之間合並
     */
    public void mergeStrategy(int mergeRowIndex, int[] mergeColumnIndex, int eachRow) {
        excelMergeStrategy = new ExcelMergeStrategy(mergeRowIndex, mergeColumnIndex, eachRow);
    }

    /**
     * 設置頭部樣式
     *
     * @return
     */
    private HorizontalCellStyleStrategy defaultStyle() {
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        //頭部樣式
        headWriteCellStyle.setFillForegroundColor(IndexedColors.LIME.getIndex());
        WriteFont headWriteFont = new WriteFont();
        headWriteFont.setFontHeightInPoints((short) 12);
        headWriteFont.setFontName("Arial");
        headWriteFont.setBold(Boolean.FALSE);
        headWriteFont.setColor(IndexedColors.WHITE.getIndex());
        headWriteCellStyle.setWriteFont(headWriteFont);
        headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        headWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        headWriteCellStyle.setWrapped(Boolean.FALSE);
        headWriteCellStyle.setBorderRight(BorderStyle.NONE);
        headWriteCellStyle.setBorderLeft(BorderStyle.NONE);
        //內容樣式
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        return new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
    }

    /**
     * 列寬設置
     * memo:當數據不存在標題時,defaultStyle頭部樣式將失效,該設置將會生效
     */
    private class CustomerColumnWidthStyleStrategy extends AbstractColumnWidthStyleStrategy {

        private static final int MAX_COLUMN_WIDTH = 7000;

        @Override
        protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<CellData> cellDataList, Cell cell, Head head,
                                      Integer relativeRowIndex, Boolean isHead) {
            writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), MAX_COLUMN_WIDTH);
        }

    }

    /**
     * 相同值合並策略
     */
    public class ExcelMergeStrategy implements CellWriteHandler {
        /**
         * 合並起始行
         */
        private int mergeRowIndex;

        /**
         * 多少行合並一次
         */
        private int eachRow;
        /**
         * 合並字段的下標
         */
        private int[] mergeColumnIndex;

        public ExcelMergeStrategy(int mergeRowIndex, int[] mergeColumnIndex, int eachRow) {
            if (mergeRowIndex < 0) {
                throw new IllegalArgumentException("mergeRowIndex must be greater than 0");
            }
            if (eachRow < 0) {
                throw new IllegalArgumentException("eachRow must be greater than 0");
            }
            this.mergeRowIndex = mergeRowIndex;
            this.mergeColumnIndex = mergeColumnIndex;
            this.eachRow = eachRow;
        }

        @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) {
            int curRowIndex = cell.getRowIndex();
            //當前列
            int curColIndex = cell.getColumnIndex();
            //合並條件:
            //1.當前行>合並起始行,默認標題行(0)不參加合並
            //2.間隔行(eachRow)的上下兩條不參加合並
            //2.1間隔行(eachRow)==0時,不設置間隔
            if (isMerge(curRowIndex)) {
                IntStream.range(0, mergeColumnIndex.length).anyMatch(i -> {
                    if (curColIndex == mergeColumnIndex[i]) {
                        mergeWithPrevRow(writeSheetHolder, cellData, cell, curRowIndex, curColIndex);
                        return true;
                    }
                    return false;
                });
            }
        }

        @Override
        public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {

        }

        /**
         * 判斷是否合並
         * 1.當前位置必須大於開始位置:curRowIndex > mergeRowIndex
         * 2.根據eachRow 判斷數據分割的間隔
         * 2.1如果根據eachRow=0,默認不合並
         * 2.2如果1如果根據eachRow>0,分割后的第一條數據不會與之前的合並:(curRowIndex-mergeRowIndex)%eachRow==0
         *
         * @return
         */
        private boolean isMerge(Integer curRowIndex) {

            if ((curRowIndex > mergeRowIndex) && eachRow > 0) {
                if ((curRowIndex - mergeRowIndex) % eachRow == 0) {
                    return false;
                }
                return true;
            }

            return false;
        }

        private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, CellData cellData, Cell cell, int curRowIndex, int curColIndex) {
            //獲取當前行的當前列的數據和上一行的當前列列數據,通過上一行數據是否相同進行合並
            Object curData = cellData.getType() == CellDataTypeEnum.STRING ? cellData.getStringValue() : cellData.getNumberValue();
            Cell preCell = cell.getSheet().getRow(curRowIndex - 1).getCell(curColIndex);
            Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() :
                    preCell.getNumericCellValue();
            // 比較當前行的第一列的單元格與上一行是否相同,相同合並當前單元格與上一行
            if (Objects.equals(curData, 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);
                }
            }
        }
    }

}


免責聲明!

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



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