qidao123.com技术社区-IT企服评测·应用市场
标题:
Easyexcel(6-单位格合并)
[打印本页]
作者:
饭宝
时间:
2025-3-8 16:14
标题:
Easyexcel(6-单位格合并)
注解
@ContentLoopMerge
用于设置合并单位格的注解,作用于字段上
eachRow:每隔几行合并
columnExtend:合并列的下标
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User {
@ContentLoopMerge(eachRow = 2, columnExtend = 1)
@ExcelProperty(value = "用户Id")
private Integer userId;
@ExcelProperty(value = "姓名")
private String name;
@ExcelProperty(value = "手机")
private String phone;
@ExcelProperty(value = "邮箱")
private String email;
@ExcelProperty(value = "创建时间")
private Date createTime;
}
复制代码
@OnceAbsoluteMerge
用于指定位置的单位格合并,作用于类上
firstRowIndex:第一行下标
lastRowIndex:最后一行下标
firstColumnIndex:第一列下标
lastColumnIndex:最后一列下标
@OnceAbsoluteMerge(firstColumnIndex = 0, lastColumnIndex = 0, firstRowIndex = 1, lastRowIndex = 2)
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User {
@ExcelProperty(value = "用户Id")
private Integer userId;
@ExcelProperty(value = "姓名")
private String name;
@ExcelProperty(value = "手机")
private String phone;
@ExcelProperty(value = "邮箱")
private String email;
@ExcelProperty(value = "创建时间")
private Date createTime;
}
复制代码
类方法
LoopMergeStrategy
源码查看
public class LoopMergeStrategy implements RowWriteHandler {
// 每隔几行合并
private final int eachRow;
// 合并几列
private final int columnExtend;
// 合并列
private final int columnIndex;
public LoopMergeStrategy(int eachRow, int columnIndex) {
this(eachRow, 1, columnIndex);
}
public LoopMergeStrategy(int eachRow, int columnExtend, int columnIndex) {
if (eachRow < 1) {
throw new IllegalArgumentException("EachRows must be greater than 1");
}
if (columnExtend < 1) {
throw new IllegalArgumentException("ColumnExtend must be greater than 1");
}
if (columnExtend == 1 && eachRow == 1) {
throw new IllegalArgumentException("ColumnExtend or eachRows must be greater than 1");
}
if (columnIndex < 0) {
throw new IllegalArgumentException("ColumnIndex must be greater than 0");
}
this.eachRow = eachRow;
this.columnExtend = columnExtend;
this.columnIndex = columnIndex;
}
public LoopMergeStrategy(LoopMergeProperty loopMergeProperty, Integer columnIndex) {
this(loopMergeProperty.getEachRow(), loopMergeProperty.getColumnExtend(), columnIndex);
}
@Override
public void afterRowDispose(RowWriteHandlerContext context) {
// 判断是否为表头
if (context.getHead() || context.getRelativeRowIndex() == null) {
return;
}
// 循环进行单元格合并
if (context.getRelativeRowIndex() % eachRow == 0) {
CellRangeAddress cellRangeAddress = new CellRangeAddress(context.getRowIndex(),
context.getRowIndex() + eachRow - 1,
columnIndex, columnIndex + columnExtend - 1);
context.getWriteSheetHolder().getSheet().addMergedRegionUnsafe(cellRangeAddress);
}
}
}
复制代码
根本使用
通过 registerWriteHandler 方法设置单位格合并策略,用于指定某几列每相差几行进行单位格合并
指定单列合并
@GetMapping("/download1")
public void download1(HttpServletResponse response) {
try {
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xls");
User user1 = new User();
user1.setUserId(123);
user1.setName("as");
user1.setPhone("15213");
user1.setEmail("5456");
user1.setCreateTime(new Date());
User user2 = new User();
user2.setUserId(123);
user2.setName("asbnm");
user2.setPhone("15213");
user2.setEmail("5456");
user2.setCreateTime(new Date());
User user3 = new User();
user3.setUserId(123);
user3.setName("as");
user3.setPhone("46543213");
user3.setEmail("5456");
user3.setCreateTime(new Date());
// 第1列每隔2行合并一次
LoopMergeStrategy loopMergeStrategy = new LoopMergeStrategy(2, 0);
EasyExcel.write(response.getOutputStream(), User.class)
.registerWriteHandler(loopMergeStrategy)
.sheet("模板")
.doWrite(Arrays.asList(user1, user2, user3));
} catch (Exception e) {
e.printStackTrace();
}
}
复制代码
指定多列合并
@GetMapping("/download1")
public void download1(HttpServletResponse response) {
try {
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xls");
User user1 = new User();
user1.setUserId(123);
user1.setName("as");
user1.setPhone("15213");
user1.setEmail("5456");
user1.setCreateTime(new Date());
User user2 = new User();
user2.setUserId(123);
user2.setName("asbnm");
user2.setPhone("15213");
user2.setEmail("5456");
user2.setCreateTime(new Date());
User user3 = new User();
user3.setUserId(123);
user3.setName("as");
user3.setPhone("46543213");
user3.setEmail("5456");
user3.setCreateTime(new Date());
// 第2列开始每隔2行合并一次,从第2列开始的两列进行合并
LoopMergeStrategy loopMergeStrategy = new LoopMergeStrategy(2, 2, 2);
EasyExcel.write(response.getOutputStream(), User.class)
.registerWriteHandler(loopMergeStrategy)
.sheet("模板")
.doWrite(Arrays.asList(user1, user2, user3));
} catch (Exception e) {
e.printStackTrace();
}
}
复制代码
OnceAbsoluteMergeStrategy
源码查看
public class OnceAbsoluteMergeStrategy implements SheetWriteHandler {
// 第一行
private final int firstRowIndex;
// 最后一行
private final int lastRowIndex;
// 第一列
private final int firstColumnIndex;
// 最后一列
private final int lastColumnIndex;
public OnceAbsoluteMergeStrategy(int firstRowIndex, int lastRowIndex, int firstColumnIndex, int lastColumnIndex) {
if (firstRowIndex < 0 || lastRowIndex < 0 || firstColumnIndex < 0 || lastColumnIndex < 0) {
throw new IllegalArgumentException("All parameters must be greater than 0");
}
this.firstRowIndex = firstRowIndex;
this.lastRowIndex = lastRowIndex;
this.firstColumnIndex = firstColumnIndex;
this.lastColumnIndex = lastColumnIndex;
}
public OnceAbsoluteMergeStrategy(OnceAbsoluteMergeProperty onceAbsoluteMergeProperty) {
this(onceAbsoluteMergeProperty.getFirstRowIndex(), onceAbsoluteMergeProperty.getLastRowIndex(),
onceAbsoluteMergeProperty.getFirstColumnIndex(), onceAbsoluteMergeProperty.getLastColumnIndex());
}
@Override
public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
CellRangeAddress cellRangeAddress =
new CellRangeAddress(firstRowIndex, lastRowIndex, firstColumnIndex, lastColumnIndex);
writeSheetHolder.getSheet().addMergedRegionUnsafe(cellRangeAddress);
}
}
复制代码
根本使用
通过 registerWriteHandler 方法设置单位格合并策略,用于指定一个区域内的单位格进行合并
@GetMapping("/download2")
public void download2(HttpServletResponse response) {
try {
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xls");
User user1 = new User();
user1.setUserId(123);
user1.setName("as");
user1.setPhone("15213");
user1.setEmail("5456");
user1.setCreateTime(new Date());
User user2 = new User();
user2.setUserId(123);
user2.setName("asbnm");
user2.setPhone("15213");
user2.setEmail("5456");
user2.setCreateTime(new Date());
User user3 = new User();
user3.setUserId(123);
user3.setName("as");
user3.setPhone("46543213");
user3.setEmail("5456");
user3.setCreateTime(new Date());
// 从第1行第3列合并到第3行第3列
OnceAbsoluteMergeStrategy onceAbsoluteMergeStrategy = new OnceAbsoluteMergeStrategy(0, 2, 2, 2);
EasyExcel.write(response.getOutputStream(), User.class)
.registerWriteHandler(onceAbsoluteMergeStrategy)
.sheet("模板")
.doWrite(Arrays.asList(user1, user2, user3));
} catch (Exception e) {
e.printStackTrace();
}
}
复制代码
合并单位格工具类
AbstractMergeStrategy
根本思路
继续 AbstractMergeStrategy 抽象合并策略,重写 merge 方法
传入要合并的数据列表,循环判定上下行是否是相同的数据,如果是则为同一个组,否则为另一个组,使用 List 生存每个组的数目
单位格渲染时,循环遍历每个组的值后,计算要合并的单位格的上下标
使用
/**
* 自定义合并策略 该类继承了AbstractMergeStrategy抽象合并策略,需要重写merge()方法
*/
public class CustomMergeStrategy extends AbstractMergeStrategy {
/**
* 分组,每几行合并一次
*/
private List<Integer> exportFieldGroupCountList;
/**
* 目标合并列index
*/
private Integer targetColumnIndex;
/**
* 需要开始合并单元格的首行index
*/
private Integer rowIndex;
public CustomMergeStrategy(List<String> exportDataList, Integer targetColumnIndex, Integer rowIndex) {
this.exportFieldGroupCountList = getGroupCountList(exportDataList, rowIndex);
this.targetColumnIndex = targetColumnIndex;
this.rowIndex = rowIndex;
}
// 该方法将目标列根据值是否相同连续可合并,存储可合并的行数
private List<Integer> getGroupCountList(List<String> exportDataList, Integer rowIndex) {
if (CollectionUtils.isEmpty(exportDataList)) {
return new ArrayList<>();
}
List<Integer> groupCountList = new ArrayList<>();
int count = 1;
for (int i = rowIndex + 1, len = exportDataList.size(); i < len; i++) {
// 判断上一列和当前列的值是否相同
if (exportDataList.get(i).equals(exportDataList.get(i - 1))) {
count++;
} else {
groupCountList.add(count);
count = 1;
}
}
// 处理完最后一条后
groupCountList.add(count);
return groupCountList;
}
@Override
protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {
if (null == rowIndex) {
rowIndex = cell.getRowIndex();
}
// 仅从首行以及目标列的单元格开始合并,忽略其他
if (cell.getRowIndex() == rowIndex + 1 && cell.getColumnIndex() == targetColumnIndex) {
mergeGroupColumn(sheet);
}
}
private void mergeGroupColumn(Sheet sheet) {
int rowCount = rowIndex + 1;
for (Integer count : exportFieldGroupCountList) {
if (count == 1) {
rowCount += count;
continue;
}
// 合并单元格
CellRangeAddress cellRangeAddress = new CellRangeAddress(rowCount, rowCount + count - 1, targetColumnIndex, targetColumnIndex);
sheet.addMergedRegionUnsafe(cellRangeAddress);
rowCount += count;
}
}
}
复制代码
从首行开始合并单位格
@GetMapping("/download3")
public void download3(HttpServletResponse response) {
try {
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xls");
User user1 = new User();
user1.setUserId(123);
user1.setName("as");
user1.setPhone("15213");
user1.setEmail("5456");
user1.setCreateTime(new Date());
User user2 = new User();
user2.setUserId(123);
user2.setName("asbnm");
user2.setPhone("15213");
user2.setEmail("5456");
user2.setCreateTime(new Date());
User user3 = new User();
user3.setUserId(123);
user3.setName("as");
user3.setPhone("46543213");
user3.setEmail("5456");
user3.setCreateTime(new Date());
List<User> userList = Arrays.asList(user1, user2, user3);
CustomMergeStrategy customMergeStrategy = new CustomMergeStrategy(userList.stream().map(e ->
String.valueOf(e.getUserId())).collect(Collectors.toList()), 0, 0);
EasyExcel.write(response.getOutputStream(), User.class)
.registerWriteHandler(customMergeStrategy)
.sheet("模板")
.doWrite(userList);
} catch (Exception e) {
e.printStackTrace();
}
}
复制代码
从指定行开始合并单位格
@GetMapping("/download3")
public void download3(HttpServletResponse response) {
try {
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xls");
User user1 = new User();
user1.setUserId(123);
user1.setName("as");
user1.setPhone("15213");
user1.setEmail("5456");
user1.setCreateTime(new Date());
User user2 = new User();
user2.setUserId(123);
user2.setName("asbnm");
user2.setPhone("15213");
user2.setEmail("5456");
user2.setCreateTime(new Date());
User user3 = new User();
user3.setUserId(123);
user3.setName("as");
user3.setPhone("46543213");
user3.setEmail("5456");
user3.setCreateTime(new Date());
List<User> userList = Arrays.asList(user1, user2, user3);
CustomMergeStrategy customMergeStrategy = new CustomMergeStrategy(userList.stream().map(e ->
String.valueOf(e.getUserId())).collect(Collectors.toList()), 0, 1);
EasyExcel.write(response.getOutputStream(), User.class)
.registerWriteHandler(customMergeStrategy)
.sheet("模板")
.doWrite(userList);
} catch (Exception e) {
e.printStackTrace();
}
}
复制代码
CellWriteHandler
根本思路
实现 CellWriteHandler 类的 afterCellDispose 方法,在每个单位格完全创建完之后执行合并单位格操作
判定当前列是否为要合并的列,且当前行是否已经到达要操作的行数
如果是,则判定上一行和当前行的数据是否一致,且序号是否一致
如果是,则进行合并单位格操作,如果上一行已经被合并过了,则进行移除,然后再重新合并单位格
使用
[code]/** * excel合并单位格导出工具类 */public class EasyExcelUtil implements CellWriteHandler { /** * 需要合并的列 */ private int[] mergeColumnIndex; /** * 从哪一行开始合并 */ private int mergeRowIndex; public EasyExcelUtil() { } public EasyExcelUtil(int mergeRowIndex, int[] mergeColumnIndex) { this.mergeRowIndex = mergeRowIndex; this.mergeColumnIndex = mergeColumnIndex; } /** * 创建每个单位格之前执行 * * @param writeSheetHolder * @param writeTableHolder * @param row * @param head * @param columnIndex * @param relativeRowIndex * @param isHead */ @Override public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) { CellWriteHandler.super.beforeCellCreate(writeSheetHolder, writeTableHolder, row, head, columnIndex, relativeRowIndex, isHead); } /** * 每个单位格数据内容渲染之后执行 * * @param writeSheetHolder * @param writeTableHolder * @param cellData * @param cell * @param head * @param relativeRowIndex * @param isHead */ @Override public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, WriteCellData cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { CellWriteHandler.super.afterCellDataConverted(writeSheetHolder, writeTableHolder, cellData, cell, head, relativeRowIndex, isHead); } /** * 每个单位格完全创建完之后执行 * * @param writeSheetHolder * @param writeTableHolder * @param cellDataList * @param cell * @param head * @param relativeRowIndex * @param isHead */ @Override public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List
欢迎光临 qidao123.com技术社区-IT企服评测·应用市场 (https://dis.qidao123.com/)
Powered by Discuz! X3.4