基于Apache POI
实现一个通用的Java工具类来读取和生成Excel文件,并将数据封装为Java对象,需要考虑.xls
和.xlsx
两种格式。
步骤1: 添加依赖
添加Apache POI的依赖:
<!-- Apache POI for .xls and .xlsx files -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.2</version>
</dependency>
步骤2: 定义Java对象
定义一个Java对象,用于映射Excel中的数据:
@Data
public class Employee {
private String name; // 员工姓名
private int age; // 员工年龄
private String department; // 员工部门
}
步骤3: 创建通用的Excel工具类
创建一个工具类,实现读取和写入Excel的方法:
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import java.io.*;
import java.lang.reflect.Field;
import java.util.*;
public class ExcelUtil {
/**
* 读取Excel文件并转换为Java对象列表。
*
* @param file Excel文件。
* @param clazz 要转换为的对象类型。
* @param <T> 对象类型。
* @return 对象列表。
* @throws IOException 如果读取文件时发生I/O异常。
*/
public static <T> List<T> readExcel(File file, Class<T> clazz) throws IOException {
Workbook workbook = null;
FileInputStream fis = new FileInputStream(file);
try {
if (file.getName().endsWith(".xls")) {
workbook = new HSSFWorkbook(fis); // 用于旧版Excel文件(.xls)
} else if (file.getName().endsWith(".xlsx")) {
workbook = new XSSFWorkbook(fis); // 用于新版Excel文件(.xlsx)
}
} finally {
fis.close();
}
List<T> resultList = new ArrayList<>();
Sheet sheet = workbook.getSheetAt(0); // 只读取第一个工作表
Iterator<Row> rowIterator = sheet.rowIterator();
Map<Integer, Field> fieldsMap = getFieldsMap(clazz);
Row firstRow = rowIterator.next(); // 跳过标题行
while (rowIterator.hasNext()) {
Row currentRow = rowIterator.next();
T obj = clazz.newInstance(); // 创建对象实例
for (Cell cell : currentRow) {
Field field = fieldsMap.get(cell.getColumnIndex());
if (field != null) {
Object value = getCellValue(cell, field.getType());
field.setAccessible(true);
field.set(obj, value);
}
}
resultList.add(obj);
}
workbook.close();
return resultList;
}
/**
* 将Java对象列表写入Excel文件。
*
* @param list 对象列表。
* @param file 要写入的Excel文件。
* @param clazz 对象类型。
* @param <T> 对象类型。
* @throws IOException 如果写入文件时发生I/O异常。
*/
public static <T> void writeExcel(List<T> list, File file, Class<T> clazz) throws IOException {
Workbook workbook = new XSSFWorkbook(); // 创建工作簿
Sheet sheet = workbook.createSheet("Sheet1"); // 创建工作表
// 写入标题行
Row titleRow = sheet.createRow(0);
Map<Integer, Field> fieldsMap = getFieldsMap(clazz);
for (int i = 0; i < fieldsMap.size(); i++) {
Field field = fieldsMap.get(i);
titleRow.createCell(i).setCellValue(field.getName());
}
int rowNum = 1; // 从第二行开始写入数据
for (T obj : list) {
Row row = sheet.createRow(rowNum++);
for (int i = 0; i < fieldsMap.size(); i++) {
Field field = fieldsMap.get(i);
field.setAccessible(true);
Object value = field.get(obj);
Cell cell = row.createCell(i);
setCellValue(cell, value);
}
}
try (FileOutputStream fos = new FileOutputStream(file)) {
workbook.write(fos); // 写入文件
}
}
/**
* 获取对象所有字段与其在Excel中列的映射关系。
*
* @param clazz 对象类型。
* @return 字段与其列索引的映射。
*/
private static <T> Map<Integer, Field> getFieldsMap(Class<T> clazz) {
Map<Integer, Field> fieldsMap = new HashMap<>();
Field[] fields = clazz.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
fieldsMap.put(i, fields[i]);
}
return fieldsMap;
}
/**
* 根据字段类型获取单元格的值。
*
* @param cell 单元格。
* @param type 字段类型。
* @return 单元格的值。
*/
private static Object getCellValue(Cell cell, Class<?> type) {
switch (cell.getCellType()) {
case STRING:
return cell.getStringCellValue();
case NUMERIC:
return cell.getNumericCellValue();
case BOOLEAN:
return cell.getBooleanCellValue();
default:
return null;
}
}
/**
* 将值设置到单元格中。
*
* @param cell 单元格。
* @param value 值。
*/
private static void setCellValue(Cell cell, Object value) {
if (value instanceof String) {
cell.setCellValue((String) value);
} else if (value instanceof Integer) {
cell.setCellValue((Integer) value);
} else if (value instanceof Double) {
cell.setCellValue((Double) value);
} else if (value instanceof Boolean) {
cell.setCellValue((Boolean) value);
} else {
cell.setCellValue(value.toString());
}
}
}
readExcel
: 读取Excel文件并将每一行数据映射到指定的Java对象中,返回一个对象列表。writeExcel
: 接受一个对象列表和Excel文件路径,将对象列表写入到Excel文件中。getFieldsMap
: 获取类的所有字段及其在Excel中的列索引的映射关系,用于在读取和写入时定位字段。getCellValue
: 根据单元格的类型获取其值。setCellValue
: 将值设置到单元格中,根据值的类型选择合适的单元格类型。
步骤四:使用Excel工具类
使用ExcelUtil
类来读取和写入Excel文件:
public class Application {
public static void main(String[] args) {
try {
// 读取Excel文件,支持.xls和.xlsx格式
List<Employee> employees = ExcelUtil.readExcel(new File("employees.xls"), Employee.class);
for (Employee emp : employees) {
System.out.println(emp);
}
// 创建要写入Excel的员工数据列表
List<Employee> newEmployees = new ArrayList<>();
// 写入Excel文件
ExcelUtil.writeExcel(newEmployees, new File("output.xlsx"), Employee.class);
} catch (IOException e) {
e.printStackTrace();
}
}
}