资讯专栏INFORMATION COLUMN

EasyExcel为单个Cell设置样式

roundstones / 2663人阅读

摘要:是阿里巴巴对封装的一个库,号称解决了的问题,并且在使用上也更方便一些然而我在使用的时候发现还是有很多坑,其中一个比较头疼的是对单个单元格样式的设置。

EasyExcel是阿里巴巴对POI封装的一个库,号称解决了POI的OOM问题,并且在使用上也更方便一些

Github:[](https://github.com/alibaba/ea...

然而我在使用的时候发现还是有很多坑,其中一个比较头疼的是对单个单元格样式的设置。EasyExcel提供了一个BaseRowModel作为每行数据的一个模型,并且其中有一个属性cellStyleMap代表每列样式的集合,本来我以为这个只要在自己定义模型的时候,也把CellStyle定义进去就行了,然而,还是我想多了……定义了CellStyle并没有什么卵用,这是第一个蛋疼的地方

/**
 * Excel基础模型
 * @author jipengfei
 */
public class BaseRowModel {

    /**
     * 每列样式
     */
    private Map cellStyleMap = new HashMap();

    public void addStyle(Integer row, CellStyle cellStyle){
        cellStyleMap.put(row,cellStyle);
    }

    public CellStyle getStyle(Integer row){
        return cellStyleMap.get(row);
    }

    public Map getCellStyleMap() {
        return cellStyleMap;
    }

    public void setCellStyleMap(Map cellStyleMap) {
        this.cellStyleMap = cellStyleMap;
    }
}

后来测试半天,才发现创建CellStyle时必须通过一个Workbook对象来创建,而这个Workbook不能随便新建一个对象完事儿,得用你当前写入的Workbook来创建对应的CellStyle样式才能起作用。然而……事情并没有那么简单,经过我对源码的反复查看,EasyExcel生成excel表的步骤是用一个ExcelWriter来写入数据,并没有提供获取Workbook的方法,不知道什么原因让阿里巴巴不提供这样一个接口……这是第二个蛋疼的地方

既然没有提供接口,那就只能用反射来硬刚了,下面就直接上代码了

我这里是在开始写数据之前就将每张表的CellStyle与每张表关联起来,再在后面的handler中获取到这个CellStyle进行设置

package edu.uddp.util;

import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.context.WriteContext;
import com.alibaba.excel.event.WriteHandler;
import com.alibaba.excel.metadata.BaseRowModel;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.ExcelBuilderImpl;
import com.sun.corba.se.spi.orbutil.threadpool.Work;
import edu.uddp.enums.CellStyleEnum;
import edu.uddp.model.SignExcelRow;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFSheet;

import java.io.*;
import java.lang.reflect.Field;
import java.util.*;

/**
 * 生成Excel表
 *
 * @author Juzi
 * @date 2018/12/23 12:37
 * Blog https://juzibiji.top
 */
public class ExcelUtil {

    private static Map> cellStyles = new HashMap<>();

    /**
     * 使用java对象模型创建excel,并使用handler
     * 生成Excel格式为xlsx
     *
     * @param path           Excel生成路径
     * @param headLineMun    表头占几行
     * @param data           传入的键值对数据(key为sheet名,value为sheet数据)
     * @param handler        自定义的EasyExcel Handler,不使用传入null即可
     * @param columnWidthMap 每列宽度
     * @throws IOException
     */
    public static void createExcelWithModelAndHandler(
            String path, int headLineMun, Map> data, WriteHandler handler,
            Map columnWidthMap, List cellStyleEnums) throws IOException {

        File file = new File(path);
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }

        OutputStream out = new FileOutputStream(path);
        // ExcelWriter用于导出Excel
        ExcelWriter writer = EasyExcelFactory.getWriterWithTempAndHandler(null, out,
                ExcelTypeEnum.XLSX, true, handler);

        // 构造单元格样式
        Workbook workbook = getWorkbook(writer);
        cellStyles.put(workbook, createCellStyle(workbook, cellStyleEnums));

        // sheet的序号,从1开始
        int i = 1;
        // 遍历传入的sheet名和sheet数据来创建sheet
        for (Map.Entry> entry : data.entrySet()) {
            Sheet sheet = new Sheet(i, headLineMun, entry.getValue().get(0).getClass(), entry.getKey(), null);
            sheet.setColumnWidthMap(columnWidthMap);
            writer.write(entry.getValue(), sheet);
            i++;
        }
        // 必须要调用finish(),否则数据不会写入文件
        writer.finish();
        out.close();
    }


    /**
     * **获取workbook**
     * 因为EasyExcel这个库设计的原因
     * 只能使用反射获取workbook
     *
     * @param writer
     * @return
     */
    private static Workbook getWorkbook(ExcelWriter writer) {
        Workbook workbook = null;
        try {
            Class clazz1 = Class.forName("com.alibaba.excel.ExcelWriter");
            Field[] fs = clazz1.getDeclaredFields();
            for (Field field : fs) {
                // 要设置属性可达,不然会抛出IllegalAccessException异常
                field.setAccessible(true);
                if ("excelBuilder".equals(field.getName())) {
                    ExcelBuilderImpl excelBuilder = (ExcelBuilderImpl) field.get(writer);
                    Class clazz2 = Class.forName("com.alibaba.excel.write.ExcelBuilderImpl");
                    Field[] fs2 = clazz2.getDeclaredFields();
                    for (Field field2 : fs2) {
                        field2.setAccessible(true);
                        if ("context".equals(field2.getName())) {
                            WriteContext context = (WriteContext) field2.get(excelBuilder);
                            workbook = context.getWorkbook();
                        }
                    }
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return workbook;
    }

    public static Map createCellStyle(Workbook workbook, List cellStyleEnums) {
        Map map = new HashMap<>();
        for (CellStyleEnum cellStyleEnum : cellStyleEnums) {
            if (cellStyleEnum.getNo() == 1) {
                CellStyle cellStyle = workbook.createCellStyle();
                cellStyle.setBorderBottom(BorderStyle.THIN); //下边框
                cellStyle.setBorderLeft(BorderStyle.THIN);//左边框
                cellStyle.setBorderTop(BorderStyle.THIN);//上边框
                cellStyle.setBorderRight(BorderStyle.THIN);//右边框
                cellStyle.setAlignment(HorizontalAlignment.CENTER);
                map.put(cellStyleEnum.getName(), cellStyle);
            } else if (cellStyleEnum.getNo() == 2) {
                CellStyle cellStyle = workbook.createCellStyle();
                cellStyle.setBorderBottom(BorderStyle.THIN); //下边框
                cellStyle.setBorderLeft(BorderStyle.THIN);//左边框
                cellStyle.setBorderTop(BorderStyle.THIN);//上边框
                cellStyle.setBorderRight(BorderStyle.THIN);//右边框
                cellStyle.setAlignment(HorizontalAlignment.CENTER);
                cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
                cellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
                map.put(cellStyleEnum.getName(), cellStyle);
            }
        }
        return map;
    }

    public static Map> getCellStyles() {
        return cellStyles;
    }
}

EasyExcel提供了一个WriteHandler,我们实现这个接口,就可以在每个单元格写入之后或者每行写入之前来进行拦截(这个handler设计的也很蛋疼),并注入我们自己的业务逻辑(设置单元格样式)。

package edu.uddp.handler;

import com.alibaba.excel.event.WriteHandler;
import edu.uddp.util.ExcelUtil;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFSheet;

import java.util.Map;

/**
 * 第三方库EasyExcel的Handler
 * 教师端生成签到历史表Excel时
 * 将未签到学生进行特殊标识
 *
 * @author Juzi
 * @since 2018/12/22 22:07
 * Blog https://juzibiji.top
 */
public class SignRecordExcelHandler implements WriteHandler {
    @Override
    public void sheet(int i, Sheet sheet) {

    }

    @Override
    public void row(int i, Row row) {

    }

    @Override
    public void cell(int i, Cell cell) {
        // 获取当前workbook对应的CellStyle集合
        Map cellStyleMap = ExcelUtil.getCellStyles().get(cell.getSheet().getWorkbook());

        // 从第二行开始设置格式,第一行是表头
        if (cell.getRowIndex() > 0) {
            if (i == 7 && "未签到".equals(cell.getStringCellValue())) {
                // 该生未签到
                for (int j = 0; j < 8; j++) {
                    cell.getRow().getCell(j).setCellStyle(cellStyleMap.get("未签到"));
                }
            } else if (i == 8 && "已签到".equals(cell.getRow().getCell(7).getStringCellValue())) {
                // 该生已签到
                for (int j = 0; j < 9; j++) {
                    cell.getRow().getCell(j).setCellStyle(cellStyleMap.get("已签到"));
                }
            }else if(i == 8 && "未签到".equals(cell.getRow().getCell(7).getStringCellValue())){
                cell.setCellStyle(cellStyleMap.get("已签到"));
            }
        }
    }
}

上面有一些简单的逻辑处理,就不一一介绍了。

若文章有任何问题,欢迎留言指出——作者博客:桔子笔记

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/72841.html

相关文章

  • springboot批量导入excel数据

    摘要:背景小白今天闲着没事,在公司摸鱼,以为今天有事无聊的一天,突然上头说小子,今天实现一下批量导入数据吧,当时我的内心是拒绝的,然后默默打开。介绍框架本身并不支持读取,所有读取需要借助一些框架。 1 背景 小白今天闲着没事,在公司摸鱼,以为今天有事无聊的一天,突然上头说小子,今天实现一下批量导入Excel数据吧,当时我的内心是拒绝的,然后默默打开idea。 2 介绍 2.1 框架 java...

    Bmob 评论0 收藏0
  • 前端周刊第 4 期

    摘要:最快的方式测量屏幕上所有东西的尺寸,切图必备收费,不贵,代码沙箱,前端代码在线编辑器,在线编程时代的到来。欢迎订阅原周报改名为周刊更合适这个专栏每周末发布,同步更新在前端学堂微信公众号。 周刊是个人本周内看到的有意思的东西,或是技术学习的好文章或好资源,收集分享给大家。 开源库&框架动向 Java 11 (LTS) 版本正式发布 TypeScript 发布 3.1.1 版本 Crea...

    Tonny 评论0 收藏0
  • java 导出 excel 最佳实践,java 大文件 excel 避免OOM(内存溢出) exce

    摘要:消费之后,多线程处理文件导出,生成文件后上传到等文件服务器。前端直接查询并且展现对应的任务执行列表,去等文件服务器下载文件即可。这客户体验不友好,而且网络传输,系统占用多种问题。拓展阅读导出最佳实践框架 产品需求 产品经理需要导出一个页面的所有的信息到 EXCEL 文件。 需求分析 对于 excel 导出,是一个很常见的需求。 最常见的解决方案就是使用 poi 直接同步导出一个 exc...

    K_B_Z 评论0 收藏0
  • CSS命名规范

    摘要:命名规则样式类名全部用小写,首字符必须是字母,禁止数字或其他特殊字符。其他禁止使用在样式表命名中,一律使用命名。什么是命名空间通过统一的命名规范定义命名的范围,成为命名空间。1 前端开发命名规范 1.1 为什么要制定CSS命名规范 统一的命名规范,便于多人开发维护时代码统一,减少项目沟通和交接的成本,增加代码的语义化。 1.2 CSS命名规则 样式类名全部用小写,首字符必须是字母,禁止数...

    vvpale 评论0 收藏0
  • PC端CSS布局汇总

    摘要:因为端和移动端布局差异较大,所以我将两端布局分开讲,本文章将针对端的布局进行讲解,以下代码只写关键代码。为了提高网页性能,考虑到,表格元素尽量少用,有其他选择的情况尽量用其他布局。 前言 此文章是 解剖CSS布局原理 的续集,之前那篇文章讲的都是理论,本文章讲具体的实例,根据自己对布局的理解与开发经验分为以下几类。 因为PC端和移动端布局差异较大,所以我将两端布局分开讲,本文章将针对P...

    zhangxiangliang 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<