杰瑞科技汇

Java如何实现Excel导出?

  1. Apache POI:功能最强大、历史最悠久、社区最活跃的 Java API,可以处理 .xls (旧版 Excel) 和 .xlsx (新版 Excel) 格式,它是事实上的标准。
  2. EasyExcel:由阿里巴巴开源,基于 POI 封装,它的最大特点是内存占用低,特别适合处理大数据量(如十万甚至百万行数据)的导出,能有效避免 OutOfMemoryError

下面我将详细介绍这两种方法,并提供从简单到复杂的完整代码示例。

Java如何实现Excel导出?-图1
(图片来源网络,侵删)

Apache POI (功能全面,适合大多数场景)

Apache POI 是一个老牌项目,功能非常完善,可以操作 Office 文档的所有元素,包括样式、图表、图片、公式等。

添加 Maven 依赖

在你的 pom.xml 文件中添加 POI 的依赖,为了同时支持 .xls.xlsx,建议都加上。

<dependencies>
    <!-- 支持 .xlsx 格式 (Office 2007+) -->
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>5.2.5</version> <!-- 请使用最新版本 -->
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>5.2.5</version>
    </dependency>
    <!-- 支持 .xls 格式 (Office 97-2003) -->
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-scratchpad</artifactId>
        <version>5.2.5</version>
    </dependency>
</dependencies>

代码示例

示例 1:最简单的导出(无样式)

这个例子演示如何创建一个 .xlsx 文件并写入数据。

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.FileOutputStream;
import java.io.IOException;
public class PoiSimpleExport {
    public static void main(String[] args) {
        // 1. 创建一个新的 Excel 工作簿 (XSSFWorkbook for .xlsx)
        Workbook workbook = new XSSFWorkbook();
        // 2. 创建一个工作表
        Sheet sheet = workbook.createSheet("员工信息");
        // 3. 创建表头(第一行)
        Row headerRow = sheet.createRow(0);
        headerRow.createCell(0).setCellValue("姓名");
        headerRow.createCell(1).setCellValue("年龄");
        headerRow.createCell(2).setCellValue("部门");
        // 4. 创建数据行
        Row dataRow1 = sheet.createRow(1);
        dataRow1.createCell(0).setCellValue("张三");
        dataRow1.createCell(1).setCellValue(28);
        dataRow1.createCell(2).setCellValue("技术部");
        Row dataRow2 = sheet.createRow(2);
        dataRow2.createCell(0).setCellValue("李四");
        dataRow2.createCell(1).setCellValue(32);
        dataRow2.createCell(2).setCellValue("市场部");
        // 5. 自动调整列宽,使内容能够完整显示
        sheet.autoSizeColumn(0);
        sheet.autoSizeColumn(1);
        sheet.autoSizeColumn(2);
        // 6. 写入文件
        try (FileOutputStream outputStream = new FileOutputStream("D:/temp/员工信息.xlsx")) {
            workbook.write(outputStream);
            System.out.println("Excel 文件生成成功!");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 7. 关闭工作簿
            try {
                workbook.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

示例 2:带样式的导出

这个例子演示如何设置单元格的样式,如字体、颜色、边框等。

Java如何实现Excel导出?-图2
(图片来源网络,侵删)
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.FileOutputStream;
import java.io.IOException;
public class PoiStyledExport {
    public static void main(String[] args) {
        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet(" styled_sheet");
        // 创建样式
        CellStyle headerStyle = workbook.createCellStyle();
        Font headerFont = workbook.createFont();
        headerFont.setBold(true); // 加粗
        headerFont.setColor(IndexedColors.WHITE.getIndex()); // 白色字体
        headerStyle.setFont(headerFont);
        headerStyle.setFillForegroundColor(IndexedColors.BLUE.getIndex()); // 蓝色背景
        headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        headerStyle.setAlignment(HorizontalAlignment.CENTER); // 居中
        headerStyle.setBorderBottom(BorderStyle.THIN);
        headerStyle.setBorderTop(BorderStyle.THIN);
        headerStyle.setBorderLeft(BorderStyle.THIN);
        headerStyle.setBorderRight(BorderStyle.THIN);
        // 数据行样式
        CellStyle dataStyle = workbook.createCellStyle();
        dataStyle.setAlignment(HorizontalAlignment.CENTER);
        dataStyle.setBorderBottom(BorderStyle.THIN);
        dataStyle.setBorderTop(BorderStyle.THIN);
        dataStyle.setBorderLeft(BorderStyle.THIN);
        dataStyle.setBorderRight(BorderStyle.THIN);
        // 创建表头
        Row headerRow = sheet.createRow(0);
        String[] headers = {"姓名", "年龄", "部门", "入职日期"};
        for (int i = 0; i < headers.length; i++) {
            Cell cell = headerRow.createCell(i);
            cell.setCellValue(headers[i]);
            cell.setCellStyle(headerStyle);
        }
        // 创建数据行
        Row dataRow1 = sheet.createRow(1);
        dataRow1.createCell(0).setCellValue("王五");
        dataRow1.createCell(1).setCellValue(30);
        dataRow1.createCell(2).setCellValue("产品部");
        dataRow1.createCell(3).setCellValue.setCellValue(new Date()); // 日期类型
        for(int i=0; i<dataRow1.getLastCellNum(); i++) {
            dataRow1.getCell(i).setCellStyle(dataStyle);
        }
        // 自动调整列宽
        for (int i = 0; i < headers.length; i++) {
            sheet.autoSizeColumn(i);
        }
        // 写入文件
        try (FileOutputStream outputStream = new FileOutputStream("D:/temp/styled_employee.xlsx")) {
            workbook.write(outputStream);
            System.out.println("带样式的 Excel 文件生成成功!");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                workbook.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

EasyExcel (内存优化,适合大数据量)

EasyExcel 是阿里巴巴开源的,它通过 SAX (Simple API for XML) 模式来解析 Excel,写操作同样采用了流式写入,因此在写入大量数据时,它不会一次性将所有数据加载到内存中,从而极大地降低了内存消耗。

添加 Maven 依赖

<dependencies>
    <!-- easyexcel 核心依赖 -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>easyexcel</artifactId>
        <version>3.3.2</version> <!-- 请使用最新版本 -->
    </dependency>
</dependencies>

代码示例

EasyExcel 的使用模式更简洁,它通过一个监听器(WriteSheetHolder 等)来处理数据。

示例 1:最简单的导出

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.WriteTable;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class EasyExcelSimpleExport {
    public static void main(String[] args) {
        // 1. 准备数据
        List<User> dataList = new ArrayList<>();
        for (int i = 1; i <= 10; i++) {
            dataList.add(new User("用户" + i, 20 + i, "部门" + i, new Date()));
        }
        // 2. 写入文件
        String fileName = "D:/temp/easyexcel_user.xlsx";
        // EasyExcel.write(fileName, User.class).sheet("用户数据").doWrite(dataList);
        // 更灵活的写法,可以自定义表头
        EasyExcel.write(fileName)
                .head(head()) // 自定义表头
                .sheet("用户信息")
                .doWrite(dataList);
        System.out.println("EasyExcel 文件生成成功!");
    }
    // 自定义表头
    private static List<List<String>> head() {
        List<List<String>> list = new ArrayList<>();
        List<String> head0 = new ArrayList<>();
        head0.add("姓名");
        list.add(head0);
        List<String> head1 = new ArrayList<>();
        head1.add("年龄");
        list.add(head1);
        List<String> head2 = new ArrayList<>();
        head2.add("部门");
        list.add(head2);
        List<String> head3 = new ArrayList<>();
        head3.add("入职日期");
        list.add(head3);
        return list;
    }
    // 数据模型类
    public static class User {
        @ExcelProperty("姓名") // 指定列名
        private String name;
        @ExcelProperty("年龄")
        private Integer age;
        @ExcelProperty("部门")
        private String department;
        @ExcelProperty("入职日期")
        private Date date;
        // 构造器、getter/setter 省略...
        public User(String name, Integer age, String department, Date date) {
            this.name = name;
            this.age = age;
            this.department = department;
            this.date = date;
        }
        // 必须有无参构造器
        public User() {}
        public String getName() { return name; }
        public Integer getAge() { return age; }
        public String getDepartment() { return department; }
        public Date getDate() { return date; }
    }
}

示例 2:大数据量导出(核心优势)

EasyExcel 导出大数据量时,推荐使用 ExcelWriterWriteSheet 的组合,并分批次写入数据。

import com.alibaba.excel.EasyExcel;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class EasyExcelBigDataExport {
    public static void main(String[] args) {
        String fileName = "D:/temp/easyexcel_big_data.xlsx";
        // 1. 创建 ExcelWriter
        EasyExcel.write(fileName, User.class).sheet("大数据").doWrite(() -> {
            // 2. 使用回调函数分批次写入数据
            // 模拟从数据库分页查询数据
            for (int i = 0; i < 100000; i++) { // 假设有10万条数据
                List<User> dataList = new ArrayList<>();
                for (int j = 0; j < 1000; j++) { // 每次查询1000条
                    dataList.add(new User("用户" + (i * 1000 + j), 20 + (i * 1000 + j) % 50, "部门" + (i * 1000 + j) % 10, new Date()));
                }
                // 返回数据,EasyExcel 会自动写入
                return dataList;
            }
            // 数据写完后返回 null
            return null;
        });
        System.out.println("大数据量 Excel 文件生成成功!");
    }
    // User 类同上...
}

如何选择?

特性 Apache POI EasyExcel
内存占用 较高,大数据量易 OOM 极低,流式写入,适合大数据
API 易用性 繁琐,需要手动管理样式、对象 简洁,注解驱动,API 更友好
功能完整性 非常强大,支持所有 Office 功能 功能覆盖大部分常见需求,复杂功能可能需要回退 POI
学习曲线 陡峭 平缓
适用场景 - 数据量不大(几千行)
- 需要复杂的样式、图表、图片等
- 对兼容性要求极高
- 数据量巨大(万行以上)
- 快速开发和部署
- 对内存敏感的应用
  • 对于日常中小型数据导出,或者需要非常复杂格式的 Excel,Apache POI 是一个可靠的选择。
  • 对于大型数据导出,或者希望项目更轻量、开发更高效,EasyExcel 是不二之选,它解决了 POI 在大数据场景下的最大痛点。

希望这个详细的指南能帮助你!

Java如何实现Excel导出?-图3
(图片来源网络,侵删)
分享:
扫描分享到社交APP
上一篇
下一篇