Java操作Excel究竟能有多简单!

前言

在工作中,使用excel表格处理数据是很常见的操作,咱们接下来就来讲解下如何使用开源轮子实现下载、导入、导出的功能。

在之前,很多Java程序员都喜欢使用POI的类库来操作excel,但是非常的不方便,不仅代码写的很臃肿,还要处理各种office版本兼容问题,最怕的就是使用不当很容易造成内存溢出,因此今天给大家推荐阿里的一款开源项目 easyexcel。

项目介绍

easyexcel是一款快速、简单避免OOM的java处理Excel工具

github地址:https://github.com/alibaba/easyexcel

Start:15.2k

看了下,两天前项目团队还有在完善代码,可见项目还是挺活跃的


项目集成

使用idea开发工具简单创建了一个easyexcel-demo项目,加入了web模块以及easyexcel maven依赖,依赖如下:

<!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->

<dependency>

    <groupId>com.alibaba</groupId>

    <artifactId>easyexcel</artifactId>

    <version>2.2.4</version>

</dependency>

版本的话我们使用2.2.4,2020年6月份上传的,算是最新的版本了。



好了,我们就开始写功能了。

1、实现已有Excel模板下载

很多系统有数据批量导入的场景,因为在页面上批量加数据时间成本太大了,但是一般导入的时候得按照一定的格式改,所以一般好的产品会先让用户下载一个带有格式的文档,然后按照格式写好以后上传导入,我们来实现这个功能吧!

创建模板文件

首先我们创建一个模板文件,内容如图



将模板文件放置再项目里

然后我们把它放在项目的配置文件下,如图



然后下载代码也很简单,主要分为加载资源->读取资源->写入响应流

@RestController

@RequestMapping("/user")

public classUserController{

    /**

* 下载模板

*/

    @GetMapping("/downloadTemplate")

    publicvoiddownloadTemplate(HttpServletResponse response)throwsException{

        ClassPathResource classPathResource = new ClassPathResource("excelTemplate/easyexcel.xlsx");

        InputStream inputStream = classPathResource.getInputStream();

        Workbook workbook = new HSSFWorkbook(inputStream);

        response.setContentType("application/vnd.ms-excel");

        response.setHeader("content-Disposition", "attachment;filename=" + URLEncoder.encode("easyexcel.xlsx", "utf-8"));

        response.setHeader("Access-Control-Expose-Headers", "content-Disposition");

        OutputStream outputStream = response.getOutputStream();

        workbook.write(outputStream);

        outputStream.flush();

        outputStream.close();

    }

}

测试

启动项目,访问,如图所示,可以下载。


2.写入数据并生成文件

将数据导出到文档这种场景可以说是最常见的了,那么怎么使用easyExcel快速实现呢,我们同样还是以上面的模板为例

定义模型映射对象 UserExcelModel

@Data

public classUserExcelModelextendsBaseRowModelimplementsSerializable{

    @ExcelProperty(value = "用户名", index = 0)

    private String name;

    @ExcelProperty(value = "年龄", index = 1)

    private Integer age;

    @ExcelProperty(value = "手机号", index = 2)

    private String mobile;

    @ExcelProperty(value = "性别", index = 3)

    private String sex;

}

定义这个对象的目的有两个:当前场景下写入文件作为model对象构造数据以及下个要讲的数据读取了。

「简要代码流程如下:」

定义列标题->创建sheet->自定义字体和风格->构造数据->写入数据->写入到浏览器响应流

/**

* 导出数据

*/

    @GetMapping("/exportData")

    publicvoidexportData(HttpServletResponse response)throwsException{

        XSSFWorkbook workbook = new XSSFWorkbook();

        String []columnNames = {"用户名","年龄","手机号","性别"};

        Sheet sheet = workbook.createSheet();

        Font titleFont = workbook.createFont();

        titleFont.setFontName("simsun");

        titleFont.setBold(true);

        titleFont.setColor(IndexedColors.BLACK.index);

        XSSFCellStyle titleStyle = workbook.createCellStyle();

        titleStyle.setAlignment(HorizontalAlignment.CENTER);

        titleStyle.setVerticalAlignment(VerticalAlignment.CENTER);

        titleStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);

        titleStyle.setFillForegroundColor(IndexedColors.YELLOW.index);

        titleStyle.setFont(titleFont);

        Row titleRow = sheet.createRow(0);

        for (int i = 0; i < columnNames.length; i++) {

            Cell cell = titleRow.createCell(i);

            cell.setCellValue(columnNames[i]);

            cell.setCellStyle(titleStyle);

        }

        //模拟构造数据

        List<UserExcelModel> dataList = new ArrayList<>();

        dataList.add(new UserExcelModel("张三",12,"13867098765","男"));

        dataList.add(new UserExcelModel("张三1",12,"13867098765","男"));

        dataList.add(new UserExcelModel("张三2",12,"13867098765","男"));

        dataList.add(new UserExcelModel("张三3",12,"13867098765","男"));

        //创建数据行并写入值

        for (int j = 0; j < dataList.size(); j++) {

            UserExcelModel userExcelModel = dataList.get(j);

            int lastRowNum = sheet.getLastRowNum();

            Row dataRow = sheet.createRow(lastRowNum + 1);

            dataRow.createCell(0).setCellValue(userExcelModel.getName());

            dataRow.createCell(1).setCellValue(userExcelModel.getAge());

            dataRow.createCell(2).setCellValue(userExcelModel.getMobile());

            dataRow.createCell(3).setCellValue(userExcelModel.getSex());

        }

        response.setContentType("application/vnd.ms-excel");

        response.setHeader("content-Disposition", "attachment;filename=" + URLEncoder.encode("easyexcel.xls", "utf-8"));

        response.setHeader("Access-Control-Expose-Headers", "content-Disposition");

        OutputStream outputStream = response.getOutputStream();

        workbook.write(outputStream);

        outputStream.flush();

        outputStream.close();

    }

3.读取数据


我们再回过头来看我们定义的这个Model对象,通过指定index可以对应读取的excel里面的列,然后定义的数据类型就对应到excel里面具体的值,来看看如何实现:

 @PostMapping("/readExcel")

    publicListreadExcel(@RequestParam("file")MultipartFile file){

        List<UserExcelModel> list = new ArrayList<>();

        try {

            list = EasyExcel.read(file.getInputStream(),UserExcelModel.class,new ModelExcelListener()).sheet().doReadSync();

        } catch (IOException e) {

            e.printStackTrace();

        }

        return list;

    }

看完代码是不是心里一万头草拟吗飞过~ 看完这个代码再看用poi工具处理的,是不是相当简洁了。对于代码中的ModelExcelListener,其实是我们自定义的一个读取监听类,贴贴代码:

public static classModelExcelListenerextendsAnalysisEventListener{

        private List<Object> datas = new ArrayList<>();

        /**

* 通过 AnalysisContext 对象还可以获取当前 sheet,当前行等数据

*/

        @Override

        publicvoidinvoke(Object data, AnalysisContext context){

            //数据存储到list,供批量处理,或后续自己业务逻辑处理。

            log.info("读取到数据{}",data);

            datas.add(data);

            //根据业务自行处理,可以写入数据库等等

        }

        //所以的数据解析完了调用

        @Override

        publicvoiddoAfterAllAnalysed(AnalysisContext context){

            log.info("所有数据解析完成");

        }

    }

这是一个读取数据监听类,有特殊业务需求的都可以在这个类里面自定义实现,比如边读边写库啊,数据过滤和处理等等,用的好了绝对是一把利剑。

PostMan模拟调用

控制台输出

总结

通过本篇文章,我们演示了如何使用easyexcel进行一些excel的操作,在实际的项目应用中,可以对以上示例代码进行进一步的封装,使其不管是读取、导出等操作都能几行代码搞定,这个就得根据情况大家自由发挥了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,128评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,316评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,737评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,283评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,384评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,458评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,467评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,251评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,688评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,980评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,155评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,818评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,492评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,142评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,382评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,020评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,044评论 2 352

推荐阅读更多精彩内容