EasyPoi表头字体及样式自定义

        最近在研究EasyPoi的excel导出功能,发现其不支持表头各个单元格样式自定义,所以就对其导出功能进行了重写。

一、EasyPoi源码分析

        在进行重写之前,首先要了解EasyPoi源码中,对表头处理的代码具体是如何实现的。查看源码可以看出,导出功能主要是通过ExcelExportService类来实现,而在其中可以看到向excel中填入表头及数据的方法为insertDataToSheet,具体代码如下:

protected void insertDataToSheet(Workbook workbook, ExportParams entity,
                                     List<ExcelExportEntity> entityList, Collection<?> dataSet,
                                     Sheet sheet) {
    try {
        dataHandler = entity.getDataHandler();
        if (dataHandler != null && dataHandler.getNeedHandlerFields() != null) {
            needHandlerList = Arrays.asList(dataHandler.getNeedHandlerFields());
        }
        dictHandler = entity.getDictHandler();
        commentHandler = entity.getCommentHandler();
        // 创建表格样式
        setExcelExportStyler((IExcelExportStyler) entity.getStyle()
                .getConstructor(Workbook.class).newInstance(workbook));
        Drawing                 patriarch   = PoiExcelGraphDataUtil.getDrawingPatriarch(sheet);
        List<ExcelExportEntity> excelParams = new ArrayList<ExcelExportEntity>();
        if (entity.isAddIndex()) {
            excelParams.add(indexExcelEntity(entity));
        }
        excelParams.addAll(entityList);
        sortAllParams(excelParams);
        int index = entity.isCreateHeadRows()
                ? createHeaderAndTitle(entity, sheet, workbook, excelParams) : 0;
        int titleHeight = index;
        setCellWith(excelParams, sheet);
        setColumnHidden(excelParams, sheet);
        short rowHeight = entity.getHeight() != 0 ? entity.getHeight() : getRowHeight(excelParams);
        setCurrentIndex(1);
        createAddressList(sheet, index, excelParams, 0);
        Iterator<?>  its      = dataSet.iterator();
        List<Object> tempList = new ArrayList<Object>();
        while (its.hasNext()) {
            Object t = its.next();
            index += createCells(patriarch, index, t, excelParams, sheet, workbook, rowHeight, 0)[0];
            tempList.add(t);
            if (index >= MAX_NUM) {
                break;
            }
        }
        if (entity.getFreezeCol() != 0) {
            sheet.createFreezePane(entity.getFreezeCol(), 0, entity.getFreezeCol(), 0);
        }

        mergeCells(sheet, excelParams, titleHeight);

        its = dataSet.iterator();
        for (int i = 0, le = tempList.size(); i < le; i++) {
            its.next();
            its.remove();
        }
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("List data more than max ,data size is {}",
                    dataSet.size());
        }
        // 发现还有剩余list 继续循环创建Sheet
        if (dataSet.size() > 0) {
            createSheetForMap(workbook, entity, entityList, dataSet);
        } else {
            // 创建合计信息
            addStatisticsRow(getExcelExportStyler().getStyles(true, null), sheet);
        }

    } catch (Exception e) {
        LOGGER.error(e.getMessage(), e);
        throw new ExcelExportException(ExcelExportEnum.EXPORT_ERROR, e);
    }
}

        而在此方法中进一步分析,可看出表头数据及样式操作的方法为createHeaderAndTitle,跳转后可确定操作表头方法为createHeaderRow,具体代码如下:

private int createHeaderRow(ExportParams title, Sheet sheet, Workbook workbook, int index,
                                List<ExcelExportEntity> excelParams, int cellIndex) {
    Row row  = sheet.getRow(index) == null ? sheet.createRow(index) : sheet.getRow(index);
    int rows = getRowNums(excelParams, true);
    row.setHeight(title.getHeaderHeight());
    Row listRow = null;
    if (rows >= 2) {
        listRow = sheet.getRow(index + 1);
        if (listRow == null) {
            listRow = sheet.createRow(index + 1);
            listRow.setHeight(title.getHeaderHeight());

        }
    }
    int       groupCellLength = 0;
    CellStyle titleStyle      = getExcelExportStyler().getTitleStyle(title.getColor());
    for (int i = 0, exportFieldTitleSize = excelParams.size(); i < exportFieldTitleSize; i++) {
        ExcelExportEntity entity = excelParams.get(i);
        // 加入换了groupName或者结束就,就把之前的那个换行
        if (StringUtils.isBlank(entity.getGroupName()) || i == 0 || !entity.getGroupName().equals(excelParams.get(i - 1).getGroupName())) {
            if (groupCellLength > 1) {
                sheet.addMergedRegion(new CellRangeAddress(index, index, cellIndex - groupCellLength, cellIndex - 1));
            }
            groupCellLength = 0;
        }
        if (StringUtils.isNotBlank(entity.getGroupName())) {
            createStringCell(row, cellIndex, entity.getGroupName(), titleStyle, entity);
            createStringCell(listRow, cellIndex, entity.getName(), titleStyle, entity);
            groupCellLength++;
        } else if (StringUtils.isNotBlank(entity.getName())) {
            createStringCell(row, cellIndex, entity.getName(), titleStyle, entity);
        }
        if (entity.getList() != null) {
            // 保持原来的
            int tempCellIndex = cellIndex;
            cellIndex = createHeaderRow(title, sheet, workbook, rows == 1 ? index : index + 1, entity.getList(), cellIndex);
            List<ExcelExportEntity> sTitel = entity.getList();
            if (StringUtils.isNotBlank(entity.getName()) && sTitel.size() > 1) {
                PoiMergeCellUtil.addMergedRegion(sheet, index, index, tempCellIndex, tempCellIndex + getFieldLength(sTitel));
            }
            /*for (int j = 0, size = sTitel.size(); j < size; j++) {

                createStringCell(rows == 2 ? listRow : row, cellIndex, sTitel.get(j).getName(),
                        titleStyle, entity);
                cellIndex++;
            }*/
            cellIndex--;
        } else if (rows > 1 && StringUtils.isBlank(entity.getGroupName())) {
            createStringCell(listRow, cellIndex, "", titleStyle, entity);
            PoiMergeCellUtil.addMergedRegion(sheet, index, index + rows - 1, cellIndex, cellIndex);
        }
        cellIndex++;
    }
    if (groupCellLength > 1) {
        PoiMergeCellUtil.addMergedRegion(sheet, index, index, cellIndex - groupCellLength, cellIndex - 1);
    }
    return cellIndex;

}

        分析源码可看出,表头的样式主要是根据excelParams参数中存储的样式来设定,而此参数对应的类型(ExcelExportEntity)中,样式字段只有宽度和高度,而这就是EasyPoi不支持自定义表头样式的原因。

        通过上述分析,我们可知,若要支持自定义表头样式,我们首先考虑在createHeaderRow方法的中增加表头样式的参数(List<ExcelExportExtendEntity> extendList),而此方法为private方法,所以只能在继承ExcelExportService类的自定义类中重载此方法。继而,需要依次重载createHeaderAndTitle、insertDataToSheet、createSheetForMap。而之所以要依次重载这些方法,主要原因在于,表头自定义样式的获取最好和本身excelParams参数内容的获取放在一起,防止重复调用。而excelParams参数内容是通过getAllExcelField方法来获取,源码如下:

public void getAllExcelField(String[] exclusions, String targetId, Field[] fields,
                                 List<ExcelExportEntity> excelParams, Class<?> pojoClass,
                                 List<Method> getMethods, ExcelEntity excelGroup) throws Exception {
    List<String>      exclusionsList = exclusions != null ? Arrays.asList(exclusions) : null;
    ExcelExportEntity excelEntity;
    // 遍历整个filed
    for (int i = 0; i < fields.length; i++) {
        Field field = fields[i];
        // 先判断是不是collection,在判断是不是java自带对象,之后就是我们自己的对象了
        if (PoiPublicUtil.isNotUserExcelUserThis(exclusionsList, field, targetId)) {
            continue;
        }
        // 首先判断Excel 可能一下特殊数据用户回自定义处理
        if (field.getAnnotation(Excel.class) != null) {
            Excel  excel = field.getAnnotation(Excel.class);
            String name  = PoiPublicUtil.getValueByTargetId(excel.name(), targetId, null);
            if (StringUtils.isNotBlank(name)) {
                excelParams.add(createExcelExportEntity(field, targetId, pojoClass, getMethods, excelGroup));
            }
        } else if (PoiPublicUtil.isCollection(field.getType())) {
            ExcelCollection         excel = field.getAnnotation(ExcelCollection.class);
            ParameterizedType       pt    = (ParameterizedType) field.getGenericType();
            Class<?>                clz   = (Class<?>) pt.getActualTypeArguments()[0];
            List<ExcelExportEntity> list  = new ArrayList<ExcelExportEntity>();
            getAllExcelField(exclusions,
                    StringUtils.isNotEmpty(excel.id()) ? excel.id() : targetId,
                    PoiPublicUtil.getClassFields(clz), list, clz, null, null);
            excelEntity = new ExcelExportEntity();
            excelEntity.setName(PoiPublicUtil.getValueByTargetId(excel.name(), targetId, null));
            if (i18nHandler != null) {
                excelEntity.setName(i18nHandler.getLocaleName(excelEntity.getName()));
            }
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值