Springboot 基于EasyExcel导入导出excel的实例

1. EasyExcel简介

Java解析,生成Excel比较有名的框架有Apache POI,jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版本Excel解压缩以及解压后存储都是在内存中完成的,内存消耗很大。easyexcel重写了poi对07版本excel的解析,一个3M的excel用poi sax解析需要100M左右的内存,改用easyexcel可以降低到几M,并且再大的excel也不会出现内存溢出,03版本依赖POI的sax模式,再上层坐了模型转换的封装,让使用者更加简单方便。

2. EasyExcel常用注解

2.1 @ExcelProperty

用于Excel和实体类直接的匹配

名称默认值描述
value用于匹配excel中的头,必须全匹配,如果有多行头,会匹配最后一行头
orderInteger.MAX_VALUE优先级高于value,会根据order的顺序来匹配实体和excel中数据的顺序
index-1优先级高于valueorder,会根据index直接指定到excel中具体的哪一列
converter自动选择指定当前字段用什么转换器,默认会自动选择。读的情况下只要实现com.alibaba.excel.converters.Converter#convertToJavaData(com.alibaba.excel.converters.ReadConverterContext<?>) 方法即可

2.2 @ExcelIgnore 

默认所有字段都会和excel去匹配,家里这个注解会忽略该字段。

2.3 @ExcelIgnoreUnannotated

默认不加@ExcelProperty的注解的都会参与读写,加了不会参与读写

2.4 @DateTimeFormat

日期转换,用String去接收Excel日期格式的数据会调用这个注解。

名称默认值描述
value参照java.text.SimpleDateFormat书写即可
use1904windowing自动选择excel中时间是存储1900年起的一个双精度浮点数,但是有时候默认开始日期是1904,所以设置这个值改成默认1904年开始

2.5 NumberFormat

数字转换,用String去接收Excel数字格式的数据会调用这个注解。

名称默认值描述
value参照java.text.DecimalFormat书写即可
roundingModeRoundingMode.HALF_UP格式化的时候设置舍入模式

3. 引入EasyExcel的依赖

<dependency>     

  <groupId>com.alibaba</groupId>    

  <artifactId>easyexcel</artifactId>    

  <version>3.1.1</version>

</dependency>

4. 实现导入导出的处理

  • 导入导出对象的实体类
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
// 类上加注解 @ExcelIgnoreUnannotated,过滤属性没有@ExcelProperty注解的字段
@ExcelIgnoreUnannotated
public class User {
​
    /**
     * user id.
     */
    @ExcelProperty("ID")
    private Long id;
​
    /**
     * 姓名.
     */
    @ExcelProperty("姓名")
    private String userName;
​
    /**
     * 性别.
     */
    @ExcelProperty("性别")
    private String gender;
​
    /**
     * 地址.
     */
    @ExcelProperty("地址")
    private String address;
​
    /**
     * 邮箱.
     */
    @ExcelProperty("邮箱")
    private String email;
​
    /**
     * 手机号码.
     */
    @ExcelProperty("手机号码")
    private Long phoneNumber;
​
    /**
     * 描述.
     */
    @ExcelIgnore
    @ExcelProperty("描述")
    private String description;
}
  •  导入导出的Controller
@GetMapping("/export")
public void exportUserInfo(HttpServletResponse response) {
    try {
        response.reset();
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
        String fileName = "导出用户信息列表";
        // 注意:这里要加上filename*=utf-8'zh_cn'否则可能会导致导出文件名乱码
        response.setHeader("Content-disposition",
                           "attachment;filename*=utf-8'zh_cn'" + fileName + System.currentTimeMillis() + ".xlsx");
        userService.exportUserInfo(response.getOutputStream());
    } catch (IOException e) {
        e.printStackTrace();
    }
}
​
@PostMapping("/import")
public void importUserInfo(@RequestParam(value = "file") MultipartFile file) {
    try {
        userService.importUserInfo(file.getInputStream());
    } catch (IOException e) {
        e.printStackTrace();
    }
}
  •  导入导出的Service
public interface UserService {
​
    /**
     * 导出文件
     *
     * @param outputStream
     */
    void exportUserInfo(ServletOutputStream outputStream);
​
    /**
     * 导入文件
     *
     * @param inputStream
     */
    void importUserInfo(InputStream inputStream);
}
  •  导入导出的业务逻辑代码
@Slf4j
@Service
public class UserServiceImpl implements UserService {
​
   @Override
    public void exportUserInfo(ServletOutputStream outputStream) {
        // 第一种方式
        ExcelWriter excelWriter = EasyExcelFactory.write(outputStream).build();
        WriteSheet userSheet = EasyExcelFactory.writerSheet(0)
                .head(User.class)
                // 导出文件需不包含的列名
                .excludeColumnFieldNames(Lists.newArrayList())
                // 导出文件包含的列名
                .includeColumnFieldNames(Lists.newArrayList())
                .build();
        excelWriter.write(this::getUserList, userSheet);
        excelWriter.finish();
        // 第二种方式
        EasyExcelFactory.write(outputStream, User.class).sheet("userInfo").doWrite(this::getUserList);
    }
​
    private List<User> getUserList() {
        return Collections.singletonList(User.builder()
                .id(1L).userName("itender").gender("男").address("广东深圳").email("itender@163.com")
                .phoneNumber(13156777777L).description("hello world")
                .build());
    }
​
    @Override
    public void importUserInfo(InputStream inputStream) {
        // 第一种方式
        ExcelDataListener excelDataListener = new ExcelDataListener();
        ExcelReader excelReader = EasyExcelFactory.read(inputStream).build();
        ReadSheet userSheet = EasyExcelFactory.readSheet(0)
                .head(User.class)
                .registerReadListener(excelDataListener)
                .build();
        excelReader.read(userSheet);
        // 第二种方式
        EasyExcelFactory.read(inputStream, User.class, new ReadListener<User>() {
            /**
             * 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收
             */
            private static final int BATCH_COUNT = 100;
            /**
             * 缓存的数据
             */
            private final List<User> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
​
            @Override
            public void invoke(User user, AnalysisContext analysisContext) {
                cachedDataList.add(user);
            }
            @Override
            public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                cachedDataList.forEach(user -> log.info(user.toString()));
            }
        }).sheet().doRead();
        // 拿到错误信息,返回前端
        String errorMsg = excelDataListener.getErrorMsg();
    }
}
  •  监听器
@Slf4j
public class ExcelDataListener implements ReadListener<User> {
​
    /**
     * 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收
     */
    private static final int BATCH_COUNT = 100;
    /**
     * 缓存的数据
     */
    private static final List<User> CACHED_DATA_LIST = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
​
    /**
     * 错误信息
     */
    @Getter
    private String errorMsg;
​
    /**
     * 这个每一条数据解析都会来调用
     *
     * @param user
     * @param analysisContext
     */
    @Override
    public void invoke(User user, AnalysisContext analysisContext) {
        log.info("解析到一条数据:{}", JSONUtil.toJsonStr(user));
        // TODO 校验导入数据是否合规
        // 如果不合规
        this.errorMsg = StrFormatter.format("导入数据第{}行校验不通过!", analysisContext.readRowHolder().getRowIndex());
        CACHED_DATA_LIST.add(user);
        // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
        if (CACHED_DATA_LIST.size() >= BATCH_COUNT) {
            // TODO 保存数据到MySQL
​
            // 存储完成置空list
            CACHED_DATA_LIST.clear();
        }
    }
​
    /**
     * 所有数据解析完成了 都会来调用
     *
     * @param analysisContext
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        // 这里也要保存数据,确保最后遗留的数据也存储到数据库
        // TODO 保存数据到MySQL
        log.info("所有数据解析完成!");
    }
}

 问题:

  • 在很多场景下,Excel的列与实体类可能并不完全一致,这时就需要排除一些实体类的字段。

    方式一:类上加注解 @ExcelIgnoreUnannotated,过滤属性没有@ExcelProperty注解的字段

    方式二:指定字段加@ExcelIgnore注解

    方式三:代码指定过滤字段,通过excludeColumnFiledNames方法:

  • 防止导出文件名乱码:

    response.setHeader("Content-disposition", "attachment;filename*=utf-8'zh_cn'" + fileName + System.currentTimeMillis() + ".xlsx");

  • 可以自定义Listener监听器实现导入数据校验,避免一次性导入太多数据,最好数据分批入库。

### 回答1: Spring Boot 是一个用于创建基于 Spring 框架的独立、生产级别的应用程序的框架。EasyExcel 是一个基于 Java 的开源框架,可以方便地读写 Excel 文件。使用 EasyExcel 可以轻松地进行 Excel 文件的导入导出,非常适合在 Spring Boot 项目中使用。 下面是在 Spring Boot 项目中使用 EasyExcel 进行 Excel 文件导入导出的基本步骤: 1. 添加 EasyExcel 依赖 在项目的 pom.xml 文件中添加 EasyExcel 依赖: ```xml <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.2.10</version> </dependency> ``` 2. 编写 Excel 导出代码 使用 EasyExcel 可以非常方便地进行 Excel 文件的导出。例如,以下代码可以将一个 List 对象导出Excel 文件: ```java // 定义 Excel 表头 List<List<String>> head = new ArrayList<>(); head.add(Arrays.asList("姓名", "年龄")); // 定义 Excel 数据 List<List<Object>> data = new ArrayList<>(); data.add(Arrays.asList("张三", 18)); data.add(Arrays.asList("李四", 20)); data.add(Arrays.asList("王五", 22)); // 导出 Excel 文件 String fileName = "example.xlsx"; String sheetName = "Sheet1"; EasyExcel.write(fileName).sheet(sheetName).head(head).sheet().doWrite(data); ``` 3. 编写 Excel 导入代码 使用 EasyExcel 进行 Excel 文件的导入也非常方便。例如,以下代码可以从 Excel 文件中读取数据并转换为一个 List 对象: ```java // 定义读取 Excel 文件的监听器 public class ExcelListener extends AnalysisEventListener<Object> { private List<Object> data = new ArrayList<>(); @Override public void invoke(Object object, AnalysisContext context) { data.add(object); } @Override public void doAfterAllAnalysed(AnalysisContext context) {} public List<Object> getData() { return data; } } // 读取 Excel 文件 String fileName = "example.xlsx"; ExcelListener listener = new ExcelListener(); EasyExcel.read(fileName, listener).sheet().doRead(); List<Object> data = listener.getData(); ``` 4. 将 Excel 文件导入到数据库 读取 Excel 文件之后,可以将数据存入数据库中。以下代码演示了将读取的 Excel 文件中的数据存入 MySQL 数据库的过程: ```java // 定义实体类 @Data public class Person { private String name; private Integer age; } // 保存数据到数据库 List<Person> persons = new ArrayList<>(); for (Object obj : data) { List<Object> row = (List<Object>) obj; Person person = new Person(); person.setName((String) row.get(0)); person.setAge((Integer) row.get(1)); persons.add(person); } personRepository.saveAll(persons); ``` 以上就是使用 EasyExcel 进行 Excel 文件导入导出的基本步骤。根据实际需求,可以对以上代码进行相应的修改和扩展。 ### 回答2: Spring Boot 是一个开源的Java开发框架,可以帮助开发人员快速构建基于Spring的应用程序。EasyExcel 是一种基于Java的Excel读写工具,它提供了简单便捷的API,可以方便地实现Excel导入导出功能。 在Spring Boot中使用EasyExcel进行导入导出操作非常简单。首先,我们需要在pom.xml文件中添加EasyExcel的依赖项,以便可以使用它的功能。然后,我们可以创建一个Controller类来处理导入导出的请求。 对于导入操作,我们可以使用EasyExcel提供的@ExcelProperty注解来标记实体类的字段与Excel的列的映射关系。然后,我们可以使用EasyExcel的read方法来读取Excel文件,并将数据转换为实体类对象。最后,我们可以对读取到的数据进行相应的业务操作,比如存储到数据库中。 对于导出操作,我们可以使用EasyExcel的@ExcelProperty注解标记实体类的字段,并使用EasyExcel的write方法来将实体类列表写入Excel文件。我们可以通过指定文件路径或输出流的方式进行导出。 除了基本的导入导出功能,EasyExcel还提供了一些高级特性,比如读取大文件、多sheet处理、自定义读写处理器等。这些特性可以帮助我们更好地应对复杂的Excel导入导出需求。 总而言之,Spring Boot结合EasyExcel提供了一种简单快捷的方式来实现Excel导入导出功能。无论是处理简单的Excel文件还是应对复杂的导入导出需求,Spring Boot和EasyExcel都能够提供强大的支持。 ### 回答3: Spring Boot 是一种简化了开发过程的Java框架,而EasyExcel是一种用于操作Excel文件的开源库。通过结合使用Spring Boot和EasyExcel,我们可以方便地实现Excel文件的导入导出功能。下面将详细介绍如何使用Spring Boot和EasyExcel来实现导入导出功能。 首先,我们需要在Spring Boot的项目中引入EasyExcel的依赖。在pom.xml文件中添加以下依赖: ``` <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.2.6</version> </dependency> ``` 接着,我们可以创建一个Controller类来处理导入导出的请求。在该类中,我们可以定义两个方法,一个用于导入Excel文件,另一个用于导出Excel文件。 对于导入功能,我们可以使用EasyExcel提供的`read()`方法来读取Excel文件,并将读取到的数据转换为一个List对象。以下是一个简单的导入方法的示例代码: ```java @PostMapping("/import") public void importExcel(@RequestParam("file") MultipartFile file) throws IOException { List<DataDTO> dataList = EasyExcel.read(file.getInputStream()).head(DataDTO.class).sheet().doReadSync(); // 处理导入的数据 } ``` 对于导出功能,我们可以使用EasyExcel提供的`write()`方法来创建一个Excel文件,并将数据写入到该文件中。以下是一个简单的导出方法的示例代码: ```java @GetMapping("/export") public void exportExcel(HttpServletResponse response) throws IOException { List<DataDTO> dataList = getDataList(); // 获取导出的数据 response.setContentType("application/vnd.ms-excel"); response.setCharacterEncoding("utf-8"); response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("data.xlsx", "utf-8")); EasyExcel.write(response.getOutputStream()).sheet("Data").doWrite(dataList); } ``` 在上述代码中,我们首先获取需要导出的数据(getDataList()方法需要根据实际情况实现),然后设置响应头信息,最后使用`write()`方法将数据写入到响应的输出流中。 通过以上步骤,我们在Spring Boot项目中成功实现了使用EasyExcel进行Excel文件的导入导出功能。我们可以根据具体需求对导入的数据进行处理,也可以根据实际情况设置导出文件的格式和名称。同时,EasyExcel还提供了更多的功能和选项,如设置表头、导入数据校验等,可以根据具体需求进行使用。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

钟小猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值