看本片之前可以先开这篇文章。合并原理都在其中讲了,该篇文章不讲原理,只是添加了列的合并和将上篇文章的问题修改后做了整理和稍作修改(为了支持列合并)。
目录
AbstractGenericMergeStrategy是抽象的通用合并策略
列合并
行合并
其它辅助类
relativeRowIndex用途
AbstractGenericMergeStrategy是抽象的通用合并策略
public abstract class AbstractGenericMergeStrategy<T extends GenericMerge> extends AbstractMergeStrategy {
protected List<T> list;
protected int headRowNumber = 1;
protected GenericMergeFunction function;
protected AbstractGenericMergeStrategy(List<T> list){
this.list = list;
}
protected AbstractGenericMergeStrategy(List<T> list, int headRowNumber){
this.list = list;
this.headRowNumber = headRowNumber;
}
public AbstractGenericMergeStrategy(List<T> list, int headRowNumber,GenericMergeFunction function) {
this.list = list;
this.headRowNumber = headRowNumber;
this.function = function;
}
@Override
protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {
int columnIndex = cell.getColumnIndex();
int rowIndex = cell.getRowIndex();
GenericMergeBO bo = null;
if (function != null) {
//1
GenericMergeFunction.GenericMergeFunctionHelper helper = new GenericMergeFunction.GenericMergeFunctionHelper();
helper.setColumnIndex(columnIndex);
helper.setRowIndex(rowIndex);
helper.setRelativeRowIndex(relativeRowIndex);
bo =function.apply(helper);
}else{
//2
T t = list.get(rowIndex - headRowNumber);
bo = t.merge(columnIndex,rowIndex,relativeRowIndex);
}
if (bo != null){
merge(sheet,cell,bo);
}
}
protected abstract void merge(Sheet sheet, Cell cell,GenericMergeBO bo);
protected void executorMerge(CellPoint cellPoint, Sheet sheet){
CellRangeAddress cellRangeAddress = new CellRangeAddress(
cellPoint.getStartY(),
cellPoint.getEndY(),
cellPoint.getStartX(),
cellPoint.getEndX());
sheet.addMergedRegionUnsafe(cellRangeAddress);
}
String getCellText(Cell cell){
String text = "";
CellType cellType = cell.getCellTypeEnum();
if(CellType.STRING.equals(cellType)){
text = cell.getStringCellValue();
}else if(CellType.NUMERIC.equals(cellType)){
text = Double.toString(cell.getNumericCellValue());
}else if(CellType.BOOLEAN.equals(cellType)){
text = Boolean.toString(cell.getBooleanCellValue());
}
return text;
}
}
与之前那篇文章相比,多了一个参数: GenericMergeFunction function
public interface GenericMergeFunction{
GenericMergeBO apply(GenericMergeFunctionHelper helper);
@Data
class GenericMergeFunctionHelper {
private int columnIndex;
private int rowIndex;
private int relativeRowIndex;
}
}
此参数是用在代码1处,代码2就是之前那篇文章中所说的那样,根据在定义类相关数据构造GenericMergeBO ,但如果导出的excel是杂乱无章的,即不能使用一个类去描述,例如使用easyexcel提供的不创建对象的写去导出复杂excel时,就可以使用此参数。比如下图就是使用easyexcel提供的不创建对象的写去填充的数据(都是基于easyexcel的table),没有任何类与其对应,这时候要合并单元格时GenericMergeFunction就派上了用场。该function也是为了构造GenericMergeBO。
可以看出该function参数对应的类GenericMergeFunctionHelper 中的属性和代码2构造GenericMergeBO是完全一样的。其实完全可以使用GenericMergeFunction取代List<T>,也就是代码2完全可以使用代码1代替。即即使可以用某个类去描述数据时,也可以用GenericMergeFunction,因为GenericMergeFunction更加灵活。代码2需要从list中获取到当前行数据,调用重写的父类方法merge获取GenericMergeBO。从下方示例代码Table0Function可以看出,也可以实现此功能。并且参数是不做限制的,由自己定义。(headRowNumber也可以放到GenericMergeFunctionHelper属性中)。
public class Table0Function{
private List<xxx > list;
public Table0Function (List<xxx > list){
this.list= list;
}
public GenericMergeBO create(GenericMergeFunction.GenericMergeFunctionHelper helper) {
int rowIndex = helper.getRowIndex();
int columnIndex = helper.getColumnIndex();
GenericMergeBO bo = null;
int headRowNumber = 1;
xxx t = list.get(rowIndex - headRowNumber );
bo = t.merge(columnIndex,rowIndex,relativeRowIndex);
return bo;
}
}
注意:此处下边的列表表头因为前两列不需要,所以一开始都给的是"",但在填充颜色时发现序号左侧那个单元格也填充成橙色了。最后发现因为值一样时,表头自动合并。所以最后一个给了"",另一个给了" ",这样就不会自动合并表头了。
列合并
public class GenericColumnMergeStrategy<T extends GenericMerge> extends AbstractGenericMergeStrategy<T> {
public GenericColumnMergeStrategy(List<T> list) {
super(list);
}
public GenericColumnMergeStrategy(List<T> list, int headRowNumber) {
super(list, headRowNumber);
}
public GenericColumnMergeStrategy(List<T> list, int headRowNumber, GenericMergeFunction function) {
super(list,headRowNumber,function);
}
@Override
protected void merge(Sheet sheet, Cell cell, GenericMergeBO bo) {
//列合并
if (Boolean.TRUE.equals(bo.getStartMergeCell())) {
CellPoint cellPoint = new CellPoint();
cellPoint.setStartY(cell.getRowIndex());
cellPoint.setEndY(cell.getRowIndex());
cellPoint.setStartX(cell.getColumnIndex());
cellPoint.setEndX(cell.getColumnIndex() + bo.getColspan() - 1);
cellPoint.setText(getCellText(cell));
if (cellPoint.getStartX() != cellPoint.getEndX()) {
executorMerge(cellPoint, sheet);
}
}
}
}
行合并
public class GenericRowMergeStrategy<T extends GenericMerge> extends AbstractGenericMergeStrategy<T> {
public GenericRowMergeStrategy(List<T> list) {
super(list);
}
public GenericRowMergeStrategy(List<T> list, int headRowNumber) {
super(list, headRowNumber);
}
public GenericRowMergeStrategy(List<T> list, int headRowNumber, GenericMergeFunction function) {
super(list,headRowNumber,function);
}
@Override
protected void merge(Sheet sheet, Cell cell, GenericMergeBO bo) {
if (Boolean.TRUE.equals(bo.getStartMergeCell())) {
CellPoint cellPoint = new CellPoint();
cellPoint.setStartX(cell.getColumnIndex());
cellPoint.setStartY(cell.getRowIndex());
cellPoint.setEndX(cell.getColumnIndex());
cellPoint.setEndY(cell.getRowIndex() + bo.getRowspan() - 1);
cellPoint.setText(getCellText(cell));
if (cellPoint.getStartY() != cellPoint.getEndY()) {
executorMerge(cellPoint, sheet);
}
}
}
}
列合并:startY == endY ,endX为当前columnIndex加上需要合并列的数量colspan减1,减1是因为当前单元格是起始单元格,包含在合并单元格内。
行合并:startX == endX ,endY为当前rowIndex加上需要合并行的数量rowspan减1,减1同上。
其它辅助类
#GenericMerge 使用List<T>做合并时会使用到,即AbstractGenericMergeStrategy代码2处。
public interface GenericMerge {
GenericMergeBO merge(int columnIndex,int rowIndex,Integer relativeRowIndex);
}
#CellPoint
@Data
public class CellPoint {
/**
* 开始单元格x坐标
* start cell x point
*/
private int startX;
/**
* 结束单元格x坐标
* end cell x point
*/
private int endX;
/**
* 开始单元格y坐标
* start cell y point
*/
private int startY;
/**
* 结束单元格y坐标
* end cell y point
*/
private int endY;
/**
* 单元格内容,文本
* cell content, text
*/
private String text;
}
#GenericMergeBO
@Data
public class GenericMergeBO {
/**
* 是否是开始合并的单元格
*/
private Boolean startMergeCell;
/**
* 合并的行数
*/
private Integer rowspan;
/**
* 合并的列数
*/
private Integer colspan;
}
#MergeTypeEnum
public enum MergeTypeEnum {
/**
* 水平方向合并
* Merge horizontally
*/
HORIZONTAL_MERGE(1),
/**
* 垂直方向合并
* Merge vertically
*/
VERTICAL_MERGE(2),
/**
* 先水平,然后垂直方向合并
* Merge first horizontally, then vertically
*/
CENTER_MERGE(3);
/**
* 类型
* type
*/
private int type;
MergeTypeEnum(int type){
this.type = type;
}
/**
* 获取类型值
* Get type value
*/
public int getType() {
return type;
}
}
#GenericMergeFunctionCreator 生成GenericMergeFunction抽象类(可以不使用此类)
public abstract class GenericMergeFunctionCreator {
protected GenericMergeFunctionCreator(){
}
public abstract GenericMergeBO create(GenericMergeFunction.GenericMergeFunctionHelper helper);
}
继承GenericMergeFunctionCreator 简单示例。使用GenericMergeFunctionCreator和Table0Function 示例只是为了说明构造GenericMergeBO时,不只是可以使用提供的GenericMergeFunctionHelper 参数,同时可以自己可以包装成类,使用其它自己需要的数据和GenericMergeFunctionHelper配合起来构造GenericMergeBO。也就一开始AbstractGenericMergeStrategy没有List<T>时,这里可以通过传入其它参数处理类似的功能
public class Table0Function extends GenericMergeFunctionCreator{
private int size;
public Table0Function (int size){
this.size= size;
}
@Override
public GenericMergeBO create(GenericMergeFunction.GenericMergeFunctionHelper helper) {
int rowIndex = helper.getRowIndex();
int columnIndex = helper.getColumnIndex();
GenericMergeBO bo = null;
if (rowIndex == 0 && columnIndex==0) {
bo = new GenericMergeBO();
bo.setStartMergeCell(true);
bo.setColspan(size+4);
bo.setRowspan(1);
}
return bo;
}
}
relativeRowIndex用途
easyexcel使用table去写入时,每个table的relativeRowIndex都是从0开始,对于动态的数据多个table写入时,当不确定某个table的rowIndex的具体值时,此参数就派上了用场