SpringBoot integrates POI to implement Excel file reading and writing operations

1.Environment preparation


1. Import sql script:

create database if not exists springboot default charset utf8mb4;

use springboot;

create table if not exists `user`
(
    `id`       bigint(20) primary key auto_increment comment '主键id',
    `username` varchar(255)   not null comment '用户名',
    `sex`      char(1)        not null comment '性别',
    `phone`    varchar(22)    not null comment '手机号',
    `city`     varchar(255)   not null comment '所在城市',
    `position` varchar(255)   not null comment '职位',
    `salary`   decimal(18, 2) not null comment '工资:长度18位,保留2位小数'
) engine InnoDB comment '用户表';

INSERT INTO `user` (`username`, `sex`, `phone`, `city`, `position`, `salary`) VALUES
('张三', '男', '13912345678', '北京', '软件工程师', 10000.00),
('李四', '女', '13723456789', '上海', '数据分析师', 12000.00),
('王五', '男', '15034567890', '广州', '产品经理', 15000.00),
('赵六', '女', '15145678901', '深圳', '前端工程师', 11000.00),
('刘七', '男', '15856789012', '成都', '测试工程师', 9000.00),
('陈八', '女', '13967890123', '重庆', 'UI设计师', 8000.00),
('朱九', '男', '13778901234', '武汉', '运维工程师', 10000.00),
('杨十', '女', '15089012345', '南京', '数据工程师', 13000.00),
('孙十一', '男', '15190123456', '杭州', '后端工程师', 12000.00),
('周十二', '女', '15801234567', '天津', '产品设计师', 11000.00);

image-20231001224214707

2. Create a springboot project (springboot version is 2.7.13)

3. Introduce dependencies:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-test</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.13</version>
    </dependency>
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.2</version>
    </dependency>
</dependencies>

4. Modify yml configuration:

server:
  port: 8001

# 数据库配置
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2b8&allowPublicKeyRetrieval=true
    username: root
    password: 123456

# mybatisplus配置
mybatis-plus:
  mmapper-locations: classpath:mapper/*.xml #mapper文件存放路径
  type-aliases-package: cn.z3inc.exceldemo.entity # 类型别名(实体类所在包)
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl  #配置标准sql输出

5. Use the MyBatisPlus plug-in to generate basic code:

image-20231001224944713

① Configure database:

image-20231001224418894

image-20231001224520414

② Use the code generator to generate code:

image-20231001224612743

image-20231001225559406

image-20231002165231209


2. THEN


Two ways of Excel reports:

In enterprise-level application development, Excel reports are a common reporting requirement. Excel report development is generally divided into two forms:

  • Import data from Excel into the system; (upload)

  • Generate Excel reports through Java code. (download)


Excel version:

Currently, Excel in the world is divided into two major versions: Excel2003 and Excel2007 and above;

Excel2003 is a unique binary format, its core structure is a compound document type structure, and the amount of data stored is small; the core structure of Excel2007 is an XML type structure, using an XML-based compression method to make it occupy less space , the operation efficiency is higher.

Excel 2003 Excel 2007
suffix xls xlsx
structure A binary format whose core structure is that of a compound document type XML type structure
Amount of data in a single sheet (sheet, worksheet) The table has a total of 65536 rows and 256 columns. The table has a total of 1,048,576 rows and 16,384 columns.
Features Limited storage capacity Based on xml compression, it takes up little space and has high operation efficiency.

Apache POI:

Apache POI (full name: Poor Obfuscation Implementation) is an open source project of the Apache Software Foundation. It provides a set of APIs that allow Java programs to read and write files in Microsoft Office format, including word, excel, ppt, etc.

Apache POI is currently the most popular API component for operating Microsoft Office. With POI, you can improve work efficiency, such as data report generation, data batch upload, data backup, etc.

Official website address: https://poi.apache.org/

POI's API for Excel is as follows:

  • Workbook: Workbook, Excel document object, divided into: HSSFWorkbook (2003) and XSSFWorkbook (2007) for different Excel types;
  • Sheet: Excel worksheet (table);
  • Row: Excel row;
  • Cell: Excel grid, cell.

Commonly used excel reporting tools in Java include: POI, easyexcel, easypoi, etc.


POI Quick Start:

Introduce POI dependencies:

<!--excel  POI依赖-->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>4.0.1</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>4.0.1</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml-schemas</artifactId>
    <version>4.0.1</version>
</dependency>

Example 1: Batch write operations (memory exception problems may occur when the amount of data is large)

Steps to write to excel file:

  • Create a workbook: workbook
  • Create a worksheet: sheet
  • Create row: row
  • Create column (cell): cell
  • Write specific data
package cn.z3inc.exceldemo.controller;


import cn.z3inc.exceldemo.entity.User;
import cn.z3inc.exceldemo.service.IUserService;
import lombok.RequiredArgsConstructor;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

/**
 * <p>
 * 用户表 前端控制器
 * </p>
 *
 * @author 白豆五
 * @since 2023-10-01
 */
@CrossOrigin
@RestController
@RequiredArgsConstructor
@RequestMapping("/user")
public class UserController {
    
    

    private final IUserService userService;

    /**
     * 导出excel
     */
    @RequestMapping("/export")
    public void exportExcel(HttpServletResponse response) throws IOException {
    
    
        // 1. 创建excel工作簿(workbook):excel2003使用HSSF,excel2007使用XSSF,excel2010使用SXSSF(大数据量)
        XSSFWorkbook workbook = new XSSFWorkbook();

        // 2. 创建excel工作表(sheet)
        Sheet sheet = workbook.createSheet("用户表");

        // 3. 在表中创建标题行(row): 表头
        Row titleRow = sheet.createRow(0); // 通过索引表示行,0表示第一行

        // 4. 在标题行中创建7个单元格 且 为每个单元格设置内容数据
        String[] titleArr = {
    
    "用户ID", "姓名", "性别", "电话", "所在城市", "职位", "薪资"};
        for (int i = 0; i < titleArr.length; i++) {
    
    
            Cell cell = titleRow.createCell(i); //设置单元格的位置,从0开始
            cell.setCellValue(titleArr[i]); // 为单元格填充数据
        }

        // 5. 查询所有用户数据
        List<User> userList = userService.list();

        // 6. 遍历用户list,获取每个用户,并填充每一行单元格的数据
        for (int i = 0; i < userList.size(); i++) {
    
    
            User user = userList.get(i);
            // 创建excel的行
            Row row = sheet.createRow(i+1); // 从第二行开始,索引为1
            // 为每个单元格填充数据
            row.createCell(0).setCellValue(user.getId());
            row.createCell(1).setCellValue(user.getUsername());
            row.createCell(2).setCellValue(user.getSex());
            row.createCell(3).setCellValue(user.getPhone());
            row.createCell(4).setCellValue(user.getCity());
            row.createCell(5).setCellValue(user.getPosition());
            row.createCell(6).setCellValue(user.getSalary().doubleValue());
        }

        // 7. 输出文件
        // 7.1 把excel文件写到磁盘上
        FileOutputStream outputStream = new FileOutputStream("d:/1.xlsx");
        workbook.write(outputStream); // 把excel写到输出流中
        outputStream.close(); // 关闭流

        // 7.2 把excel文件输出到浏览器上
        // 设置响应头信息
        response.setContentType("application/vnd.ms-excel");
        response.setHeader("Content-Disposition", "attachment; filename=1.xlsx");

        ServletOutputStream servletOutputStream = response.getOutputStream();
        workbook.write(servletOutputStream);
        servletOutputStream.flush(); // 刷新缓冲区
        servletOutputStream.close(); // 关闭流
        workbook.close();
    }
}

image-20231004224921153


Example 2: Large number of write operations

/**
 * 大数据量批量导出excel:SXSSF(同样兼容XSSF)
 * 官方提供了SXSSF来解决大文件写入问题,它可以写入非常大量的数据,比如上百万条数据,并且写入速度更快,占用内存更少
 * SXSSF在写入数据时会将数据分批写入硬盘(会产生临时文件),而不是一次性将所有数据写入硬盘。
 * SXSSF通过滑动窗口限制内存读取的行数(默认100行,超过100行就会写入磁盘),而XSSF将文档中所有行加载到内存中。那些不在滑动窗口中的数据是不能访问的,因为它们已经被写到磁盘上了。这样可以节省大量内存空间 。
 */
@RequestMapping("/export2")
public void exportExcel2(HttpServletResponse response) throws IOException {
    
    

    long star = System.currentTimeMillis();

    // 1. 创建excel工作簿(workbook):SXSSFWorkbook
    SXSSFWorkbook workbook = new SXSSFWorkbook();//默认窗口大小为100

    // 2. 创建excel工作表(sheet)
    Sheet sheet = workbook.createSheet("用户表");

    // 3. 在表中创建标题行(row): 表头
    Row titleRow = sheet.createRow(0); // 通过索引表示行,0表示第一行

    // 4. 在标题行中创建7个单元格 且 为每个单元格设置内容数据
    String[] titleArr = {
    
    "用户ID", "姓名", "性别", "电话", "所在城市", "职位", "薪资"};
    for (int i = 0; i < titleArr.length; i++) {
    
    
        Cell cell = titleRow.createCell(i); //设置单元格的位置,从0开始
        cell.setCellValue(titleArr[i]); // 为单元格填充数据
    }

    // 5. 查询所有用户数据
    List<User> userList = userService.list();

    // 6. 遍历用户list,获取每个用户,并填充每一行单元格的数据
    for (int i = 0; i < 65536; i++) {
    
    
        User user;
        if (i > userList.size() - 1) {
    
    
            user = userList.get(userList.size() - 1);
        } else {
    
    
            user = userList.get(i);
        }

        // 创建excel的行
        Row row = sheet.createRow(i + 1); // 从第二行开始,索引为1
        // 为每个单元格填充数据
        row.createCell(0).setCellValue(user.getId());
        row.createCell(1).setCellValue(user.getUsername());
        row.createCell(2).setCellValue(user.getSex());
        row.createCell(3).setCellValue(user.getPhone());
        row.createCell(4).setCellValue(user.getCity());
        row.createCell(5).setCellValue(user.getPosition());
        row.createCell(6).setCellValue(user.getPosition());
    }

    // 7. 输出文件
    // 7.1 把excel文件写到磁盘上
    FileOutputStream outputStream = new FileOutputStream("d:/2.xlsx");
    workbook.write(outputStream); // 把excel写到输出流中
    outputStream.close(); // 关闭流
    workbook.close();
    long end = System.currentTimeMillis();
    log.info("大数据量批量数据写入用时: {} ms", end - star);
}

After testing, XSSF outputs an excel file in about ten seconds, while SXSSF outputs an excel file in about one second.


Example: read excel file

Steps to read excel file: (read through file stream)

  • Get workbook
  • Get sheet
  • Get row
  • Get cell
  • Read data
// 读取excel文件
@RequestMapping("/upload")
public void readExcel(MultipartFile file) {
    
    
    InputStream is = null;
    XSSFWorkbook workbook = null;
    try {
    
    
        // 1. 创建excel工作簿(workbook)
        is = file.getInputStream();
        workbook = new XSSFWorkbook(is);

        // 2. 获取要解析的工作表(sheet)
        Sheet sheet = workbook.getSheetAt(0); // 获取第一个sheet

        // 3. 获取表格中的每一行,排除表头,从第二行开始
        User user;
        List<User> list = new ArrayList<>();
        for (int i = 1; i <= sheet.getLastRowNum(); i++) {
    
    
            Row row = sheet.getRow(i); // 获取第i行

            // 4. 获取每一行的每一列,并为user对象的属性赋值,添加到list集合中
            user = new User();
            user.setUsername(row.getCell(1).getStringCellValue());
            user.setSex(row.getCell(2).getStringCellValue());
            user.setPhone(row.getCell(3).getStringCellValue());
            user.setCity(row.getCell(4).getStringCellValue());
            user.setPosition(row.getCell(5).getStringCellValue());
            user.setSalary(new BigDecimal(row.getCell(6).getNumericCellValue()));
            list.add(user);
        }

        // 5. 批量保存
        userService.saveBatch(list);
    } catch (IOException e) {
    
    
        e.printStackTrace();
        throw new RuntimeException("批量导入失败");
    } finally {
    
    
        try {
    
    
            if (is != null) {
    
    
                is.close();
            }
            if (workbook != null) {
    
    
                workbook.close();
            }
        } catch (IOException e) {
    
    
            e.printStackTrace();
            throw new RuntimeException("批量导入失败");
        }
    }
}

image-20231007062047348

image-20231007062527489

image-20231007062019296


3. EasyExcel


EasyExcel is a Java-based, fast and concise Excel processing tool that solves memory overflow of large files. It allows you to quickly complete Excel's reading, writing and other functions without considering performance, memory and other factors.

Official website address: https://easyexcel.opensource.alibaba.com/

Document address: https://easyexcel.opensource.alibaba.com/docs/current/

Sample code: https://github.com/alibaba/easyexcel/tree/master/easyexcel-test/src/test/java/com/alibaba/easyexcel/test/demo

pom dependencies:

<!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>3.2.1</version>
</dependency>

Finally, EasyExcel’s official documentation is very comprehensive, so I won’t go into details one by one.

Guess you like

Origin blog.csdn.net/qq_46921028/article/details/133631309