乐趣区

关于springboot:SpringBoot整合Easyexcel操作Excel闲暇之余让我们学习更多

对于封面:

Easyexcel 官网文档

Easyexcel | github

前言

最近也是在写的一个小练习中,须要用到这个。趁着这次就将写个整合的 Demo 给大家。

心愿可能让大家有所播种。

浏览完本文,我想你对于应用 Java 配合 Easyexcel 操作 Excel 是齐全没有问题的啦。

一、环境筹备

1.1、导入相干依赖依赖

我应用 Easyexcel 的 jar 包是 2021 年 10 月的,说一句是最新版本,莫问题吧😁

easyexcel | maven

<!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>3.0.2</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.74</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>

1.2、我的项目构造

搭建个我的项目大家都会啦,这里放一下我本人的构造。

二、读 Excel 操作 readExcel

2.1、后期筹备

筹备好一个 xslx 文件模板,我就是筹备了我本人了。

咱们创立一个实体类,来对应 xlsx 中的列名。

实体类

@Data
public class DemoModel {
    
    /**
     * 用名字去匹配,这里须要留神,如果名字反复,会导致只有一个字段读取到数据, 所以咱们罕用上面这样的格局来写确定。*/
    @ExcelProperty(value = "博客名", index = 0)
    private String name;
    
    
    @ExcelProperty(value = "社区", index = 1)
    private String communityName;

    @ExcelProperty(value = "主页", index = 2)
    private String homePageUrl;

    @ExcelProperty(value = "波及畛域", index = 3)
    private String specialty;

    @ExcelProperty(value = "分割邮箱", index = 4)
    private String email;

    /**
     * 这里用 string 去接日期能力格式化。我想接管年月日格局
     */
    @DateTimeFormat("yyyy-MM-dd HH:mm:ss")
    @ExcelProperty(value = "公布的第一篇原创文章", index = 5)
    private String startDate;
}

监听器

/**
 * 有个很重要的点 DocumentListener 不能被 spring 治理,要每次读取 excel 都要 new, 而后外面用到 spring 能够构造方法传进去
 * @author crush
 */
public class DemoListener extends AnalysisEventListener<DemoModel> {private static final Logger LOGGER = LoggerFactory.getLogger(DemoListener.class);
    

    /**
     * 每隔 5 条存储数据库,理论应用中能够 3000 条,而后清理 list,不便内存回收
     */
    private static final int BATCH_COUNT = 10;

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

    /**
     * 假如这个是一个 DAO,当然有业务逻辑这个也能够是一个 service。当然如果不必存储这个对象没用。*/
    private DemoMapper demoMapper;

    public DemoListener() {
        // 这里是 demo,所以轻易 new 一个。理论应用如果到了 spring, 请应用上面的有参构造函数
        demoMapper = new DemoMapper();}

    /**
     * 如果应用了 spring, 请应用这个构造方法。每次创立 Listener 的时候须要把 spring 治理的类传进来
     *
     * @param demoDAO
     */
    public DemoListener(DemoMapper demoMapper) {this.demoMapper = demoMapper;}
    /**
     * 这个每一条数据解析都会来调用
     *
     * @param data
     *            one row value. Is is same as {@link AnalysisContext#readRowHolder()}
     * @param context
     */
    @Override
    public void invoke(DemoModel data, AnalysisContext context) {LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data));
        list.add(data);
        // 达到 BATCH_COUNT 了,须要去存储一次数据库,避免数据几万条数据在内存,容易 OOM
        if (list.size() >= BATCH_COUNT) {saveData();
            // 存储实现清理 list
            list.clear();}
    }

    /**
     * 所有数据解析实现了 都会来调用
     *
     * @param context
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 这里也要保留数据,确保最初遗留的数据也存储到数据库
        saveData();
        LOGGER.info("所有数据解析实现!"+count);
    }

    /**
     * 加上存储数据库
     */
    private void saveData() {LOGGER.info("{}条数据,开始存储数据库!", list.size());
        // 进行数据库层面操作
        demoMapper.save(list);
        LOGGER.info("存储数据库胜利!");
    }
}

mapper 层: 此处只是模仿

/**
 * @Author: crush
 * @Date: 2021-10-31 11:39
 * version 1.0
 */
@Repository
public class DemoMapper {public void save(List<DemoModel> demoModels){System.out.println("Mapper:"+demoModels);
    }
}

类型转换

2.2、读单个 Sheet

/**
     * demo1 最简略的读
     * 咱们先操作单个的 Sheet, 进行读操作
     * * <p>1. 创立 excel 对应的实体对象 参照{@link QuestionModel}
     * * <p>2. 因为默认一行行的读取 excel,所以须要创立 excel 一行一行的回调监听器,参照{@link DocumentListener}
     * * <p>3. 间接读即可
     */
@Test
public void demo1TestRead() {
    // 有个很重要的点 DemoDataListener 不能被 spring 治理,要每次读取 excel 都要 new, 而后外面用到 spring 能够构造方法传进去
    // 写法 1:String fileName = "E:\\project_code\\commons-utils\\springboot-excel\\src\\main\\resources\\excel\\demo.xlsx";
    // 这里 须要指定读用哪个 class 去读,而后读取第一个 sheet 文件流会主动敞开
    EasyExcel.read(fileName, DemoModel.class, new DemoListener()).sheet().doRead();
}

这里咱们无需指定 sheet,因为咱们就一个工作表,间接默认就完事了。

控制台输入:

23:35:52.583 [main] INFO com.crush.excel.listener.DemoListener - 解析到一条数据:{"communityName":"掘金","email":"nzc_wyh@163.com","homePageUrl":"https://juejin.cn/user/2859142558267559","name":"宁在春","specialty":"Java 后端开发","startDate":"2021-10-31 12:01:52"}
23:35:52.584 [main] INFO com.crush.excel.listener.DemoListener - 解析到一条数据:{"communityName":"CSDN","email":"nzc_wyh@163.com","homePageUrl":"https://blog.csdn.net/weixin_45821811?spm=1000.2115.3001.5343","name":"宁在春","specialty":"Java 后端开发","startDate":"2020-05-11 12:01:52"}
23:35:52.585 [main] INFO com.crush.excel.listener.DemoListener - 2 条数据,开始存储数据库!Mapper:[DemoModel(name= 宁在春, communityName= 掘金, homePageUrl=https://juejin.cn/user/2859142558267559, specialty=Java 后端开发, email=nzc_wyh@163.com, startDate=2021-10-31 12:01:52), DemoModel(name= 宁在春, communityName=CSDN, homePageUrl=https://blog.csdn.net/weixin_45821811?spm=1000.2115.3001.5343, specialty=Java 后端开发, email=nzc_wyh@163.com, startDate=2020-05-11 12:01:52)]
23:35:52.617 [main] INFO com.crush.excel.listener.DemoListener - 存储数据库胜利!23:35:52.618 [main] INFO com.crush.excel.listener.DemoListener - 所有数据解析实现!2

这是最简略的形式,也是读取 Excel 中,单个 Sheet 的操作,但咱们平时中,一个 excel 是会有多个工作表的。

如下:

2.3、读多个 Sheet

其实实质上还是操作单个 sheet 工作表。

因为各个 Sheet 的数据不同,因此要建设多个 Model 和多个监听类。

这边就不再把全副 model 贴出了,如果不太明确,能够去文末看看源码。

同时也要创立多个监听器。

mapper 层在这里就省略了哈。

/**
     * 读多个或者全副 sheet, 这里留神一个 sheet 不能读取屡次,屡次读取须要从新读取文件
     * <p>
     * 1. 创立 excel 对应的实体对象 参照{@link QuestionModel}
     * <p>
     * 2. 因为默认一行行的读取 excel,所以须要创立 excel 一行一行的回调监听器,参照{@link DocumentListener}
     * <p>
     * 3. 间接读即可
     */
@Test
public void repeatedRead() {
    String fileName = "E:\\project_code\\commons-utils\\springboot-excel\\src\\main\\resources\\excel\\Document_Success.xlsx";
    // 读取须要读取的 Sheet
    ExcelReader excelReader = EasyExcel.read(fileName).build();
    //  本人应用性能必须不同的 Listener
    ReadSheet readSheet1 =
        EasyExcel.readSheet(0).head(DocumentModel.class).registerReadListener(new DocumentListener()).build();
    ReadSheet readSheet2 =
        EasyExcel.readSheet(1).head(TemplateModel.class).registerReadListener(new TemplateListener()).build();

    ReadSheet readSheet3 =
        EasyExcel.readSheet(2).head(SectionModel.class).registerReadListener(new SectionListener()).build();

    ReadSheet readSheet4 =
        EasyExcel.readSheet(3).head(QuestionModel.class).registerReadListener(new QuestionListener()).build();

    ReadSheet readSheet5 =
        EasyExcel.readSheet(4).head(OptionModel.class).registerReadListener(new OptionListener()).build();

    ReadSheet readSheet6 =
        EasyExcel.readSheet(5).head(ConditionModel.class).registerReadListener(new ConditionListener()).build();

    ReadSheet readSheet7 =
        EasyExcel.readSheet(6).head(QuestionTooltipModel.class).registerReadListener(new QuestionTooltipListener()).build();

    ReadSheet readSheet8 =
        EasyExcel.readSheet(7).head(OptionTooltipModel.class).registerReadListener(new OptionTooltipListener()).build();

    // 这里留神 肯定要把 sheet1 sheet2 一起传进去,不然有个问题就是 03 版的 excel 会读取屡次,节约性能
    excelReader.read(readSheet1, readSheet2, readSheet3, readSheet4, readSheet5, readSheet6, readSheet7, readSheet8);
    // 这里千万别遗记敞开,读的时候会创立临时文件,到时磁盘会崩的
    excelReader.finish();}

控制台输入:

23:42:19.733 [main] INFO com.crush.excel.listener.DocumentListener - 解析到一条数据:{"customerId":1,"name":"Document i"}

23:42:19.755 [main] INFO com.crush.excel.listener.TemplateListener - 解析到一条数据:{"documentType":1,"fontStyleId":1,"lobId":1,"name":"Template q","userGroupId":1}


23:42:19.785 [main] INFO com.crush.excel.listener.SectionListener - 解析到一条数据:{"index":1,"name":"Section 1","order":1}
23:42:19.785 [main] INFO com.crush.excel.listener.SectionListener - 解析到一条数据:{"index":2,"name":"Section 2","order":2}


23:42:19.823 [main] INFO com.crush.excel.listener.QuestionListener - 解析到一条数据:{"allowComments":"false","answerType":"1","enhancedField":"false","index":"1","order":"1","question":"This is Simple Question","required":"true","sectionIndex":"1"}
23:42:19.824 [main] INFO com.crush.excel.listener.QuestionListener - 解析到一条数据:{"allowComments":"false","answerType":"2","enhancedField":"false","index":"2","order":"2","question":"This is Simple Question","required":"false","sectionIndex":"1"}
23:42:19.825 [main] INFO com.crush.excel.listener.QuestionListener - 解析到一条数据:{"allowComments":"false","answerType":"10","enhancedField":"false","index":"3","order":"3","question":"This is Simple Question","required":"false","sectionIndex":"1"}
23:42:19.826 [main] INFO com.crush.excel.listener.QuestionListener - 解析到一条数据:{"allowComments":"false","answerType":"3","enhancedField":"false","index":"4","order":"1","question":"This is Simple Question","required":"true","sectionIndex":"2"}
23:42:19.827 [main] INFO com.crush.excel.listener.QuestionListener - 解析到一条数据:{"allowComments":"false","answerType":"5","enhancedField":"false","index":"5","order":"2","question":"This is Simple Question","required":"false","sectionIndex":"2"}
23:42:19.831 [main] INFO com.crush.excel.listener.QuestionListener - 解析到一条数据:{"allowComments":"false","answerType":"12","enhancedField":"false","index":"6","order":"3","question":"This is Simple Question","required":"true","sectionIndex":"2"}

23:42:19.847 [main] INFO com.crush.excel.listener.OptionListener - 解析到一条数据:{"index":1,"order":1,"questionIndex":3,"value":"Option 1"}
23:42:19.848 [main] INFO com.crush.excel.listener.OptionListener - 解析到一条数据:{"index":2,"order":2,"questionIndex":3,"value":"Option 2"}
23:42:19.849 [main] INFO com.crush.excel.listener.OptionListener - 解析到一条数据:{"index":3,"order":3,"questionIndex":3,"value":"Option 3"}
23:42:19.849 [main] INFO com.crush.excel.listener.OptionListener - 解析到一条数据:{"index":4,"order":4,"questionIndex":3,"value":"Option 4"}
23:42:19.850 [main] INFO com.crush.excel.listener.OptionListener - 解析到一条数据:{"index":5,"order":1,"questionIndex":6,"value":"Option 1"}
23:42:19.850 [main] INFO com.crush.excel.listener.OptionListener - 解析到一条数据:{"index":6,"order":2,"questionIndex":6,"value":"Option 2"}
23:42:19.851 [main] INFO com.crush.excel.listener.OptionListener - 解析到一条数据:{"index":7,"order":3,"questionIndex":6,"value":"Option 3"}

23:42:19.868 [main] INFO com.crush.excel.listener.ConditionListener - 解析到一条数据:{"action":1,"index":1,"questionIndex":1,"selectedAnswer":"Test","triggerQuestionIndex":1,"triggerSectionIndex":1}
23:42:19.869 [main] INFO com.crush.excel.listener.ConditionListener - 解析到一条数据:{"action":1,"index":2,"questionIndex":2,"selectedAnswer":"Test","triggerSectionIndex":2}



23:42:19.888 [main] INFO com.crush.excel.listener.QuestionTooltipListener - 解析到一条数据:{"endIndex":10,"index":1,"parentIndex":1,"startIndex":1,"text":"Sample Tooltip"}


23:42:19.908 [main] INFO com.crush.excel.listener.OptionTooltipListener - 解析到一条数据:{"endIndex":10,"index":1,"parentIndex":1,"startIndex":1,"text":"Sample Tooltip"}
23:42:19.910 [main] INFO com.crush.excel.listener.OptionTooltipListener - 解析到一条数据:{"endIndex":10,"index":2,"parentIndex":2,"startIndex":1,"text":"Sample Tooltip"}

咱们能够在获取到数据的时候,存储进数据库。另外咱们经常会上传 excel,进行数据的导入,所以咱们再来看看 web 中的 excel 的读。

2.4、web 中的读

@AutowiredDemoMapper demoMapper;/** * 文件上传 * <p> * 1. 创立 excel 对应的实体对象 参照{@link UploadData} * <p> * 2. 因为默认一行行的读取 excel,所以须要创立 excel 一行一行的回调监听器,参照{@link UploadDataListener} * <p> * 3. 间接读即可 */@PostMapping("upload")@ResponseBodypublic String upload(MultipartFile file) throws IOException {EasyExcel.read(file.getInputStream(), DemoModel.class, new DemoListener(demoMapper)).sheet().doRead();    return "success";}

我想这样的场景是咱们在 Web 开发中最罕用到的那种。

如果是内存足够,数据量不是特地大的话,像我这么写也是齐全可能承受的。

如果是操作数据十万或几十万数据的大兄弟,能够前去官网看看优化计划。👉Easyexcel | github

三、写 Excle 操作 writeExcel

3.1、写到单个 Sheet 中

/**
     * 最简略的写
     * <p>1. 创立 excel 对应的实体对象 参照{@link DemoModel}
     * <p>2. 间接写即可
     */
@Test
public void simpleWrite() {DemoModel model = new DemoModel();
    model.setName("宁在春");
    model.setCommunityName("知乎");
    model.setHomePageUrl("https://www.zhihu.com/creator/manage/creation/all");
    model.setEmail("nza_wyh@163.com");
    model.setSpecialty("SpringBoot");
    model.setStartDate("2021-10-31 12:00:00");
    DemoModel model2 = new DemoModel();
    model2.setName("宁在春 2");
    model2.setCommunityName("知乎 2");
    model2.setHomePageUrl("2https://www.zhihu.com/creator/manage/creation/all");
    model2.setEmail("nza_wyh@163.com2");
    model2.setSpecialty("SpringBoot2");
    model2.setStartDate("2021-10-31 12:00:00");
    List<DemoModel> models = new ArrayList<DemoModel>();
    models.add(model);
    models.add(model2);
    // 写法 1
    String fileName = "E:\\project_code\\commons-utils\\springboot-excel\\src\\main\\resources\\excel\\demo2.xlsx";
    // 这里 须要指定写用哪个 class 去写,而后写到第一个 sheet,名字为模板 而后文件流会主动敞开
    // 如果这里想应用 03 则 传入 excelType 参数即可
    EasyExcel.write(fileName, DemoModel.class).sheet(0).doWrite(models);
    
    //        // 写法 2
    //        // 这里 须要指定写用哪个 class 去写
    ExcelWriter excelWriter = EasyExcel.write(fileName, DemoModel.class).build();
    WriteSheet writeSheet = EasyExcel.writerSheet(0).build();
    excelWriter.write(models, writeSheet);
    // 千万别遗记 finish 会帮忙敞开流
    excelWriter.finish();}

这是操作 excel 文件中单个 Sheet 的操作,非常简略。

EasyExcel.write(fileName, DemoModel.class).sheet(0).doWrite(models);对于 sheet()中的参数 0,咱们其实就一张 Sheet 工作表,填与不填其实都一样,另外,此处也能够填 sheet 表名字,也是一样。

操作后果:

留神:

留神:我发现如果我是间接向这个 excel 文件进行写入,默认是采纳笼罩的形式进行写入,即之前有的信息都会被笼罩掉。

测试:

写之前:

写之后:

补充:

如果咱们间接写,是采纳笼罩模式的,这必定是不合乎一些业务场景的。所以必定有解决形式的,

easyexcel 中对此也是有解决的。

它有一个依据模板写入,模板如下:

/**
     * 依据模板写入
     * <p>1. 创立 excel 对应的实体对象 参照
     * <p>2. 应用 注解指定写入的列
     * <p>3. 应用 withTemplate 写取模板
     * <p>4. 间接写即可
     */
@Test
public void templateWrite() {DemoModel model = new DemoModel();
    model.setName("宁在春");
    model.setCommunityName("知乎");
    model.setHomePageUrl("https://www.zhihu.com/creator/manage/creation/all");
    model.setEmail("nza_wyh@163.com");
    model.setSpecialty("SpringBoot");
    model.setStartDate("2021-10-31 12:00:00");
    DemoModel model2 = new DemoModel();
    model2.setName("宁在春 2");
    model2.setCommunityName("知乎 2");
    model2.setHomePageUrl("2https://www.zhihu.com/creator/manage/creation/all");
    model2.setEmail("nza_wyh@163.com2");
    model2.setSpecialty("SpringBoot2");
    model2.setStartDate("2021-10-31 12:00:00");
    List<DemoModel> models = new ArrayList<DemoModel>();
    models.add(model);
    models.add(model2);
    String templateFileName = "E:\\project_code\\commons-utils\\springboot-excel\\src\\main\\resources\\excel\\demo2.xlsx";
    String fileName = "E:\\project_code\\commons-utils\\springboot-excel\\src\\main\\resources\\excel\\templateWrite.xlsx";
    // 这里 须要指定写用哪个 class 去写,而后写到第一个 sheet,名字为模板 而后文件流会主动敞开
    EasyExcel.write(fileName, DemoModel.class).withTemplate(templateFileName).sheet().doWrite(models);
}

最初的成果如下:

写到留神那一大节的时候,我也有思考这个是如何进行解决的。

我最开始想的是,是先把文件读出来,而后把数据拼接起来,再写进去。然而我一下就颠覆这个想法,一旦那样做,内存耗费什么的都太大了,不太适合。

而后简略看了一下,它是间接 new 了一个 File,加载进内存。(感觉本人好憨)


因为这个我又去测试了个不同的,如果把模板批改的不合乎会咋样。

测试的后果就是合乎我的猜想,就是 copy 了一份原文件,在源文件的根底上进行写操作,不论原文件格式如何,都会进行保留。

3.2、反复写入或写到多个 Sheet 中

反复写入:

其实就是循环了单个的操作。

// 办法 1 如果写到同一个 sheet
    String fileName = "E:\\project_code\\commons-utils\\springboot-excel\\src\\main\\resources\\excel\\demo2.xlsx";
//        // 这里 须要指定写用哪个 class 去写
ExcelWriter excelWriter = EasyExcel.write(fileName, DemoModel.class).build();
WriteSheet writeSheet = EasyExcel.writerSheet(0).build();
// 去调用写入, 这里我调用了五次,理论应用时依据数据库分页的总的页数来
for (int i = 0; i < 5; i++) {
    // 分页去数据库查问数据 这里能够去数据库查问每一页的数据
    List<DemoModel> data = data();
    excelWriter.write(data, writeSheet);
}
// 千万别遗记 finish 会帮忙敞开流
excelWriter.finish();

data()就是生成数据的一个办法。

写到多个 Sheet 中:

其本质也是下面那样,只是调用不同监听类,不同的对象罢了,更简略的形式,以做到不同的解决,目前还没有找到更简略的办法。

和读多个 sheet 中一样的形式,在此处就不再复述了。

3.3、web 中的写

既然有写就要也有读了,善始善终,这个也给大家贴出来了。

/**
     * 文件下载(失败了会返回一个有局部数据的 Excel)* <p>
     * 1. 创立 excel 对应的实体对象 参照
     * <p>
     * 2. 设置返回的 参数
     * <p>
     * 3. 间接写,这里留神,finish 的时候会主动敞开 OutputStream, 当然你里面再敞开流问题不大
     */
@GetMapping("download")
public void download(HttpServletResponse response) throws IOException {
    // 这里留神 有同学反馈应用 swagger 会导致各种问题,请间接用浏览器或者用 postman
    response.setContentType("application/vnd.ms-excel");
    response.setCharacterEncoding("utf-8");
    // 这里 URLEncoder.encode 能够避免中文乱码 当然和 easyexcel 没有关系
    String fileName = URLEncoder.encode("测试", "UTF-8");
    response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
    // 这里的 sheet 的参数就是生成后的工作表的名称
    EasyExcel.write(response.getOutputStream(), DemoModel.class).sheet("模板").doWrite(data());
}

/**
     * 文件下载并且失败的时候返回 json(默认失败了会返回一个有局部数据的 Excel)*
     * @since 2.1.1
     */
@GetMapping("downloadFailedUsingJson")
public void downloadFailedUsingJson(HttpServletResponse response) throws IOException {
    // 这里留神 有同学反馈应用 swagger 会导致各种问题,请间接用浏览器或者用 postman
    try {response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        // 这里 URLEncoder.encode 能够避免中文乱码 当然和 easyexcel 没有关系
        String fileName = URLEncoder.encode("测试", "UTF-8");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
        // 这里须要设置不敞开流
        EasyExcel.write(response.getOutputStream(), DemoModel.class).autoCloseStream(Boolean.FALSE).sheet("模板")
            .doWrite(data());
    } catch (Exception e) {
        // 重置 response
        response.reset();
        response.setContentType("application/json");
        response.setCharacterEncoding("utf-8");
        Map<String, String> map = new HashMap<String, String>();
        map.put("status", "failure");
        map.put("message", "下载文件失败" + e.getMessage());
        response.getWriter().println(JSON.toJSONString(map));
    }
}

private List<DemoModel> data(){List<DemoModel> demoModels = new ArrayList<>();
    DemoModel model = new DemoModel();
    model.setName("宁在春");
    model.setCommunityName("知乎");
    model.setHomePageUrl("https://www.zhihu.com/creator/manage/creation/all");
    model.setEmail("nza_wyh@163.com");
    model.setSpecialty("SpringBoot");
    model.setStartDate("2021-10-31 12:00:00");
    DemoModel model2 = new DemoModel();
    model2.setName("宁在春 2");
    model2.setCommunityName("知乎 2");
    model2.setHomePageUrl("2https://www.zhihu.com/creator/manage/creation/all");
    model2.setEmail("nza_wyh@163.com2");
    model2.setSpecialty("SpringBoot2");
    model2.setStartDate("2021-10-31 12:00:00");
    demoModels.add(model);
    demoModels.add(model2);
    return demoModels;
}

后果:

四、可能会产生的问题

  1. 在实体中曾经应用了 @Data 注解, 就不要再应用@Accessors(chain = true),否则会产生读取为空的景象。

    这一点我曾经亲自踩坑了(一开始排这个错都排了会😂)

  2. 在读的时候 Listener 外面须要应用 spring 的@Autowired

    Listener 创立成员变量,而后在构造方法外面传进去。必须不让 spring 治理 Listener,每次读取都要new 一个。

这两点是我认为非常常见,又比拟容易踩的坑,给大家列出来了。

具体的可点击👉 Easexcel 常见问题

五、喃喃自语

11 月更文开始,每天写写我的项目,做做记录,空虚的每一天。

纸上得来终觉浅,绝知此事要躬行。

大家好,我是博主 宁在春:主页

一名喜爱文艺却踏上编程这条路线的小青年。

心愿:咱们,待别日相见时,都已有所成

一个可恶的猫咪小表情,切实太可恶了,没方法抵御住引诱啊。

退出移动版