以下代码直接复制粘贴就能直接看见效果(使用 EasyExcel 实现 点这里)
- 测试实体类
@Data
public class AttendanceRecordExcelTest {
@ExcelProperty(value = "用户名")
@ApiModelProperty(value = "用户名")
private String userName;
@ExcelProperty(value = "上班打卡时间")
@ApiModelProperty(value = "上班打卡时间")
@DateTimeFormat(value = "yyyy-MM-dd HH:mm:ss")
private Date morningPunch;
@ExcelProperty(value = "拜访时间")
@ApiModelProperty(value = "拜访时间")
@DateTimeFormat(value = "yyyy-MM-dd HH:mm:ss")
private Date visitTime;
@ExcelProperty(value = "拜访客户")
@ApiModelProperty(value = "拜访客户")
private String customer;
@ExcelProperty(value = "拜访备注")
@ApiModelProperty(value = "拜访备注")
private String visitNotes;
@ExcelProperty(value = "下班打卡时间")
@ApiModelProperty(value = "下班打卡时间")
@DateTimeFormat(value = "yyyy-MM-dd HH:mm:ss")
private Date eveningPunch;
public AttendanceRecordExcelTest(String userName, Date morningPunch, Date visitTime, String customer, String visitNotes, Date eveningPunch) {
this.userName = userName;
this.morningPunch = morningPunch;
this.visitTime = visitTime;
this.customer = customer;
this.visitNotes = visitNotes;
this.eveningPunch = eveningPunch;
}
}
- 合并单元格处理器
import io.swagger.annotations.ApiModelProperty;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import java.lang.reflect.Field;
import java.util.Date;
import java.util.List;
import java.util.Objects;
public class ApacheMergeColumnHandler {
/**
* 合并指定列的单元格。
*
* @param sheet 要合并单元格的工作表。
* @param columnsToMerge 要合并的列的索引列表。
*/
public static void mergeColumns(Sheet sheet, int... columnsToMerge) {
for (int columnIndex : columnsToMerge) {
mergeColumn(sheet, columnIndex);
}
}
/**
* 合并所有列的单元格。
*
* @param sheet 要合并单元格的工作表。
*/
public static void mergeColumns(Sheet sheet) {
int columnCount = sheet.getRow(0).getLastCellNum();
int[] allColumns = new int[columnCount];
for (int i = 0; i < columnCount; i++) {
allColumns[i] = i;
}
mergeColumns(sheet, allColumns);
}
/**
* 合并单个列的单元格。
*
* @param sheet 工作表。
* @param columnIndex 要合并的列索引。
*/
private static void mergeColumn(Sheet sheet, int columnIndex) {
int lastRow = sheet.getLastRowNum();
if (lastRow < 1) return;
Object previousValue = getCellValue(sheet.getRow(0).getCell(columnIndex));
int startRow = 0;
for (int rowIndex = 1; rowIndex <= lastRow; rowIndex++) {
Row currentRow = sheet.getRow(rowIndex);
Object currentValue = getCellValue(currentRow.getCell(columnIndex));
if (!Objects.equals(previousValue, currentValue)) {
if (rowIndex - 1 > startRow) {
mergeCells(sheet, startRow, rowIndex - 1, columnIndex);
}
startRow = rowIndex;
previousValue = currentValue;
}
}
if (lastRow > startRow) {
mergeCells(sheet, startRow, lastRow, columnIndex);
}
}
/**
* 合并单元格。
*
* @param sheet 工作表。
* @param startRow 起始行。
* @param endRow 结束行。
* @param column 列索引。
*/
private static void mergeCells(Sheet sheet, int startRow, int endRow, int column) {
sheet.addMergedRegion(new CellRangeAddress(startRow, endRow, column, column));
}
/**
* 写入Excel表头。
* 通过反射获取类的字段信息,并根据字段上的ApiModelProperty注解或字段名写入表头。
*
* @param sheet Excel中的工作表。
* @param centeredStyle 设置单元格居中样式的CellStyle对象。
* @param clazz 需要反射获取字段信息的类。
*/
public static <T> void writeHeader(Sheet sheet, CellStyle centeredStyle, Class<T> clazz) {
Row headerRow = sheet.createRow(0);
Field[] fields = clazz.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
Cell cell = headerRow.createCell(i);
ApiModelProperty annotation = fields[i].getAnnotation(ApiModelProperty.class);
cell.setCellValue(annotation != null ? annotation.value() : fields[i].getName());
cell.setCellStyle(centeredStyle);
}
}
/**
* 写入Excel内容。
* 通过反射获取类的字段值并写入到Excel单元格中。
*
* @param sheet Excel中的工作表。
* @param records 需要写入Excel的记录列表。
* @param centeredStyle 设置单元格居中样式的CellStyle对象。
* @param dateStyle 设置日期单元格样式的CellStyle对象。
* @param clazz 需要反射获取字段信息的类。
*/
public static <T> void writeContent(Sheet sheet, List<T> records, CellStyle centeredStyle, CellStyle dateStyle, Class<T> clazz) {
Field[] fields = clazz.getDeclaredFields();
int rowIndex = 1;
for (T record : records) {
Row row = sheet.createRow(rowIndex++);
for (int i = 0; i < fields.length; i++) {
fields[i].setAccessible(true);
try {
Object value = fields[i].get(record);
createCell(row, i, value, value instanceof Date ? dateStyle : centeredStyle);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
/**
* 创建一个用于表示日期的单元格样式。
*
* @param workbook 工作簿对象,用于创建单元格样式和数据格式。
* @return 创建的单元格样式对象,用于显示日期。
*/
public static CellStyle getDateStyle(Workbook workbook, String format) {
CellStyle dateStyle = workbook.createCellStyle();
DataFormat dateFormat = workbook.createDataFormat();
dateStyle.setDataFormat(dateFormat.getFormat(format));
dateStyle.setAlignment(HorizontalAlignment.CENTER);
dateStyle.setVerticalAlignment(VerticalAlignment.CENTER);
return dateStyle;
}
/**
* 根据给定的参数在指定的行中创建一个单元格,并设置其值和样式。
*
* @param row 要创建单元格的行。
* @param column 单元格的列索引。
* @param value 单元格的值。
* @param style 单元格的样式。
*/
private static void createCell(Row row, int column, Object value, CellStyle style) {
Cell cell = row.createCell(column);
if (value instanceof Date) {
cell.setCellValue((Date) value);
} else if (value instanceof String) {
cell.setCellValue((String) value);
}
cell.setCellStyle(style);
}
}
/**
* 获取单元格的值。
* 此方法根据单元格的类型,返回对应类型的值。支持的类型包括字符串、数字、日期、布尔值和公式。
* 如果单元格为null,则返回null。对于日期类型,使用了Apache POI提供的DateUtil工具类来判断。
*
* @param cell 单元格对象,不能为空。
* @return 单元格的值,根据单元格类型返回对应类型的值,如果单元格为null,则返回null。
*/
public static Object getCellValue(Cell cell) {
if (cell == null) {
return null;
}
switch (cell.getCellType()) {
case STRING:
return cell.getStringCellValue();
case NUMERIC:
return DateUtil.isCellDateFormatted(cell) ? cell.getDateCellValue() : cell.getNumericCellValue();
case BOOLEAN:
return cell.getBooleanCellValue();
case FORMULA:
return cell.getCellFormula();
default:
return null;
}
}
- 样式处理器
import org.apache.poi.ss.usermodel.*;
public class CenterAlignCellStyleStrategyApache {
/**
* 获取一个中心对齐样式的单元格样式。
* 该方法创建并配置了一个新的单元格样式,用于在Excel表格中实现文本和数字的中心对齐显示。
* 同时,设置了单元格的边框为细边框,以提高表格的可读性。
*
* @param workbook 正在被操作的Excel工作簿对象,用于创建新的单元格样式。
* @return 返回一个已配置好的,用于中心对齐显示的单元格样式。
*/
public static CellStyle getCenterAlignStyle(Workbook workbook) {
// 创建一个新的单元格样式对象
CellStyle style = workbook.createCellStyle();
// 配置单元格内容水平方向和垂直方向都居中对齐
style.setAlignment(HorizontalAlignment.CENTER);
style.setVerticalAlignment(VerticalAlignment.CENTER);
// 启用文本自动换行,以适应单元格宽度
style.setWrapText(true);
// 设置单元格四边的边框样式为细边框
style.setBorderLeft(BorderStyle.THIN);
style.setBorderTop(BorderStyle.THIN);
style.setBorderRight(BorderStyle.THIN);
style.setBorderBottom(BorderStyle.THIN);
// 返回配置好的单元格样式
return style;
}
}
- main 测试
public static void main(String[] args) {
List<AttendanceRecordExcelTest> processedRecords = new ArrayList<>();
// processedRecords 定义测试数据
processedRecords.add(new AttendanceRecordExcelTest("刘备", new Date(), new Date(), "秦始皇", "统一六国", new Date()));
processedRecords.add(new AttendanceRecordExcelTest("刘备", new Date(), new Date(), "秦始皇", "统一文字", new Date()));
processedRecords.add(new AttendanceRecordExcelTest("关羽", new Date(), new Date(), "曹操", "官渡之战,诛杀颜良,解白马之围,受封汉寿亭侯", new Date()));
processedRecords.add(new AttendanceRecordExcelTest("张飞", new Date(), new Date(), "张郃", "巴西之战败张郃", new Date()));
processedRecords.add(new AttendanceRecordExcelTest("赵云", new Date(), new Date(), "刘备", "单骑救主", new Date()));
processedRecords.add(new AttendanceRecordExcelTest("赵云", new Date(), new Date(), "刘备", "七进七出救阿斗", new Date()));
processedRecords.add(new AttendanceRecordExcelTest("黄忠", new Date(), new Date(), "刘备", "助刘备攻破益州刘璋", new Date()));
String filePath = "F:\\ChromeDownloadLocation\\test1.xlsx";
try (Workbook workbook = new XSSFWorkbook()) {
Sheet sheet = workbook.createSheet("Sheet1");
// 设置样式处理器
CellStyle centeredStyle = ApacheCenterAlignCellStyleStrategy.getCenterAlignStyle(workbook);
// 设置日期的单元格样式
CellStyle dateStyle = ApacheMergeColumnHandler.getDateStyle(workbook, "yyyy-MM-dd HH:mm:ss");
// 写入表头
ApacheMergeColumnHandler.writeHeader(sheet, centeredStyle, MergeCellsExcelDto.class);
// 写入内容
ApacheMergeColumnHandler.writeContent(sheet, processedRecords, centeredStyle, dateStyle, MergeCellsExcelDto.class);
// 合并所有列
// ApacheMergeColumnHandler.mergeColumns(sheet);
// 合并指定列
ApacheMergeColumnHandler.mergeColumns(sheet, 0, 1);
try (FileOutputStream out = new FileOutputStream(Paths.get(filePath).toFile())) {
workbook.write(out);
}
System.out.println("Processed data exported successfully to " + filePath);
} catch (IOException e) {
e.printStackTrace();
}
}
-
默认效果
-
指定列合并效果
-
全部列合并效果