若依导出excel,合并单元格
需求描述 :表格中订单对应的商品和运单为list,且商品和运单数量不一致,展示时候以多的条目为行数,少的展示空行。具体如下图所示
若依中整合POI的工具类无法满足如下需求
在自定义注解 Excel 中添加字段
/**
* 是否需要合并行 与 needMerge 以及 子列表不兼容
*/
public boolean lineMerge() default false;
/**
* 合并行的依据的主键
*/
public boolean lineMergeId() default false;
修改 ExcelUtil.fillExcelData方法
public void fillExcelData(int index, Row row) {
int startNo = index * sheetSize;
int endNo = Math.min(startNo + sheetSize, list.size());
int rowNo = (1 + rownum) - startNo;
String objIdValve = "";//注解中 lineMergeId 为true的value 合并单元格使用
int mergeStartRow = 0;//合并单元格 起始行
for (int i = startNo; i < endNo; i++) {
rowNo = isSubList() ? (i > 1 ? rowNo + 1 : rowNo + i) : i + 1 + rownum - startNo;
row = sheet.createRow(rowNo);
// 得到导出对象.
T vo = (T) list.get(i);
Collection<?> subList = null;
if (isSubList()) {
if (isSubListValue(vo)) {
subList = getListCellValue(vo);
subMergedLastRowNum = subMergedLastRowNum + subList.size();
} else {
subMergedFirstRowNum++;
subMergedLastRowNum++;
}
}
int column = 0;
boolean mergeCells = false;//合并单元格 当前单元格是否需要合并
for (Object[] os : fields) {
Field field = (Field) os[0];
Excel excel = (Excel) os[1];
/**
* 合并单元格判断条件处理
*/
if (excel.lineMergeId()) {
try {
Object value = getTargetValue(vo, field, excel);
if (!objIdValve.equals(value.toString())) {
objIdValve = value.toString();
mergeCells = false;
mergeStartRow = rowNo;
} else {
mergeCells = true;
}
} catch (Exception e) {
log.error("合并单元格导出主键获取失败,导出Excel失败{}", e);
}
}
if (Collection.class.isAssignableFrom(field.getType()) && StringUtils.isNotNull(subList)) {
boolean subFirst = false;
for (Object obj : subList) {
if (subFirst) {
rowNo++;
row = sheet.createRow(rowNo);
}
List<Field> subFields = FieldUtils.getFieldsListWithAnnotation(obj.getClass(), Excel.class);
int subIndex = 0;
for (Field subField : subFields) {
if (subField.isAnnotationPresent(Excel.class)) {
subField.setAccessible(true);
Excel attr = subField.getAnnotation(Excel.class);
this.addCell(attr, row, (T) obj, subField, column + subIndex);
}
subIndex++;
}
subFirst = true;
}
this.subMergedFirstRowNum = this.subMergedFirstRowNum + subList.size();
} else {
this.addCell(excel, row, vo, field, column++);
}
/**
* 合并单元格操作
*/
if (excel.lineMerge() && mergeCells) {
if (rowNo - mergeStartRow > 1) {
List<CellRangeAddress> cellList = new ArrayList<>(sheet.getMergedRegions());
for (int i1 = 0; i1 < cellList.size(); i1++) {
CellRangeAddress ca = cellList.get(i1);
if (mergeStartRow == ca.getFirstRow() && rowNo - 1 == ca.getLastRow() && column - 1 == ca.getFirstColumn() && column - 1 == ca.getLastColumn()) {
sheet.removeMergedRegion(i1);
}
}
}
sheet.addMergedRegion(new CellRangeAddress(mergeStartRow, rowNo, column - 1, column - 1));
}
}
}
}
具体使用方式
在订单编号 @Excel注解中添加 lineMergeId = true,合并单元格的行以此为合并依据,没有此标记则不会执行合并单元格
在需要合并的列中的@Excel注解中添加 lineMerge = true
注:自定义注解 Excel中原有 needMerge字段 以及 ExcelUtil中的子列表不兼容
import com.ruoyi.common.core.annotation.Excel;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
public class Test {
@Excel(name = "订单编号", lineMerge = true, lineMergeId = true)
private String orderNo;
@Excel(name = "订单名称", lineMerge = true)
private String orderName;
@Excel(name = "总价", lineMerge = true)
private BigDecimal amount;
@Excel(name = "商品名称")
private String goodsName;
@Excel(name = "单价")
private BigDecimal price;
@Excel(name = "数量")
private Double quantity;
@Excel(name = "预计到达时间", lineMerge = true)
private LocalDateTime arriveDate;
@Excel(name = "快递公司")
private String express;
@Excel(name = "发货时间")
private LocalDateTime deliveryDate;
@Excel(name = "发货数量")
private Double quantityShipped;
@Excel(name = "到货时间")
private Double trueArriveDate;
@Excel(name = "税率", lineMerge = true)
private Double taxRate;
@Excel(name = "税额", lineMerge = true)
private BigDecimal taxAmount;
@Excel(name = "是否完成", lineMerge = true, readConverterExp = "0=否,1=是")
private Integer completed;
}