基於注解、反射實現導出動態合並


一、效果演示及相關說明
由於項目信息不能泄露,這里采用測試數據,下面的測試數據是手動輸入的,僅用來輔助說明下面的解釋
測試數據原始效果

合並后的效果

二、首先創建注解類。
作用:加載導出字段上,order 表示分組次數。0表示一次分組,1表示二次分組,依次類推
isflag 表示分組策略,如果為true,則用來這個字段作為當前合並的依據,所以和該字段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處理框架,相關導出、導入實現如果不懂請查看官方文檔
https://www.yuque.com/easyexcel/doc/easyexcel

根據官方提供的單次合並策略OnceAbsoluteMergeStrategy可知,實現合並的核心代碼如下

 CellRangeAddress cellRangeAddress = new CellRangeAddress(this.firstRowIndex, this.lastRowIndex, this.firstColumnIndex, this.lastColumnIndex);
        writeSheetHolder.getSheet().addMergedRegionUnsafe(cellRangeAddress);

所以我們接下來需要想辦法先知道那些數據是需要合並的,所以我們要預處理導出的數據.
然后根據數據上面的注解解析出一個合並map,map的key是 order,value是一個對象,包含通過反射得到的Field[]數組的index索引、合並標識。

詳細見代碼

/**
     * 生成合並策略Map
     * @param dataList
     * @return
     */
    private  void generateMergeMap(List dataList,Class<?> type){
        //解析分組依據
        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){
                //處理數據
                try {
                    this.handData(0,mergeFlagDTOList,currObj,preObj,i);
                } catch (IllegalAccessException e) {
                    throw new BadRequestAlertException("導出時發生解析錯誤!");
                }
            }
            preObj=currObj;
        }
    }

/**
     * 解析數據
     * @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());
    }

 /**
     * 處理數據
     * @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);
                //繼續遞歸
                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);
    }

最后根據合並map對數據進行合並操作

 @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))));
        }
    }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM