导出合并单元格工具类

1.main方法调用

    public static void main(String[] args) {
        List<GroupExport<ScoreDemo, String>> groupExports = new ArrayList<>();
        GroupExport<ScoreDemo, String> build = GroupExport.<ScoreDemo, String>builder()
                //对省进行分组
                .groupColumn(ScoreDemo::getProvince)
                .calculation(demoData -> {
                    //当前省数据进行求和
                    String sum = demoData.stream().map(x -> new BigDecimal(x.getScore())).reduce(BigDecimal::add).get().toString();
                    //设置省总成绩和 这里全部设置 和设置一次都行
                    for (ScoreDemo demoDatum : demoData) {
                        demoDatum.setProvinceScore(sum);
                    }
                })
                //需要合并的列
                .columns(new int[]{0, 7})
                .build();
        GroupExport<ScoreDemo, String> build2 = GroupExport.<ScoreDemo, String>builder()
                //对市进行分组
                .groupColumn(ScoreDemo::getCity)
                .calculation(demoData -> {
                    //当前市数据进行求和
                    String sum = demoData.stream().map(x -> new BigDecimal(x.getScore())).reduce(BigDecimal::add).get().toString();
                    //设置省总成绩和 这里全部设置 和设置一次都行
                    for (ScoreDemo demoDatum : demoData) {
                        demoDatum.setCityScore(sum);
                    }
                })
                //需要合并的列
                .columns(new int[]{1, 6})
                .build();
        GroupExport<ScoreDemo, String> build3 = GroupExport.<ScoreDemo, String>builder()
                .groupColumn(ScoreDemo::getArea)
                .calculation(demoData -> {
                    String sum = demoData.stream().map(x -> new BigDecimal(x.getScore())).reduce(BigDecimal::add).get().toString();
                    for (ScoreDemo demoDatum : demoData) {
                        demoDatum.setAreaScore(sum);
                    }
                })
                .columns(new int[]{2, 5})
                .build();
        //添加进集合
        groupExports.add(build);
        groupExports.add(build2);
        groupExports.add(build3);

        //构造数据
        List<ScoreDemo> data = mockData();
        long start = System.currentTimeMillis();
        //导出
        ExportGroupUtil.exportGroup(data, groupExports,"省市区成绩单",ScoreDemo.class);
        System.out.println(System.currentTimeMillis()-start);
    }

    private static List<ScoreDemo> mockData() {
        Random random = new Random();
        List<ScoreDemo> list = Lists.newArrayList();
        //数据过大会栈溢出
        for (int x = 0; x < 10; x++) {
            for (int i = 0; i < 20; i++) {
                ScoreDemo e = new ScoreDemo();
                if(i < 6){
                    e.setProvince(x+"A");
                    if(i < 2){
                        e.setCity("D");
                        e.setArea("E");
                    }else{
                        e.setCity("F");
                        if(i == 2){
                            e.setArea("G");
                        }else{
                            e.setArea("H");
                        }
                    }
                }else if(i < 10){
                    e.setProvince(x+"B");
                    if(i < 8){
                        e.setCity("I");
                        e.setArea("J");
                    }else{
                        e.setCity("K");
                        if(i < 9){
                            e.setArea("R");
                        }else{
                            e.setArea("M");
                        }
                    }
                }else{
                    e.setProvince(x+"C");
                    if(i < 18){
                        e.setCity("XX");
                        e.setArea("XJ");
                    }else{
                        e.setCity("XK");
                        if(i < 19){
                            e.setArea("XR");
                        }else{
                            e.setArea("XM");
                        }
                    }
                }
                e.setName("张三"+i);
                e.setScore(random.nextInt(20)+"");
                list.add(e);
            }
        }
        return list;
    }

2.工具类

package com.ruijie.substitute.controller.common;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.merge.OnceAbsoluteMergeStrategy;

import java.lang.reflect.Field;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Collectors;

/**
 * @menu 导出并合并单元格工具类
 * @BelongsProject: substitute-resource
 * @BelongsPackage: com.ruijie.substitute.controller.common
 * @Author: rjxiaozhenjie@ruijie.com.cn
 * @CreateTime: 2022-11-22  09:27
 * @Version: 1.0
 */
public class ExportGroupUtil {

    /**
     *
     * 分组导出数据
     *
     * @author rjxiaozhenjie@ruijie.com.cn
     * @date 2022/11/22 09:33:24
     * @param data 需要导出的数据  排不排序都行 内部会对数据分组排序
     * @param groupFunctions 分组函数 GroupExport需写入 分组字段 业务逻辑 合并的列索引
     * @param filePath 导出文件路径
     * @param clz 导出的实体类class
     */
    public static <T,R extends Comparable> void exportGroup(List<T> data, List<GroupExport<T,R>> groupFunctions, String filePath,Class<T> clz) {
        if (groupFunctions.isEmpty()) {
            //不分组的数据
            EasyExcel.write(filePath+".xlsx",clz).sheet("模板").doWrite(data);
            return;
        }
        Function<T, R> groupColumn = groupFunctions.get(0).getGroupColumn();
        //数据排序
        Comparator<T> comparing = Comparator.comparing(groupColumn);
        if (groupFunctions.size() > 1) {
            for (int i = 1; i < groupFunctions.size(); i++) {
                comparing = comparing.thenComparing(groupFunctions.get(i).getGroupColumn());
            }
        }
        data.sort(comparing);

        //不分组的数据
        EasyExcel.write(filePath+"(未合并单元格).xlsx",clz).sheet("模板").doWrite(data);

        //数据分组
        Collector groupCollector = Collectors.groupingBy(groupFunctions.get(groupFunctions.size()-1).getGroupColumn(), LinkedHashMap::new, Collectors.toList());
        for (int i = groupFunctions.size() - 2; i >= 0; i--) {
            groupCollector = Collectors.groupingBy(groupFunctions.get(i).getGroupColumn(), LinkedHashMap::new, groupCollector);
        }
        //分组结果
        Map<String,Object> groupMap = (Map<String,Object>) data.stream().collect(groupCollector);
        //开始行   表头占了多少行 start就写几
        int start = getHeadLen(clz);

        // 方法2 自定义合并单元格策略
        //合并策略
        List<OnceAbsoluteMergeStrategy> list = new LinkedList<>();
        //分组数据map处理
        dataProcessing(groupMap,groupFunctions,0,start,list);

        // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
        ExcelWriterBuilder write = EasyExcel.write(filePath + ".xlsx",clz);

        for (OnceAbsoluteMergeStrategy onceAbsoluteMergeStrategy : list) {
            write.registerWriteHandler(onceAbsoluteMergeStrategy);
        }
        write.sheet("模板").doWrite(data);
    }

    /**
     *
     * 递归调用数据处理逻辑
     *
     * @author rjxiaozhenjie@ruijie.com.cn
     * @date 2022/11/22 09:30:37
     * @param map 数据分组后map
     * @param groupFunctions 分组处理逻辑 这里存放外部写的业务逻辑 通过 groupFunctionsIndex 来顺序获取逻辑
     * @param groupFunctionsIndex 分组处理逻辑对应的下标
     * @param startIndex 起始行 用来控制数据
     * @param strategy 存放分组策略 后续导出使用此集合里面的策略 完成单元格合并
     * @return java.util.List<T>
     */
    private static <T,R extends Comparable> List<T> dataProcessing(Map<String,Object> map,  List<GroupExport<T, R>> groupFunctions,int groupFunctionsIndex , int startIndex, List<OnceAbsoluteMergeStrategy> strategy) {
        List<T> list = new LinkedList<>();
        for (Map.Entry<String,Object> x : map.entrySet()) {
            //获得数据value
            Object value = x.getValue();
            //如果数据不是最小单位
            if(value instanceof Map){
                //处理数据 并 返回最小数据集合
                List<T> data = dataProcessing((Map<String, Object>) value, groupFunctions, groupFunctionsIndex + 1, startIndex, strategy);
                GroupExport<T, R> trGroupExport = groupFunctions.get(groupFunctionsIndex);
                trGroupExport.getCalculation().accept(data);
                //拿出哪些列需要合并
                int[] columns = trGroupExport.getColumns();
                //增加合并单元格策略
                if(data.size() > 1){
                    for (int column : columns) {
                        strategy.add(new OnceAbsoluteMergeStrategy(startIndex, startIndex + data.size() - 1, column, column));
                    }
                }
                startIndex += data.size() ;
                list.addAll(data);
            }else if(value instanceof List){
                List<T> minimumUnitList = (List<T>) value;
                //已经是最小单位了
                GroupExport<T, R> trGroupExport = groupFunctions.get(groupFunctionsIndex);
                //处理业务逻辑
                trGroupExport.getCalculation().accept(minimumUnitList);
                //拿出哪些列需要合并
                int[] columns = trGroupExport.getColumns();
                //增加合并单元格策略
                if (minimumUnitList.size() > 1) {
                    for (int column : columns) {
                        strategy.add(new OnceAbsoluteMergeStrategy(startIndex, startIndex + minimumUnitList.size() - 1, column, column));
                    }
                }
                startIndex += minimumUnitList.size() ;
                list.addAll(minimumUnitList);
            }
        }
        return list;
    }

    /**
     *
     * 获取导出表头行高 主要是用来判断表头占了几行 得到后续合并单元格的起始位置
     *
     * @author rjxiaozhenjie@ruijie.com.cn
     * @date 2022/11/21 14:23:03
     * @param clz 导出实体类class
     * @return int
     */
    private static <T> int getHeadLen(Class<T> clz) {
        int height = 0;
        Field[] declaredFields = clz.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            ExcelProperty annotation = declaredField.getAnnotation(ExcelProperty.class);
            if(annotation != null){
                String[] value = annotation.value();
                if(value != null && value.length > height){
                    height = value.length;
                }
            }
        }
        return height;
    }

}

3.相关实体

package com.ruijie.substitute.controller.common;

import lombok.Builder;
import lombok.Getter;

import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;

/**
 * @menu 分组导出实体类
 * @BelongsProject: substitute-resource
 * @BelongsPackage: com.ruijie.substitute.controller.common
 * @Author: rjxiaozhenjie@ruijie.com.cn
 * @CreateTime: 2022-11-18  17:02
 * @Version: 1.0
 */
@Builder
@Getter
public final class GroupExport<T, R> {

    /**
     * 按照什么来分组
     */
    private Function<T, R> groupColumn;

    /**
     * 对这些分组数据需要处理的逻辑
     */
    private Consumer<List<T>> calculation;

    /**
     * 涉及到需要合并的列 对应excel中的索引位置  从0 开始
     */
    private int[] columns;

}

4实体类

package com.ruijie.substitute.controller.common;

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.HeadStyle;
import com.alibaba.excel.enums.poi.FillPatternTypeEnum;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

/**
 * @menu 备货产品转单率
 * @BelongsProject: substitute-resource
 * @BelongsPackage: com.ruijie.substitute.controller.common
 * @Author: rjxiaozhenjie@ruijie.com.cn
 * @CreateTime: 2022-11-16  15:54
 * @Version: 1.0
 */
@Setter
@Getter
@EqualsAndHashCode
@ToString
@HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 22)
public class ScoreDemo {

    @ExcelProperty(index = 0, value = {"项目基础信息", "省"})
    private String province;

    @ExcelProperty(index = 1,  value ={"项目基础信息", "市"})
    private String city;

    @ExcelProperty(index = 2, value = {"项目基础信息", "区"})
    private String area;

    @ExcelProperty(index = 3, value = {"项目基础信息", "名称"})
    private String name;

    @ExcelProperty(index = 4, value = {"项目基础信息", "成绩"})
    private String score;

    @ExcelProperty(index = 5, value = {"项目基础信息", "区总成绩"})
    private String areaScore;

    @ExcelProperty(index = 6, value = {"项目基础信息", "市总成绩"})
    private String cityScore;

    @ExcelProperty(index = 7, value = {"项目基础信息", "省总成绩"})
    private String provinceScore;

}

 

原文地址:http://www.cnblogs.com/yexuba/p/16914213.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性