SoFunction
Updated on 2025-04-21

Share the complete guide to Excel processing in SpringBoot

Excel processing guide in SpringBoot

1. Basics of Excel processing

1.1 Why do you need to process Excel files in your application?

In enterprise application development, Excel file processing is a very common requirement and is mainly used in the following scenarios:

  • Data import: Allow users to upload batch data to the system through Excel
  • Data Export: Export system data to Excel for users to download and analyze
  • Report generation: Generate complex reports and format them into Excel
  • Data exchange: As a medium for exchanging data between different systems
  • Batch data processing: Processing large amounts of structured data

1.2 Introduction to Excel processing library in Java

There are the following main libraries for processing Excel files in Java:

1.2.1 Apache POI

Apache POI is the most widely used Excel processing library in Java, providing a comprehensive API to create, read and modify Office documents.

advantage

  • Full functionality, supporting all functions of Excel
  • Supports .xls (HSSF - Excel 97-2003) and .xlsx (XSSF - Excel 2007+) formats
  • Active community and rich documentation
  • Supports advanced functions such as formula calculation, charts, and merging cells

shortcoming

  • The API is relatively complex
  • Memory consumption is high when processing large files (especially XSSF)
1.2.2 EasyExcel

EasyExcel is an open source Excel processing library from Alibaba. It is based on POI, but has done a lot of optimizations.

advantage

  • Low memory footprint, use SAX mode to read, avoid OOM
  • API is simple and easy to use, annotation driver
  • Fast reading and writing speed
  • Suitable for handling large Excel files

shortcoming

  • Not as comprehensive as POI
  • Relatively low flexibility
1.2.3 JExcel

JExcel is another Java library that handles Excel.

advantage

  • The API is simpler
  • Faster speed

shortcoming

  • Only support legacy Excel (.xls) format
  • No longer active maintenance
  • Limited functions
1.2.4 Apache POI SXSSF

SXSSF is a streaming processing mode provided by POI, designed for processing large Excel files.

advantage

  • Greatly reduce memory usage
  • Suitable for generating large Excel files

shortcoming

  • Only write operations are supported, not reads
  • Functionality is limited than XSSF

1.3 Integrated Excel processing in Spring Boot

Spring Boot itself does not provide Excel processing capabilities, but it can easily integrate various Excel processing libraries mentioned above. This guide will mainly introduce:

  1. How to integrate Apache POI and EasyExcel in Spring Boot Project
  2. How to implement common functions of Excel import and export
  3. How to deal with FAQs and optimize performance

2. Integrate Excel processing library in Spring Boot

2.1 Integration of Apache POI

2.1.1 Add dependencies

existAdd the following dependencies to the file:

<dependency>
    <groupId></groupId>
    <artifactId>poi</artifactId>
    <version>5.2.3</version>
</dependency>
<dependency>
    <groupId></groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>5.2.3</version>
</dependency>

If using Gradle,Added in:

implementation ':poi:5.2.3'
implementation ':poi-ooxml:5.2.3'
2.1.2 Create a basic configuration class

Create a configuration class to handle Excel-related configurations:

package ;

import ;
import ;
import ;
import ;
import ;

@Configuration
public class ExcelConfig {
    
    @Bean
    public MultipartResolver multipartResolver() {
        CommonsMultipartResolver resolver = new CommonsMultipartResolver();
        (10485760); // Set the maximum upload file to 10MB        return resolver;
    }
}

2.2 Integrated EasyExcel

2.2.1 Add dependencies

existAdd the following dependencies to the file:

<dependency>
    <groupId></groupId>
    <artifactId>easyexcel</artifactId>
    <version>3.2.1</version>
</dependency>

If using Gradle,Added in:

implementation ':easyexcel:3.2.1'
2.2.2 Create a configuration class
package ;

import ;
import ;
import ;
import ;

@Configuration
public class EasyExcelConfig {
    
    @Bean
    public MultipartResolver multipartResolver() {
        CommonsMultipartResolver resolver = new CommonsMultipartResolver();
        (10485760); // Set the maximum upload file to 10MB        return resolver;
    }
}

3. Read Excel files using Apache POI

3.1 Creating a Data Model

First, create a model class to map data in Excel:

package ;

import ;

@Data
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
    private String department;
}

3.2 Create an Excel read service

Create a service class to handle Excel file reading:

package ;

import ;
import .*;
import ;
import ;
import ;

import ;
import ;
import ;
import ;
import ;

@Service
public class ExcelService {

    public List&lt;User&gt; readUsersFromExcel(MultipartFile file) throws IOException {
        List&lt;User&gt; userList = new ArrayList&lt;&gt;();
        
        // Get the workbook        try (InputStream inputStream = ()) {
            Workbook workbook = (inputStream);
            
            // Get the first worksheet            Sheet sheet = (0);
            
            // Skip the title line            Iterator&lt;Row&gt; rowIterator = ();
            if (()) {
                (); // Skip the title line            }
            
            // traverse data rows            while (()) {
                Row row = ();
                User user = new User();
                
                // Read cell data                ((long) (0, .CREATE_NULL_AS_BLANK).getNumericCellValue());
                (getCellValueAsString((1)));
                ((int) (2, .CREATE_NULL_AS_BLANK).getNumericCellValue());
                (getCellValueAsString((3)));
                (getCellValueAsString((4)));
                
                (user);
            }
            
            ();
        }
        
        return userList;
    }
    
    // Get the string value of the cell    private String getCellValueAsString(Cell cell) {
        if (cell == null) {
            return "";
        }
        
        switch (()) {
            case STRING:
                return ();
            case NUMERIC:
                if ((cell)) {
                    return ().toString();
                } else {
                    return ((int) ());
                }
            case BOOLEAN:
                return (());
            case FORMULA:
                return ();
            default:
                return "";
        }
    }
}

3.3 Create Controller to handle Excel uploads

Create a Controller to handle Excel file uploads:

package ;

import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;

import ;
import ;

@RestController
@RequestMapping("/api/excel")
public class ExcelController {

    @Autowired
    private ExcelService excelService;

    @PostMapping("/upload")
    public ResponseEntity<List<User>> uploadExcel(@RequestParam("file") MultipartFile file) {
        try {
            List<User> users = (file);
            return (users);
        } catch (IOException e) {
            ();
            return ().build();
        }
    }
}

3.4 Create HTML upload page

existsrc/main/resources/templatesCreated in the directory

&lt;!DOCTYPE html&gt;
&lt;html xmlns:th=""&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;title&gt;ExcelUpload&lt;/title&gt;
    &lt;link rel="stylesheet" href="/bootstrap/4.5.2/css/" rel="external nofollow"  rel="external nofollow" &gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;div class="container mt-5"&gt;
        &lt;div class="card"&gt;
            &lt;div class="card-header"&gt;
                &lt;h3&gt;UploadExceldocument&lt;/h3&gt;
            &lt;/div&gt;
            &lt;div class="card-body"&gt;
                &lt;form  enctype="multipart/form-data"&gt;
                    &lt;div class="form-group"&gt;
                        &lt;label for="file"&gt;chooseExceldocument:&lt;/label&gt;
                        &lt;input type="file" class="form-control-file"  name="file" accept=".xls,.xlsx"&gt;
                    &lt;/div&gt;
                    &lt;button type="button" class="btn btn-primary" onclick="uploadExcel()"&gt;Upload&lt;/button&gt;
                &lt;/form&gt;
                
                &lt;div class="mt-4"&gt;
                    &lt;h4&gt;Upload结果:&lt;/h4&gt;
                    &lt;div &gt;&lt;/div&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;
    
    &lt;script src="/jquery-3.5."&gt;&lt;/script&gt;
    &lt;script&gt;
        function uploadExcel() {
            var formData = new FormData(('uploadForm'));
            
            $.ajax({
                url: '/api/excel/upload',
                type: 'POST',
                data: formData,
                processData: false,
                contentType: false,
                success: function(response) {
                    var resultHtml = '&lt;table class="table table-striped"&gt;' +
                                    '&lt;thead&gt;&lt;tr&gt;&lt;th&gt;ID&lt;/th&gt;&lt;th&gt;Name&lt;/th&gt;&lt;th&gt;age&lt;/th&gt;&lt;th&gt;Mail&lt;/th&gt;&lt;th&gt;department&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;' +
                                    '&lt;tbody&gt;';
                    
                    for (var i = 0; i &lt; ; i++) {
                        var user = response[i];
                        resultHtml += '&lt;tr&gt;' +
                                     '&lt;td&gt;' +  + '&lt;/td&gt;' +
                                     '&lt;td&gt;' +  + '&lt;/td&gt;' +
                                     '&lt;td&gt;' +  + '&lt;/td&gt;' +
                                     '&lt;td&gt;' +  + '&lt;/td&gt;' +
                                     '&lt;td&gt;' +  + '&lt;/td&gt;' +
                                     '&lt;/tr&gt;';
                    }
                    
                    resultHtml += '&lt;/tbody&gt;&lt;/table&gt;';
                    
                    $('#resultContainer').html(resultHtml);
                },
                error: function(error) {
                    $('#resultContainer').html('<div class="alert alert-danger">Upload failed: ' + + '</div>');                }
            });
        }
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;

3.5 Handling more complex Excel structures

In practical applications, Excel structure may be more complex, such as multiple worksheets, merging cells, formulas, etc. Here are examples of handling these situations:

public List&lt;Department&gt; readComplexExcel(MultipartFile file) throws IOException {
    List&lt;Department&gt; departments = new ArrayList&lt;&gt;();
    
    try (InputStream inputStream = ()) {
        Workbook workbook = (inputStream);
        
        // Read department information (first worksheet)        Sheet departmentSheet = (0);
        for (int i = 1; i &lt;= (); i++) {
            Row row = (i);
            if (row == null) continue;
            
            Department department = new Department();
            ((long) (0).getNumericCellValue());
            ((1).getStringCellValue());
            ((2).getStringCellValue());
            (new ArrayList&lt;&gt;());
            
            (department);
        }
        
        // Read employee information (second worksheet)        Sheet employeeSheet = (1);
        for (int i = 1; i &lt;= (); i++) {
            Row row = (i);
            if (row == null) continue;
            
            User employee = new User();
            ((long) (0).getNumericCellValue());
            ((1).getStringCellValue());
            ((int) (2).getNumericCellValue());
            ((3).getStringCellValue());
            
            // Obtain the department ID and associate it with the corresponding department            long departmentId = (long) (4).getNumericCellValue();
            for (Department dept : departments) {
                if (() == departmentId) {
                    ().add(employee);
                    break;
                }
            }
        }
        
        ();
    }
    
    return departments;
}

4. Create and export Excel files using Apache POI

4.1 Create a basic Excel file

Here is an example of creating a simple Excel file:

package ;

import ;
import .*;
import ;
import ;

import ;
import ;
import ;
import ;

@Service
public class ExcelExportService {

    public ByteArrayInputStream exportUsersToExcel(List&lt;User&gt; users) throws IOException {
        try (Workbook workbook = new XSSFWorkbook()) {
            // Create worksheets            Sheet sheet = ("User Data");
            
            // Create a header style            Font headerFont = ();
            (true);
            (());
            
            CellStyle headerCellStyle = ();
            (headerFont);
            (IndexedColors.LIGHT_YELLOW.getIndex());
            (FillPatternType.SOLID_FOREGROUND);
            ();
            ();
            ();
            ();
            
            // Create a header row            Row headerRow = (0);
            
            // Create a header cell            Cell cell0 = (0);
            ("ID");
            (headerCellStyle);
            
            Cell cell1 = (1);
            ("Name");
            (headerCellStyle);
            
            Cell cell2 = (2);
            ("age");
            (headerCellStyle);
            
            Cell cell3 = (3);
            ("Mail");
            (headerCellStyle);
            
            Cell cell4 = (4);
            ("department");
            (headerCellStyle);
            
            // Set the data cell style            CellStyle dataCellStyle = ();
            ();
            ();
            ();
            ();
            
            // Create data rows            int rowIdx = 1;
            for (User user : users) {
                Row row = (rowIdx++);
                
                Cell idCell = (0);
                (());
                (dataCellStyle);
                
                Cell nameCell = (1);
                (());
                (dataCellStyle);
                
                Cell ageCell = (2);
                (());
                (dataCellStyle);
                
                Cell emailCell = (3);
                (());
                (dataCellStyle);
                
                Cell deptCell = (4);
                (());
                (dataCellStyle);
            }
            
            // Automatically adjust column width            for (int i = 0; i &lt; 5; i++) {
                (i);
            }
            
            // Write to ByteArrayOutputStream            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            (outputStream);
            
            return new ByteArrayInputStream(());
        }
    }
}

4.2 Create an export controller

package ;

import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;

import ;
import ;
import ;
import ;

@RestController
@RequestMapping("/api/excel")
public class ExcelExportController {

    @Autowired
    private ExcelExportService excelExportService;

    @GetMapping("/export")
    public ResponseEntity&lt;InputStreamResource&gt; exportUsers() throws IOException {
        // Generate sample data        List&lt;User&gt; users = getTestUsers();
        
        // Generate Excel file        ByteArrayInputStream in = (users);
        
        // Set HTTP header        HttpHeaders headers = new HttpHeaders();
        ("Content-Disposition", "attachment; filename=");
        
        // Return to Excel file        return ResponseEntity
                .ok()
                .headers(headers)
                .contentType(("application/-excel"))
                .body(new InputStreamResource(in));
    }
    
    // Generate test user data    private List&lt;User&gt; getTestUsers() {
        List&lt;User&gt; users = new ArrayList&lt;&gt;();
        
        User user1 = new User();
        (1L);
        ("Zhang San");
        (28);
        ("zhangsan@");
        ("R&D Department");
        (user1);
        
        User user2 = new User();
        (2L);
        ("Li Si");
        (32);
        ("lisi@");
        ("Market Department");
        (user2);
        
        User user3 = new User();
        (3L);
        ("Wang Wu");
        (45);
        ("wangwu@");
        ("Ministry of Administration");
        (user3);
        
        User user4 = new User();
        (4L);
        ("Zhao Liu");
        (36);
        ("zhaoliu@");
        ("Treasury Department");
        (user4);
        
        User user5 = new User();
        (5L);
        ("Qian Qi");
        (29);
        ("qianqi@");
        ("Human Resources Department");
        (user5);
        
        return users;
    }
}

4.3 Create an export page

existsrc/main/resources/templatesCreated in the directory

&lt;!DOCTYPE html&gt;
&lt;html xmlns:th=""&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;title&gt;ExcelExport&lt;/title&gt;
    &lt;link rel="stylesheet" href="/bootstrap/4.5.2/css/" rel="external nofollow"  rel="external nofollow" &gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;div class="container mt-5"&gt;
        &lt;div class="card"&gt;
            &lt;div class="card-header"&gt;
                &lt;h3&gt;ExportExceldocument&lt;/h3&gt;
            &lt;/div&gt;
            &lt;div class="card-body"&gt;
                &lt;p&gt;点击下面的按钮Export用户数据到Exceldocument:&lt;/p&gt;
                &lt;a href="/api/excel/export" rel="external nofollow"  class="btn btn-primary"&gt;Export用户数据&lt;/a&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;

4.4 Creating complex Excel files

Here is an example of creating a more complex Excel file, including multiple worksheets, merged cells, formulas, and more:

public ByteArrayInputStream exportComplexExcel(List&lt;Department&gt; departments) throws IOException {
    try (Workbook workbook = new XSSFWorkbook()) {
        // Create fonts and styles        Font headerFont = ();
        (true);
        ((short) 14);
        
        CellStyle headerStyle = ();
        (headerFont);
        (IndexedColors.LIGHT_BLUE.getIndex());
        (FillPatternType.SOLID_FOREGROUND);
        ();
        
        CellStyle titleStyle = ();
        Font titleFont = ();
        (true);
        ((short) 16);
        (titleFont);
        ();
        
        // Create a summary table        Sheet summarySheet = ("Department Summary");
        
        // Create a title line        Row titleRow = (0);
        Cell titleCell = (0);
        ("Company Department Personnel Statistics");
        (titleStyle);
        
        // Merge the title cells        (new CellRangeAddress(0, 0, 0, 3));
        
        // Create a header        Row headerRow = (1);
        String[] headers = {"Department ID", "Department Name", "Department Manager", "Number of employees"};
        
        for (int i = 0; i &lt; ; i++) {
            Cell cell = (i);
            (headers[i]);
            (headerStyle);
        }
        
        // Fill in department data        int rowIdx = 2;
        int totalEmployees = 0;
        
        for (Department dept : departments) {
            Row row = (rowIdx++);
            
            (0).setCellValue(());
            (1).setCellValue(());
            (2).setCellValue(());
            (3).setCellValue(().size());
            
            totalEmployees += ().size();
            
            // Create separate worksheets for each department            Sheet deptSheet = (());
            
            // Create department header            Row deptHeaderRow = (0);
            Cell deptTitleCell = (0);
            (() + " - Employee List");
            (titleStyle);
            (new CellRangeAddress(0, 0, 0, 4));
            
            // Employee table            Row empHeaderRow = (1);
            String[] empHeaders = {"Employee ID", "Name", "age", "Mail", "Enterprise Year"};
            
            for (int i = 0; i &lt; ; i++) {
                Cell cell = (i);
                (empHeaders[i]);
                (headerStyle);
            }
            
            // Fill in employee data            int empRowIdx = 2;
            for (User emp : ()) {
                Row empRow = (empRowIdx++);
                
                (0).setCellValue(());
                (1).setCellValue(());
                (2).setCellValue(());
                (3).setCellValue(());
                
                // Use the formula to calculate the term of employment (assuming age minus 25)                Cell tenureCell = (4);
                ("C" + empRowIdx + "-25");
            }
            
            // Automatically adjust column width            for (int i = 0; i &lt; 5; i++) {
                (i);
            }
        }
        
        // Create a total row        Row totalRow = (rowIdx);
        Cell totalLabelCell = (0);
        ("total");
        (headerStyle);
        
        // Merge total label cells        (new CellRangeAddress(rowIdx, rowIdx, 0, 2));
        
        Cell totalValueCell = (3);
        (totalEmployees);
        (headerStyle);
        
        // Automatically adjust column width        for (int i = 0; i &lt; 4; i++) {
            (i);
        }
        
        // Add a chart        XSSFSheet chartSheet = (XSSFSheet) ("Department Statistical Chart");
        
        // Copy department data to chart data table        Row chartHeaderRow = (0);
        (0).setCellValue("department");
        (1).setCellValue("Number of Employees");
        
        int chartRowIdx = 1;
        for (Department dept : departments) {
            Row row = (chartRowIdx++);
            (0).setCellValue(());
            (1).setCellValue(().size());
        }
        
        // Create charts and data sequences        XSSFDrawing drawing = ();
        XSSFClientAnchor anchor = (0, 0, 0, 0, 4, 0, 15, 15);
        
        XSSFChart chart = (anchor);
        ("Department personnel distribution");
        (false);
        
        XDDFChartLegend legend = ();
        ();
        
        // X-axis and Y-axis        XDDFCategoryAxis bottomAxis = ();
        ("department");
        XDDFValueAxis leftAxis = ();
        ("Number of Employees");
        
        // Create a data source        XDDFDataSource&lt;String&gt; departments = (
                chartSheet, new CellRangeAddress(1, chartRowIdx - 1, 0, 0));
        
        XDDFNumericalDataSource&lt;Double&gt; values = (
                chartSheet, new CellRangeAddress(1, chartRowIdx - 1, 1, 1));
        
        // Create a bar chart        XDDFBarChartData barChart = (XDDFBarChartData) (
                , bottomAxis, leftAxis);
        (true);
        
         series = () (departments, values);
        ("Number of Employees", null);
        
        (barChart);
        
        // Write to ByteArrayOutputStream        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        (outputStream);
        
        return new ByteArrayInputStream(());
    }
}

Note: The above chart code needs to add the following dependencies:

<dependency>
    <groupId></groupId>
    <artifactId>poi-ooxml-full</artifactId>
    <version>5.2.3</version>
</dependency>

4.5 Export Excel using templates

In some scenarios, we need to generate files based on predefined Excel templates, and the following is an example:

public ByteArrayInputStream exportFromTemplate(List&lt;User&gt; users) throws IOException {
    // Load the template file    try (InputStream templateStream = getClass().getResourceAsStream("/templates/user_template.xlsx");
         Workbook workbook = (templateStream)) {
        
        Sheet sheet = (0);
        
        //Fill data from the second row (the first row is the header)        int rowIdx = 1;
        for (User user : users) {
            Row row = (rowIdx++);
            
            (0).setCellValue(());
            (1).setCellValue(());
            (2).setCellValue(());
            (3).setCellValue(());
            (4).setCellValue(());
        }
        
        // Update the date cell in the template (assuming it is in the A1 position)        Row headerRow = (0);
        if ((6) != null) {
            Cell dateCell = (6);
            (new Date());
        }
        
        // Automatically adjust column width        for (int i = 0; i &lt; 5; i++) {
            (i);
        }
        
        // Write to ByteArrayOutputStream        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        (outputStream);
        
        return new ByteArrayInputStream(());
    }
}

5. Use EasyExcel to process Excel files

EasyExcel is Alibaba's open source POI-based Excel processing tool. Compared with native POI, it provides a cleaner API and has obvious performance advantages when processing large files.

5.1 Read Excel using EasyExcel

5.1.1 Creating a Data Model

When using EasyExcel, annotations are usually used to map Excel columns:

package ;

import ;
import ;
import ;

import ;

@Data
public class Employee {
    
    @ExcelProperty("Employee ID")
    private Long id;
    
    @ExcelProperty("Name")
    private String name;
    
    @ExcelProperty("age")
    private Integer age;
    
    @ExcelProperty("Mail")
    private String email;
    
    @ExcelProperty("department")
    private String department;
    
    @ExcelProperty("Order date")
    @DateTimeFormat("yyyy-MM-dd")
    private Date hireDate;
    
    @ExcelProperty("Salary")
    private Double salary;
}
5.1.2 Create a read listener

EasyExcel uses event mode to read Excel, and needs to create a listener to process the read data:

package ;

import ;
import ;
import ;
import .slf4j.Slf4j;

import ;
import ;

@Slf4j
public class EmployeeReadListener extends AnalysisEventListener&lt;Employee&gt; {

    /**
      * Used to temporarily store read data
      */
    private List&lt;Employee&gt; employeeList = new ArrayList&lt;&gt;();
    
    /**
      * The invoke method will be called once every time a row of data is read
      */
    @Override
    public void invoke(Employee employee, AnalysisContext context) {
        ("Read a data: {}", employee);
        (employee);
        
        // When BATCH_COUNT is reached, the database needs to be stored once to prevent tens of thousands of pieces of data from being in memory, making it easy to OOM        if (() &gt;= 5000) {
            saveData();
            // Clean the memory            ();
        }
    }
    
    /**
      * Call this method after all data parsing is completed
      */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // Make sure the last batch of data is saved        saveData();
        ("All data parsing is completed!");
    }
    
    /**
      * Save data, here is just printing, and in actual applications, you can save the data into the database
      */
    private void saveData() {
        ("{}Data,Start saving the database!", ());
        // Here you can call the persistence layer to complete the data entry into the database        ("Storing the database successfully!");
    }
    
    /**
      * Get the read data
      */
    public List&lt;Employee&gt; getEmployeeList() {
        return employeeList;
    }
}
5.1.3 Create an Excel read service
package ;

import ;
import ;
import ;
import .slf4j.Slf4j;
import ;
import ;

import ;
import ;

@Slf4j
@Service
public class EasyExcelService {

    public List<Employee> readEmployeeData(MultipartFile file) throws IOException {
        EmployeeReadListener listener = new EmployeeReadListener();
        
        ((), , listener).sheet().doRead();
        
        return ();
    }
}
5.1.4 Creating a Controller
package ;

import ;
import ;
import .slf4j.Slf4j;
import ;
import ;
import ;
import ;
import ;
import ;
import ;

import ;
import ;

@Slf4j
@RestController
@RequestMapping("/api/easyexcel")
public class EasyExcelController {

    @Autowired
    private EasyExcelService easyExcelService;
    
    @PostMapping("/upload")
    public ResponseEntity&lt;List&lt;Employee&gt;&gt; uploadExcel(@RequestParam("file") MultipartFile file) {
        try {
            List&lt;Employee&gt; employees = (file);
            return (employees);
        } catch (IOException e) {
            ("Excel read failed", e);
            return ().build();
        }
    }
}

5.2 Export Excel using EasyExcel

5.2.1 Simple export example
package ;

import ;
import ;
import ;
import ;

import ;
import ;
import ;
import ;

@Service
public class EasyExcelExportService {

    /**
      * Export employee data to Excel file
      */
    public void exportEmployees(List&lt;Employee&gt; employees, OutputStream outputStream) {
        (outputStream, )
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())  // Automatically adjust column width                .sheet("Employee Data")
                .doWrite(employees);
    }
    
    /**
      * Export employee data to specified file
      */
    public void exportEmployeesToFile(List&lt;Employee&gt; employees, String fileName) throws IOException {
        // Make sure the directory exists        File file = new File(fileName);
        if (!().exists()) {
            ().mkdirs();
        }
        
        (fileName, )
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                .sheet("Employee Data")
                .doWrite(employees);
    }
    
    /**
      * Export multiple Sheets Excel
      */
    public void exportMultipleSheets(List&lt;List&lt;Employee&gt;&gt; departmentEmployees, 
                                    List&lt;String&gt; sheetNames, 
                                    OutputStream outputStream) {
        // Create ExcelWriter        try (var excelWriter = (outputStream, )
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                .build()) {
            
            // Multiple Sheets are written to the same object            for (int i = 0; i &lt; (); i++) {
                // Get the Sheet name                String sheetName = i &lt; () ? (i) : "Sheet" + (i + 1);
                
                // Create a new Sheet                var writeSheet = (i, sheetName).build();
                
                // Write data                ((i), writeSheet);
            }
        }
    }
}
5.2.2 Create Controller
package ;

import ;
import ;
import ;
import ;
import ;
import ;

import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;

@RestController
@RequestMapping("/api/easyexcel")
public class EasyExcelExportController {

    @Autowired
    private EasyExcelExportService exportService;
    
    @GetMapping("/export")
    public void exportEmployees(HttpServletResponse response) throws IOException {
        // Set the response content        ("application/");
        ("utf-8");
        
        // Set file name        String fileName = ("Employee Data", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
        ("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        
        // Get test data        List&lt;Employee&gt; employees = getTestEmployees();
        
        // Export Excel        (employees, ());
    }
    
    @GetMapping("/export-multiple-sheets")
    public void exportMultipleSheets(HttpServletResponse response) throws IOException {
        // Set the response content        ("application/");
        ("utf-8");
        
        // Set file name        String fileName = ("Department Employee Data", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
        ("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        
        // Get test data - Employees in three departments        List&lt;List&lt;Employee&gt;&gt; departmentEmployees = new ArrayList&lt;&gt;();
        (getEmployeesByDepartment("R&D Department"));
        (getEmployeesByDepartment("Market Department"));
        (getEmployeesByDepartment("Ministry of Administration"));
        
        // Sheet name        List&lt;String&gt; sheetNames = ("R&D Department Employee", "State of Marketing", "Administrative Office Staff");
        
        // Export Excel        (departmentEmployees, sheetNames, ());
    }
    
    /**
      * Generate test employee data
      */
    private List&lt;Employee&gt; getTestEmployees() {
        List&lt;Employee&gt; employees = new ArrayList&lt;&gt;();
        
        // Add test data        for (int i = 1; i &lt;= 10; i++) {
            Employee employee = new Employee();
            ((long) i);
            ("staff" + i);
            (20 + i);
            ("employee" + i + "@");
            (i % 3 == 0 ? "R&D Department" : (i % 3 == 1 ? "Market Department" : "Ministry of Administration"));
            (new Date());
            (5000.0 + i * 1000);
            
            (employee);
        }
        
        return employees;
    }
    
    /**
      * Obtain employees according to the department
      */
    private List&lt;Employee&gt; getEmployeesByDepartment(String department) {
        List&lt;Employee&gt; allEmployees = getTestEmployees();
        List&lt;Employee&gt; departmentEmployees = new ArrayList&lt;&gt;();
        
        for (Employee employee : allEmployees) {
            if ((())) {
                (employee);
            }
        }
        
        return departmentEmployees;
    }

    // ... 5.2.3 Using custom styles and complex table headers
    /**
      * Export custom style Excel
      */
    public void exportWithCustomStyle(List&lt;Employee&gt; employees, OutputStream outputStream) {
        // Set custom interceptors to handle styles        (outputStream, )
                // Automatically adjust column width                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                // Set the header style                .registerWriteHandler(new AbstractRowHeightStyleStrategy() {
                    @Override
                    protected void setHeadColumnHeight(Row row, int relativeRowIndex) {
                        // Set the header row height                        ((short) 500);
                    }

                    @Override
                    protected void setContentColumnHeight(Row row, int relativeRowIndex) {
                        // Set content line height                        ((short) 400);
                    }
                })
                // Set cell style                .registerWriteHandler(new CellWriteHandler() {
                    @Override
                    public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, 
                                              Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
                        // Set the header style                        if (isHead) {
                            Workbook workbook = ().getWorkbook();
                            CellStyle style = ();
                            Font font = ();
                            (true);
                            ((short) 12);
                            (());
                            (font);
                            (IndexedColors.ROYAL_BLUE.getIndex());
                            (FillPatternType.SOLID_FOREGROUND);
                            ();
                            ();
                            (style);
                        }
                    }

                    @Override
                    public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, 
                                                     Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
                        // Here you can set styles according to the data content                    }

                    @Override
                    public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, 
                                               List&lt;CellData&gt; cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
                        // Content line style                        if (!isHead) {
                            // Even lines set background color                            if (relativeRowIndex % 2 == 0) {
                                Workbook workbook = ().getWorkbook();
                                CellStyle style = ();
                                (IndexedColors.PALE_BLUE.getIndex());
                                (FillPatternType.SOLID_FOREGROUND);
                                ();
                                ();
                                (style);
                            }
                        }
                    }
                })
                .sheet("Employee Data")
                .doWrite(employees);
    }

    /**
      * Export complex table headers Excel
      */
    public void exportWithComplexHead(List&lt;Employee&gt; employees, OutputStream outputStream) {
        // Build complex table headers        List&lt;List&lt;String&gt;&gt; head = new ArrayList&lt;&gt;();
        
        // First column ID        List&lt;String&gt; head1 = new ArrayList&lt;&gt;();
        ("Basic Information");
        ("Employee ID");
        (head1);
        
        // Second column Name        List&lt;String&gt; head2 = new ArrayList&lt;&gt;();
        ("Basic Information");
        ("Name");
        (head2);
        
        // Column 3 Age        List&lt;String&gt; head3 = new ArrayList&lt;&gt;();
        ("Basic Information");
        ("age");
        (head3);
        
        // Column 4 Email        List&lt;String&gt; head4 = new ArrayList&lt;&gt;();
        ("Contact Information");
        ("Mail");
        (head4);
        
        // Column 5 Department        List&lt;String&gt; head5 = new ArrayList&lt;&gt;();
        ("Work Information");
        ("department");
        (head5);
        
        // Column Sixth Entry Date        List&lt;String&gt; head6 = new ArrayList&lt;&gt;();
        ("Work Information");
        ("Order date");
        (head6);
        
        // Column 7 Salary        List&lt;String&gt; head7 = new ArrayList&lt;&gt;();
        ("Salary Information");
        ("Monthly salary(Yuan)");
        (head7);
        
        // Convert data to List<List<Object>> format        List&lt;List&lt;Object&gt;&gt; dataList = new ArrayList&lt;&gt;();
        for (Employee employee : employees) {
            List&lt;Object&gt; data = new ArrayList&lt;&gt;();
            (());
            (());
            (());
            (());
            (());
            (());
            (());
            (data);
        }
        
        // Write to Excel        (outputStream)
                .head(head)
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                .sheet("Employee Data")
                .doWrite(dataList);
    }
}

6. Strategy for handling large Excel files

6.1 Using Apache POI SXSSF Mode

SXSSF (Streaming Xlsx Writer) is a streaming writing method provided by POI, which can greatly reduce memory usage:

public void exportLargeExcel(String fileName, int rowCount) throws IOException {
    try (SXSSFWorkbook workbook = new SXSSFWorkbook(100)) { // 100 indicates the number of rows reserved in memory        Sheet sheet = ("Big Data");
        
        // Create a header        Row headerRow = (0);
        for (int i = 0; i &lt; 10; i++) {
            (i).setCellValue("List " + (i + 1));
        }
        
        // Create data rows        for (int i = 0; i &lt; rowCount; i++) {
            Row row = (i + 1);
            for (int j = 0; j &lt; 10; j++) {
                (j).setCellValue("data " + (i + 1) + "-" + (j + 1));
            }
            
            // Clean up temporary files every 10,000 lines generated            if (i % 10000 == 0) {
                ((SXSSFSheet)sheet).flushRows();
            }
        }
        
        // Write to the file        try (FileOutputStream outputStream = new FileOutputStream(fileName)) {
            (outputStream);
        }
        
        // Clean up temporary files        ();
    }
}

Notes:

  1. Be sure to call after usedispose()Method to clean temporary files
  2. SXSSF only supports write operations, not reads
  3. Some advanced features (such as merging cells, etc.) are not supported

6.2 Using EasyExcel to handle large files

EasyExcel has designed to consider large file processing, and uses SAX to read line by line, with a small memory footprint:

// Read large filespublic void readLargeExcel(String fileName) {
    // Read using SAX    (fileName, , new EmployeeReadListener())
            .sheet()
            .doRead();
}

// Write to large filespublic void writeLargeExcel(String fileName, int batchSize) {
    // Get data in batches    try (ExcelWriter excelWriter = (fileName, )
            .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
            .build()) {
        
        // Get the WriteSheet object        WriteSheet writeSheet = ("Employee Data").build();
        
        // Simulate data acquisition in batches        int totalCount = 100000; // Total data volume        for (int i = 0; i &lt; totalCount; i += batchSize) {
            // Get the current batch data            List&lt;Employee&gt; data = getBatchData(i, (i + batchSize, totalCount));
            // Write to Excel            (data, writeSheet);
        }
    }
}

// Simulate data acquisition in batchesprivate List&lt;Employee&gt; getBatchData(int start, int end) {
    List&lt;Employee&gt; list = new ArrayList&lt;&gt;();
    for (int i = start; i &lt; end; i++) {
        Employee employee = new Employee();
        ((long) i);
        ("staff" + i);
        (20 + (i % 20));
        ("employee" + i + "@");
        (i % 3 == 0 ? "R&D Department" : (i % 3 == 1 ? "Market Department" : "Ministry of Administration"));
        (new Date());
        (5000.0 + (i % 10) * 1000);
        
        (employee);
    }
    return list;
}

6.3 Use CSV instead of Excel

For extremely large data sets, consider using CSV format instead of Excel:

public void exportToCsv(List&lt;Employee&gt; employees, String fileName) throws IOException {
    try (FileWriter writer = new FileWriter(fileName);
         CSVPrinter csvPrinter = new CSVPrinter(writer, 
                 .withHeader("ID", "Name", "age", "Mail", "department", "Order date", "Salary"))) {
                 
        for (Employee employee : employees) {
            (
                (),
                (),
                (),
                (),
                (),
                (),
                ()
            );
        }
        
        ();
    }
}

Note: Using CSV requires adding dependencies:

<dependency>
    <groupId></groupId>
    <artifactId>commons-csv</artifactId>
    <version>1.9.0</version>
</dependency>

6.4 Pagination Export Large Data Sets

For large data sets that need to be exported in web applications, you can consider paging export:

@GetMapping("/export/paged")
public ResponseEntity&lt;String&gt; exportPaged() {
    // Generate a unique task ID    String taskId = ().toString();
    
    // Start asynchronous task    (() -&gt; {
        try {
            // Export file path            String filePath = "/temp/" + taskId + ".xlsx";
            
            //Page query data and write to Excel            int pageSize = 1000;
            int totalPages = getTotalPages(pageSize);
            
            try (ExcelWriter excelWriter = (filePath, )
                    .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                    .build()) {
                
                WriteSheet writeSheet = ("Employee Data").build();
                
                // Pagination export                for (int pageNum = 0; pageNum &lt; totalPages; pageNum++) {
                    // Query data from database paging                    List&lt;Employee&gt; pageData = getPageData(pageNum, pageSize);
                    // Write to Excel                    (pageData, writeSheet);
                    // Update progress                    updateExportProgress(taskId, (pageNum + 1) * 100 / totalPages);
                }
            }
            
            // Update the export status to complete            updateExportStatus(taskId, "COMPLETED", filePath);
            
        } catch (Exception e) {
            // Update export status failed            updateExportStatus(taskId, "FAILED", null);
        }
    });
    
    // Return task ID    return (taskId);
}

@GetMapping("/export/status/{taskId}")
public ResponseEntity&lt;Map&lt;String, Object&gt;&gt; getExportStatus(@PathVariable String taskId) {
    // Get task status    Map&lt;String, Object&gt; status = getTaskStatus(taskId);
    return (status);
}

@GetMapping("/export/download/{taskId}")
public ResponseEntity&lt;Resource&gt; downloadExportedFile(@PathVariable String taskId) {
    // Get the export file path    String filePath = getExportedFilePath(taskId);
    
    if (filePath == null) {
        return ().build();
    }
    
    // Create file resources    Resource resource = new FileSystemResource(filePath);
    
    return ()
            .header(HttpHeaders.CONTENT_DISPOSITION, 
                    "attachment; filename=employee_data.xlsx")
            .contentType(("application/-excel"))
            .body(resource);
}

7. Practical application scenarios and best practices

7.1 Dynamic column export

In some business scenarios, the exported column needs to be dynamically determined based on user selection:

public ByteArrayInputStream exportDynamicColumns(List&lt;Employee&gt; employees, List&lt;String&gt; selectedColumns) throws IOException {
    // Define all possible columns    Map&lt;String, String&gt; allColumns = new HashMap&lt;&gt;();
    ("id", "Employee ID");
    ("name", "Name");
    ("age", "age");
    ("email", "Mail");
    ("department", "department");
    ("hireDate", "Order date");
    ("salary", "Salary");
    
    try (Workbook workbook = new XSSFWorkbook()) {
        Sheet sheet = ("Employee Data");
        
        // Create a header row        Row headerRow = (0);
        
        // Set the header style        CellStyle headerStyle = ();
        Font headerFont = ();
        (true);
        (headerFont);
        
        // Fill the table header        int colIdx = 0;
        for (String column : selectedColumns) {
            if ((column)) {
                Cell cell = (colIdx++);
                ((column));
                (headerStyle);
            }
        }
        
        // Fill in data        int rowIdx = 1;
        for (Employee employee : employees) {
            Row row = (rowIdx++);
            
            colIdx = 0;
            for (String column : selectedColumns) {
                Cell cell = (colIdx++);
                
                // Set cell value according to column name                switch (column) {
                    case "id":
                        (());
                        break;
                    case "name":
                        (());
                        break;
                    case "age":
                        (());
                        break;
                    case "email":
                        (());
                        break;
                    case "department":
                        (());
                        break;
                    case "hireDate":
                        if (() != null) {
                            (());
                            
                            // Set date format                            CellStyle dateStyle = ();
                            CreationHelper createHelper = ();
                            (().getFormat("yyyy-mm-dd"));
                            (dateStyle);
                        }
                        break;
                    case "salary":
                        (());
                        break;
                }
            }
        }
        
        // Automatically adjust column width        for (int i = 0; i &lt; (); i++) {
            (i);
        }
        
        // Output        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        (outputStream);
        return new ByteArrayInputStream(());
    }
}

7.2 Excel template filling

Generate Excel using Freemarker or other template engine:

public ByteArrayInputStream fillTemplate(Map&lt;String, Object&gt; data) throws Exception {
    // Loading template    Configuration cfg = new Configuration(Configuration.VERSION_2_3_30);
    (getClass().getClassLoader(), "templates");
    ("UTF-8");
    
    // Get the template    Template template = ("excel_template.ftl");
    
    // Output directory    File tempDir = new File((""));
    File tempFile = new File(tempDir, "temp_" + () + ".xlsx");
    
    // Fill the template    try (Writer out = new FileWriter(tempFile)) {
        (data, out);
    }
    
    // Read the filled file    try (FileInputStream fis = new FileInputStream(tempFile)) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len;
        while ((len = (buffer)) &gt; -1) {
            (buffer, 0, len);
        }
        ();
        
        // Delete temporary files        ();
        
        return new ByteArrayInputStream(());
    }
}

7.3 Excel file verification

Perform data verification before importing Excel files:

public class ExcelValidationListener extends AnalysisEventListener&lt;Employee&gt; {
    
    private List&lt;Employee&gt; validEmployees = new ArrayList&lt;&gt;();
    private List&lt;Map&lt;String, Object&gt;&gt; errorRecords = new ArrayList&lt;&gt;();
    private int rowIndex = 1; // Starting from 1, 0 is the header    
    @Override
    public void invoke(Employee employee, AnalysisContext context) {
        rowIndex++;
        
        // Verify data        List&lt;String&gt; errors = validateEmployee(employee);
        
        if (()) {
            // The data is valid            (employee);
        } else {
            // Record error            Map&lt;String, Object&gt; errorRecord = new HashMap&lt;&gt;();
            ("rowIndex", rowIndex);
            ("data", employee);
            ("errors", errors);
            (errorRecord);
        }
    }
    
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // Processing is completed    }
    
    // Verify employee data    private List&lt;String&gt; validateEmployee(Employee employee) {
        List&lt;String&gt; errors = new ArrayList&lt;&gt;();
        
        // Verify name        if (() == null || ().trim().isEmpty()) {
            ("The name cannot be empty");
        }
        
        // Verify age        if (() == null) {
            ("Age cannot be empty");
        } else if (() &lt; 18 || () &gt; 65) {
            ("Age must be between 18 and 65 years old");
        }
        
        // Verify the email address        if (() != null &amp;&amp; !().isEmpty()) {
            String emailRegex = "^[a-zA-Z0-9_+&amp;*-]+(?:\\.[a-zA-Z0-9_+&amp;*-]+)*@" +
                    "(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$";
            if (!().matches(emailRegex)) {
                ("The email format is incorrect");
            }
        }
        
        // Verification Department        if (() == null || ().trim().isEmpty()) {
            ("The department cannot be empty");
        }
        
        // Verify salary        if (() != null &amp;&amp; () &lt; 0) {
            ("Salary cannot be negative");
        }
        
        return errors;
    }
    
    public List&lt;Employee&gt; getValidEmployees() {
        return validEmployees;
    }
    
    public List&lt;Map&lt;String, Object&gt;&gt; getErrorRecords() {
        return errorRecords;
    }
    
    public boolean hasErrors() {
        return !();
    }
}

7.4 Unified exception handling

Add unified exception handling for Excel processing:

@ControllerAdvice
public class ExcelExceptionHandler {

    private static final Logger logger = ();
    
    @ExceptionHandler()
    public ResponseEntity&lt;Map&lt;String, String&gt;&gt; handleIOException(IOException e) {
        ("File read and write exception", e);
        
        Map&lt;String, String&gt; response = new HashMap&lt;&gt;();
        ("error", "File read and write exception");
        ("message", ());
        
        return (HttpStatus.INTERNAL_SERVER_ERROR).body(response);
    }
    
    @ExceptionHandler()
    public ResponseEntity&lt;Map&lt;String, String&gt;&gt; handleIllegalArgumentException(IllegalArgumentException e) {
        ("Parameter exception", e);
        
        Map&lt;String, String&gt; response = new HashMap&lt;&gt;();
        ("error", "Parameter exception");
        ("message", ());
        
        return (HttpStatus.BAD_REQUEST).body(response);
    }
    
    @ExceptionHandler()
    public ResponseEntity&lt;Map&lt;String, String&gt;&gt; handleGenericException(Exception e) {
        ("Excel handles exceptions", e);
        
        Map&lt;String, String&gt; response = new HashMap&lt;&gt;();
        ("error", "Excel handles exceptions");
        ("message", ());
        
        return (HttpStatus.INTERNAL_SERVER_ERROR).body(response);
    }
}

8. Performance optimization and precautions

8.1 Performance optimization suggestions

Use the appropriate Excel library

  • Apache POI can be used in small files
  • Please use EasyExcel or POI's SXSSF mode for large files
  • Consider using CSV format for extremely large files

Avoid loading entire files at once

  • Use streaming parsing when reading
  • Use batch writes when writing

Set the buffer size reasonably

  • Setting a reasonable number of memory lines in SXSSFWorkbook
  • Select the appropriate batch size in batch processing

Reduce style objects

  • Style object reuse instead of creating new styles for each cell
  • Limit the number of colors, fonts, and border styles used

Using asynchronous processing

  • Put large file processing in background threads to execute
  • Provide progress feedback mechanism

8.2 Notes

Memory management

  • Pay attention to monitoring JVM memory usage
  • For large file processing, consider increasing JVM heap memory (-Xmx parameter)
  • Close resources and clean temporary files in time after use

Safety considerations

  • Limit uploaded file size
  • Verify file type and content
  • Prevent malicious Excel files (including macros or formulas)

Coding issues

  • Make sure to use the correct character encoding when processing international characters
  • Make sure to encode correctly when the file name contains Chinese

Concurrent control

  • Pay attention to server load when processing large files
  • Limit the number of concurrent processing tasks

Temporary file cleaning

  • When using SXSSF, the dispose() method must be called to clean the temporary file
  • Regularly clean temporary files on the server

Summarize

Spring Boot provides powerful and flexible Excel processing capabilities. By combining tools such as Apache POI and EasyExcel, you can easily realize the reading, creation and export of Excel files. In actual applications, appropriate processing strategies should be selected based on specific needs and data volumes, which should not only ensure complete functions, but also pay attention to performance and resource use.

Whether it is simple data export, complex report generation, or large data file processing, it can be flexibly implemented through the methods introduced in this article. The key is to choose appropriate technical solutions based on actual business scenarios, and pay attention to performance optimization and exception handling.

The above is personal experience. I hope you can give you a reference and I hope you can support me more.