我们致力于探索、分享和推荐最新的实用技术栈、开源项目、框架和实用工具。每天都有新鲜的开源资讯等待你的发现!
大家好,我是常利兵,独立开发者,这是我的网站 https://make.dxmwl.com
Java 导出 Excel,你真的会吗?
在 Java 开发的世界里,相信不少小伙伴都遇到过这样的需求:将数据导出为 Excel 文件 。看似简单的任务,背后却隐藏着不少门道。比如,当数据量庞大时,如何避免内存溢出?怎样自定义 Excel 的样式,让导出的表格更加美观和专业?又有哪些工具和库可以帮助我们高效地实现这一功能?
在实际开发中,导出 Excel 是一个非常常见的需求。无论是生成报表、数据备份,还是与其他系统进行数据交互,Excel 文件都因其直观、易于编辑的特点,成为了数据传输和展示的重要载体 。所以掌握 Java 中导出 Excel 文件的方法,对于我们开发者来说,是一项必备的技能。接下来,就让我们一起深入探索 Java 导出 Excel 的奥秘吧!
一、Java 导出 Excel 的常用工具
在 Java 中,有许多工具可以帮助我们实现 Excel 文件的导出,其中比较常用的有 Apache POI 和 EasyExcel 。下面我们来详细了解一下这两个工具。
(一)Apache POI
Apache POI 是一个强大的操作 Microsoft Office 格式文件的 API,它允许 Java 开发者创建、修改和显示 MS Office 文件,包括 Excel、Word、PowerPoint 等 。在 Excel 文件导出方面,Apache POI 提供了丰富的功能和灵活的操作方式。
Apache POI 针对 Excel 文件提供了两种主要的实现:HSSF 和 XSSF 。HSSF 用于操作 Excel 97-2003 版本的文件,文件后缀为.xls ,它基于早期的二进制格式,一个工作表最多支持 65536 行、256 列 。而 XSSF 则用于操作 Excel 2007 及以上版本的文件,文件后缀为.xlsx ,它基于 Office Open XML 格式,一个工作表最多支持 1048576 行、16384 列 ,并且在处理大型文件时,内存使用效率更高,还支持 Excel 中的许多高级功能,如公式、格式、图表等 。使用 Apache POI 导出 Excel 文件,我们可以通过创建 Workbook(工作簿)、Sheet(工作表)、Row(行)和 Cell(单元格)等对象,逐步构建出 Excel 文件的结构,并填充数据 。同时,还可以对单元格的样式、字体、颜色、边框等进行设置,使导出的 Excel 文件更加美观和专业 。不过,Apache POI 在处理大数据量时,可能会因为内存占用过高而导致性能问题,需要我们谨慎使用 。
(二)EasyExcel
EasyExcel 是阿里巴巴开源的一个 Excel 处理框架,它是基于 Apache POI 进行封装的,旨在简化 Excel 数据的读写操作 。EasyExcel 具有高性能、简单易用、占用内存小等特点,特别适合处理大量数据的导入导出 。
EasyExcel 通过使用注解和简洁的 API,大大简化了 Excel 文件的操作过程 。我们只需要定义一个 Java 实体类,使用 @ExcelProperty 等注解来标识字段与 Excel 表头的映射关系,就可以轻松实现数据的导出 。例如,在导出用户信息时,我们可以定义一个 User 类,使用注解指定每个字段对应的表头名称,然后通过 EasyExcel 的 write 方法,传入文件路径、实体类和数据列表,即可完成 Excel 文件的导出 。在处理大数据量时,EasyExcel 采用了 SAX(Simple API for XML)模式,按需逐行读取和写入数据,避免了一次性加载整个文件到内存中,从而有效降低了内存的使用,提高了处理效率 。此外,EasyExcel 还支持多线程读写、自定义样式、复杂表头、公式设置等功能,满足了我们在实际开发中的各种需求 。
二、使用 Apache POI 导出 Excel 文件
(一)导入依赖
如果你使用的是 Maven 项目,在pom.xml文件中添加 Apache POI 的依赖。对于 Excel 2007 及以上版本的.xlsx文件,需要添加poi-ooxml依赖;对于 Excel 97 - 2003 版本的.xls文件,需要添加poi依赖 。这里以.xlsx文件为例:
<dependencies>
<!-- POI 核心库,包含操作 Office 文档的基本类 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.3.0</version>
</dependency>
<!-- POI OOXML 库,用于处理 .xlsx 等基于 XML 的格式 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.3.0</version>
</dependency>
</dependencies>
添加依赖后,Maven 会自动下载并管理这些依赖包,让你的项目具备使用 Apache POI 的基础 。
(二)编写导出代码
下面通过一个示例代码,展示如何使用 Apache POI 导出一个简单的 Excel 文件 。假设我们有一个用户列表,每个用户包含姓名、年龄和性别信息,需要将这些信息导出到 Excel 文件中 。
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
publicclassExcelExporter{
publicstaticvoidmain(String[] args){
// 模拟数据
List<User> userList = new ArrayList<>();
userList.add(new User("张三", 20, "男"));
userList.add(new User("李四", 22, "女"));
userList.add(new User("王五", 25, "男"));
// 创建工作簿
Workbook workbook = new XSSFWorkbook();
// 创建工作表
Sheet sheet = workbook.createSheet("用户信息");
// 创建表头行
Row headerRow = sheet.createRow(0);
String[] headers = {"姓名", "年龄", "性别"};
for (int i = 0; i < headers.length; i++) {
Cell cell = headerRow.createCell(i);
cell.setCellValue(headers[i]);
}
// 写入数据行
for (int i = 0; i < userList.size(); i++) {
User user = userList.get(i);
Row dataRow = sheet.createRow(i + 1);
dataRow.createCell(0).setCellValue(user.getName());
dataRow.createCell(1).setCellValue(user.getAge());
dataRow.createCell(2).setCellValue(user.getGender());
}
// 自动调整列宽
for (int i = 0; i < headers.length; i++) {
sheet.autoSizeColumn(i);
}
// 保存文件
try (FileOutputStream fileOut = new FileOutputStream("users.xlsx")) {
workbook.write(fileOut);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
workbook.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
classUser{
private String name;
privateint age;
private String gender;
publicUser(String name, int age, String gender){
this.name = name;
this.age = age;
this.gender = gender;
}
public String getName(){
return name;
}
publicintgetAge(){
return age;
}
public String getGender(){
return gender;
}
}
代码解释如下:
创建工作簿和工作表:使用XSSFWorkbook创建一个新的 Excel 工作簿对象,代表整个 Excel 文件 。然后通过工作簿的createSheet方法创建一个名为 “用户信息” 的工作表对象,工作表是工作簿中的一个页面,用于组织和展示数据 。
创建表头行:在工作表中创建第一行(索引为 0)作为表头行,通过循环创建单元格,并设置单元格的值为表头信息,如 “姓名”“年龄”“性别” 。这一步确定了 Excel 表格的列名和数据结构 。
写入数据行:通过循环遍历用户列表,为每个用户在工作表中创建一行数据 。在每一行中,根据用户对象的属性值,创建相应的单元格并设置其值,将用户的姓名、年龄和性别信息填充到对应的单元格中 。
自动调整列宽:使用工作表的autoSizeColumn方法,根据列中内容的长度自动调整每列的宽度,确保数据能够完整显示,不会出现内容被截断的情况 。这样可以使导出的 Excel 表格更加美观和易读 。
保存文件:使用FileOutputStream将工作簿写入到指定的文件路径 “users.xlsx” 中,将内存中的 Excel 数据保存到磁盘上,形成一个可访问和使用的 Excel 文件 。最后,关闭工作簿,释放资源 。
通过上述步骤,我们就可以使用 Apache POI 将数据成功导出为 Excel 文件 。在实际应用中,你可以根据具体需求,对代码进行扩展和优化,例如设置单元格样式、添加公式、处理复杂的数据结构等 。
三、使用 EasyExcel 导出 Excel 文件
(一)引入依赖
如果你使用的是 Maven 项目,在pom.xml文件中添加 EasyExcel 的依赖:
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.3.2</version>
</dependency>
</dependencies>
添加依赖后,Maven 会自动下载 EasyExcel 及其相关依赖包,为你的项目提供导出 Excel 文件的支持 。
(二)定义数据模型
创建一个 Java Bean 类,用于表示 Excel 表格中的数据 。通过@ExcelProperty注解来定义列名,指定字段与 Excel 表头的映射关系 。假设我们要导出用户信息,创建User类如下:
import com.alibaba.excel.annotation.ExcelProperty;
publicclassUser{
@ExcelProperty("姓名")
private String name;
@ExcelProperty("年龄")
private Integer age;
@ExcelProperty("性别")
private String gender;
// 省略构造函数、Getter和Setter方法
publicUser(String name, Integer age, String gender){
this.name = name;
this.age = age;
this.gender = gender;
}
public String getName(){
return name;
}
publicvoidsetName(String name){
this.name = name;
}
public Integer getAge(){
return age;
}
publicvoidsetAge(Integer age){
this.age = age;
}
public String getGender(){
return gender;
}
publicvoidsetGender(String gender){
this.gender = gender;
}
}
在上述代码中,使用@ExcelProperty注解为User类的每个字段指定了对应的 Excel 表头名称 。这样,在导出 Excel 文件时,EasyExcel 会根据这些注解自动生成表头,并将对象的属性值写入相应的单元格 。
(三)编写导出逻辑
下面通过示例代码展示如何使用 EasyExcel 将用户数据导出到 Excel 文件中 。
import com.alibaba.excel.EasyExcel;
import java.util.ArrayList;
import java.util.List;
publicclassEasyExcelExporter{
publicstaticvoidmain(String[] args){
// 模拟数据
List<User> userList = new ArrayList<>();
userList.add(new User("张三", 20, "男"));
userList.add(new User("李四", 22, "女"));
userList.add(new User("王五", 25, "男"));
// 导出文件路径
String fileName = "users_easyexcel.xlsx";
// 写入Excel文件
EasyExcel.write(fileName, User.class)
.sheet("用户信息")
.doWrite(userList);
System.out.println("Excel文件导出成功!");
}
}
代码解释如下:
创建数据列表:通过ArrayList创建一个用户列表userList,并添加了三个用户对象,模拟从数据库或其他数据源获取的数据 。
指定导出文件路径:定义fileName变量,指定导出的 Excel 文件路径为users_easyexcel.xlsx 。
使用 EasyExcel 写入文件:使用EasyExcel.write方法创建一个写入器,传入导出文件路径和数据模型类User.class 。然后通过sheet方法指定工作表名称为 “用户信息” ,最后调用doWrite方法,传入用户数据列表userList,将数据写入 Excel 文件 。
通过以上步骤,我们就可以使用 EasyExcel 轻松地将数据导出为 Excel 文件 。整个过程代码简洁明了,无需繁琐的单元格和工作表创建操作,大大提高了开发效率 。
四、处理大数据量的 Excel 导出
当数据量较大时,直接导出 Excel 可能会导致内存溢出等问题 。为了避免这些问题,我们可以采用分批写入和使用模板的方式来处理大数据量的 Excel 导出 。
(一)分批写入
分批写入数据的原理是将大数据集分成多个小批次,每次只将一小部分数据写入 Excel 文件 。这样可以避免一次性加载所有数据到内存中,从而减少内存的占用 。
在 EasyExcel 中实现分批写入的代码示例如下:
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import java.util.List;
publicclassBigDataExporter{
publicstaticvoidmain(String[] args){
// 假设 totalData 是你的大数据集
List<User> totalData = getTotalData();
int batchSize = 1000; // 每次写入1000条数据
String fileName = "big_data_export.xlsx";
ExcelWriter excelWriter = EasyExcel.write(fileName, User.class).build();
WriteSheet writeSheet = EasyExcel.writerSheet("数据").build();
for (int i = 0; i < totalData.size(); i += batchSize) {
int end = Math.min(i + batchSize, totalData.size());
List<User> batchData = totalData.subList(i, end);
excelWriter.write(batchData, writeSheet);
}
excelWriter.finish();
}
privatestatic List<User> getTotalData(){
// 模拟从数据库或其他数据源获取大数据集
List<User> data = new ArrayList<>();
// 这里添加数据的逻辑
return data;
}
}
在上述代码中,我们通过totalData.subList(i, end)方法从大数据集中获取每一批次的数据,然后使用excelWriter.write(batchData, writeSheet)方法将每批数据写入 Excel 文件 。这样就实现了分批写入,有效避免了一次性加载所有数据到内存的问题 。
(二)使用模板
使用模板的方式是预先创建一个包含表头的 Excel 模板文件,然后使用 EasyExcel 将数据追加到模板中 。这种方式可以减少内存占用,提高导出效率 。
具体步骤如下:
创建 Excel 模板:使用 Excel 软件创建一个 Excel 文件,在其中定义好表头、格式等内容 。例如,创建一个名为template.xlsx的模板文件,其中包含 “姓名”“年龄”“性别” 等表头 。
使用 EasyExcel 追加数据:在 Java 代码中,使用 EasyExcel 的withTemplate方法指定模板文件,然后将数据追加到模板中 。代码示例如下:
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.List;
publicclassTemplateExporter{
publicstaticvoidmain(String[] args){
// 假设 userList 是你的数据列表
List<User> userList = getUserList();
String templateFilePath = "template.xlsx";
String outputFilePath = "exported_data.xlsx";
try (InputStream inputStream = new FileInputStream(templateFilePath);
FileOutputStream outputStream = new FileOutputStream(outputFilePath)) {
ExcelWriter excelWriter = EasyExcel.write(outputStream)
.withTemplate(inputStream)
.build();
WriteSheet writeSheet = EasyExcel.writerSheet("数据").build();
excelWriter.write(userList, writeSheet);
excelWriter.finish();
} catch (Exception e) {
e.printStackTrace();
}
}
privatestatic List<User> getUserList(){
// 模拟从数据库或其他数据源获取数据列表
List<User> data = new ArrayList<>();
// 这里添加数据的逻辑
return data;
}
}
在上述代码中,通过EasyExcel.write(outputStream).withTemplate(inputStream)方法指定了模板文件,然后使用excelWriter.write(userList, writeSheet)方法将数据追加到模板中 。这种方式利用了模板文件已有的结构和格式,减少了在内存中构建整个 Excel 文件的开销,从而提高了导出效率,降低了内存占用 。
五、自定义 Excel 样式
在导出 Excel 文件时,为了使表格更加美观和专业,我们常常需要对 Excel 的样式进行自定义,如设置字体、颜色、对齐方式等 。下面我们分别来看一下如何使用 EasyExcel 和 Apache POI 进行自定义样式的设置 。
(一)EasyExcel 自定义样式
EasyExcel 提供了丰富的 API,通过实现CellWriteHandler接口,我们可以很方便地自定义 Excel 的样式 。下面是一个设置表头和内容样式的示例代码 :
import com.alibaba.excel.context.WriteContext;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import org.apache.poi.ss.usermodel.*;
import java.util.List;
publicclassCustomCellStyleHandlerimplementsCellWriteHandler{
@Override
publicvoidbeforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead){
// 可以在这里创建单元格时进行一些预处理操作
}
@Override
publicvoidafterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead){
// 可以在这里对新创建的单元格进行一些初始化操作
}
@Override
publicvoidafterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead){
// 可以在这里对转换后的数据进行一些操作
}
@Override
publicvoidafterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead){
Workbook workbook = writeSheetHolder.getSheet().getWorkbook();
if (isHead) {
// 表头样式
CellStyle cellStyle = workbook.createCellStyle();
Font font = workbook.createFont();
font.setFontName("黑体");
font.setFontHeightInPoints((short) 14);
font.setBold(true);
cellStyle.setFont(font);
cellStyle.setFillForegroundColor(IndexedColors.LIGHT_BLUE.getIndex());
cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
cellStyle.setAlignment(HorizontalAlignment.CENTER);
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
cell.setCellStyle(cellStyle);
} else {
// 内容样式
CellStyle cellStyle = workbook.createCellStyle();
Font font = workbook.createFont();
font.setFontName("宋体");
font.setFontHeightInPoints((short) 12);
cellStyle.setFont(font);
cellStyle.setAlignment(HorizontalAlignment.CENTER);
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
cell.setCellStyle(cellStyle);
}
}
}
在上述代码中,我们实现了CellWriteHandler接口,并重写了afterCellDispose方法 。在该方法中,我们根据isHead参数判断当前单元格是表头还是内容,然后分别设置不同的样式 。对于表头,我们设置了字体为黑体、字号 14、加粗、浅蓝色背景、水平和垂直居中对齐;对于内容,我们设置了字体为宋体、字号 12、水平和垂直居中对齐 。
使用自定义样式时,需要在导出 Excel 文件时注册该处理器 :
import com.alibaba.excel.EasyExcel;
import java.util.ArrayList;
import java.util.List;
publicclassStyleExporter{
publicstaticvoidmain(String[] args){
// 模拟数据
List<User> userList = new ArrayList<>();
userList.add(new User("张三", 20, "男"));
userList.add(new User("李四", 22, "女"));
userList.add(new User("王五", 25, "男"));
// 导出文件路径
String fileName = "styled_users.xlsx";
// 写入Excel文件并注册自定义样式处理器
EasyExcel.write(fileName, User.class)
.registerWriteHandler(newCustomCellStyleHandler())
.sheet("用户信息")
.doWrite(userList);
System.out.println("Excel文件导出成功!");
}
}
通过上述代码,我们在导出 Excel 文件时注册了CustomCellStyleHandler处理器,从而实现了自定义样式的设置 。
(二)Apache POI 自定义样式
Apache POI 通过创建CellStyle对象,并设置其属性,如字体、颜色、对齐方式、边框等,来实现自定义样式 。下面是一个简单的示例代码 :
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
publicclassPOIStyleExporter{
publicstaticvoidmain(String[] args){
// 模拟数据
List<User> userList = new ArrayList<>();
userList.add(new User("张三", 20, "男"));
userList.add(new User("李四", 22, "女"));
userList.add(new User("王五", 25, "男"));
// 创建工作簿
Workbook workbook = new XSSFWorkbook();
// 创建工作表
Sheet sheet = workbook.createSheet("用户信息");
// 创建表头行样式
CellStyle headerStyle = workbook.createCellStyle();
Font headerFont = workbook.createFont();
headerFont.setFontName("黑体");
headerFont.setFontHeightInPoints((short) 14);
headerFont.setBold(true);
headerStyle.setFont(headerFont);
headerStyle.setFillForegroundColor(IndexedColors.LIGHT_BLUE.getIndex());
headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
headerStyle.setAlignment(HorizontalAlignment.CENTER);
headerStyle.setVerticalAlignment(VerticalAlignment.CENTER);
// 创建表头行
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);
}
// 创建内容行样式
CellStyle contentStyle = workbook.createCellStyle();
Font contentFont = workbook.createFont();
contentFont.setFontName("宋体");
contentFont.setFontHeightInPoints((short) 12);
contentStyle.setFont(contentFont);
contentStyle.setAlignment(HorizontalAlignment.CENTER);
contentStyle.setVerticalAlignment(VerticalAlignment.CENTER);
// 写入数据行
for (int i = 0; i < userList.size(); i++) {
User user = userList.get(i);
Row dataRow = sheet.createRow(i + 1);
dataRow.createCell(0).setCellValue(user.getName());
dataRow.createCell(1).setCellValue(user.getAge());
dataRow.createCell(2).setCellValue(user.getGender());
// 应用内容行样式
for (int j = 0; j < headers.length; j++) {
dataRow.getCell(j).setCellStyle(contentStyle);
}
}
// 自动调整列宽
for (int i = 0; i < headers.length; i++) {
sheet.autoSizeColumn(i);
}
// 保存文件
try (FileOutputStream fileOut = new FileOutputStream("poi_styled_users.xlsx")) {
workbook.write(fileOut);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
workbook.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
在上述代码中,我们分别创建了表头行样式和内容行样式,然后在创建表头行和数据行时,将相应的样式应用到单元格上 。
与 EasyExcel 相比,Apache POI 的自定义样式方式更加底层,需要手动创建和设置CellStyle、Font等对象,代码相对繁琐 。而 EasyExcel 通过实现接口的方式,将样式设置的逻辑封装在处理器中,代码更加简洁和易于维护 。但在一些复杂的样式需求场景下,Apache POI 由于其更底层的操作方式,可能会具有更高的灵活性 。
六、总结与展望
在 Java 开发中,导出 Excel 文件是一个常见且实用的功能。通过本文,我们详细介绍了 Java 中导出 Excel 的常用工具 Apache POI 和 EasyExcel ,并给出了具体的使用示例 。同时,还探讨了如何处理大数据量的 Excel 导出以及如何自定义 Excel 的样式 。
Apache POI 作为一个强大的操作 Microsoft Office 格式文件的 API,提供了丰富的功能和灵活的操作方式,能够满足各种复杂的 Excel 操作需求 。而 EasyExcel 则在 Apache POI 的基础上进行了封装,简化了 Excel 数据的读写操作,特别适合处理大量数据的导入导出,具有高性能、简单易用、占用内存小等优点 。
在实际项目中,我们应根据具体的需求和场景选择合适的工具和方法 。如果数据量较小,对 Excel 的样式和格式要求较高,且需要进行复杂的操作,那么 Apache POI 可能是一个不错的选择 。而当数据量较大,对性能和内存占用有较高要求时,EasyExcel 则更具优势 。
随着技术的不断发展,相信未来会有更多更优秀的 Excel 处理工具和技术出现,为我们的开发工作带来更多的便利 。希望大家在实际项目中能够灵活运用所学知识,不断探索和实践,解决各种实际问题 。如果在导出 Excel 的过程中遇到任何问题,欢迎在评论区留言交流 。