Java實(shí)操 -> 基于注解、反射實(shí)現(xiàn)Excel導(dǎo)出動態(tài)合并
點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號”
優(yōu)質(zhì)文章,第一時間送達(dá)
一、效果演示及相關(guān)說明
由于項(xiàng)目信息不能泄露,這里采用測試數(shù)據(jù),下面的測試數(shù)據(jù)是手動輸入的,僅用來輔助說明下面的解釋
測試數(shù)據(jù)原始效果
合并后的效果
二、首先創(chuàng)建注解類。
作用:加載導(dǎo)出字段上,order 表示分組次數(shù)。0表示一次分組,1表示二次分組,依次類推
isflag 表示分組策略,如果為true,則用來這個字段作為當(dāng)前合并的依據(jù),所以和該字段order相同的字段都會合并
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author hhb
* @date :2021/9/16 13:58
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MergeFlag {
int order() default 0;
boolean isflag() default false;
}
三、自定義合并策略
這里使用的是alibabaEasyExcel的Excel處理框架,相關(guān)導(dǎo)出、導(dǎo)入實(shí)現(xiàn)如果不懂請查看官方文檔
https://www.yuque.com/easyexcel/doc/easyexcel
根據(jù)官方提供的單次合并策略O(shè)nceAbsoluteMergeStrategy可知,實(shí)現(xiàn)合并的核心代碼如下
CellRangeAddress cellRangeAddress = new CellRangeAddress(this.firstRowIndex, this.lastRowIndex, this.firstColumnIndex, this.lastColumnIndex);
writeSheetHolder.getSheet().addMergedRegionUnsafe(cellRangeAddress);所以我們接下來需要想辦法先知道那些數(shù)據(jù)是需要合并的,所以我們要預(yù)處理導(dǎo)出的數(shù)據(jù).
然后根據(jù)數(shù)據(jù)上面的注解解析出一個合并map,map的key是 order,value是一個對象,包含通過反射得到的Field[]數(shù)組的index索引、合并標(biāo)識。
詳細(xì)見代碼
/**
* 生成合并策略Map
* @param dataList
* @return
*/
private void generateMergeMap(List dataList,Class<?> type){
//解析分組依據(jù)
List<MergeFlagDTO> mergeFlagDTOList = this.analyzeData(type);
Object preObj=null;
for (int i=0;i<dataList.size();i++){
//獲取合并表示
Object currObj=dataList.get(i);
if (null!=preObj){
//處理數(shù)據(jù)
try {
this.handData(0,mergeFlagDTOList,currObj,preObj,i);
} catch (IllegalAccessException e) {
throw new BadRequestAlertException("導(dǎo)出時發(fā)生解析錯誤!");
}
}
preObj=currObj;
}
}
/**
* 解析數(shù)據(jù)
* @param type
* @return
*/
private List<MergeFlagDTO> analyzeData(Class<?> type) {
Map<Integer, MergeFlagDTO> mergeOrderMap=new HashMap<>();
Field[] fields = type.getDeclaredFields();
//獲取注解列表
for (int i=0;i<fields.length;i++){
MergeFlag mergeFlag = fields[i].getAnnotation(MergeFlag.class);
if (null!=mergeFlag){
//加入索引
MergeFlagDTO dto =mergeOrderMap.get(mergeFlag.order())==null?new MergeFlagDTO():mergeOrderMap.get(mergeFlag.order());
dto.getMergeIndexs().add(i);
dto.setOrder(mergeFlag.order());
if (mergeFlag.isflag()){
dto.setField(fields[i]);
}
mergeOrderMap.put(mergeFlag.order(),dto);
}
}
return new ArrayList<>(mergeOrderMap.values()).stream().filter(item -> null != item.getField()).sorted(Comparator.comparing(MergeFlagDTO::getOrder)).collect(Collectors.toList());
}
/**
* 處理數(shù)據(jù)
* @param start
* @param mergeFlagDTOList
* @param currObj
* @param preObj
* @param index
* @throws IllegalAccessException
*/
private void handData(int start, List<MergeFlagDTO> mergeFlagDTOList, Object currObj, Object preObj, int index) throws IllegalAccessException {
if (start<mergeFlagDTOList.size()){
MergeFlagDTO dto = mergeFlagDTOList.get(start);
Field field = dto.getField();
field.setAccessible(true);
Object currValue = field.get(currObj);
Object preValue = field.get(preObj);
if (currValue.equals(preValue)) {
this.fillMergeMap(dto.getMergeIndexs(),index);
//繼續(xù)遞歸
this.handData(start+1,mergeFlagDTOList,currObj,preObj,index);
}
}
}
/**
* 填充合并map
* @param key
* @param index
*/
private void fillMergeMap(Integer key, Integer index){
List<RowRangeDTO> rangeDTOS = mergeMap.get(key)==null?new ArrayList<>():mergeMap.get(key);
//判斷是否需要新加
boolean needAdd=true;
//遍歷
for (RowRangeDTO rangeDTO:rangeDTOS){
if (rangeDTO.getEndIndex().equals(index)){
rangeDTO.setEndIndex(index+1);
needAdd=false;
}
}
//如果沒有匹配上的就說明需要
if (needAdd){
rangeDTOS.add(new RowRangeDTO(index,index+1));
}
mergeMap.put(key,rangeDTOS);
}
最后根據(jù)合并map對數(shù)據(jù)進(jìn)行合并操作
@Override
protected void merge(Sheet sheet, Cell cell, Head head, Integer integer){
//每一個cell只合并一次
if (cell.getRowIndex()==1&&cell.getColumnIndex()==0){
mergeMap.keySet().forEach(key-> mergeMap.get(key).forEach(rowRangeDTO -> sheet.addMergedRegionUnsafe(new CellRangeAddress(rowRangeDTO.getStartIndex(),rowRangeDTO.getEndIndex(),key,key))));
}
}
作者 | 櫻島麻衣Ss
來源 | cnblogs.com/ydmysm/p/merge_excel.html

加鋒哥微信: java3459 圍觀鋒哥朋友圈,每天推送Java干貨!
