首页 > 其他分享 >EasyExcel实战 自定义动态化导出excel

EasyExcel实战 自定义动态化导出excel

时间:2023-06-06 18:15:01浏览次数:41  
标签:自定义 excel EasyExcel List mergeTitles add new 动态化 titleList

1.Java操作excel表格,除了运用POI技术,阿里开发一个工具简易操作EasyExcel,接下来我们来实战操作下自定义动态化导出excel,自定义动态化为自定义标题,合并单元格

引入 pom

<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>2.2.7</version>
        </dependency>
View Code

实现代码逻辑

package com.example.excel;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.merge.LoopMergeStrategy;
import jdk.nashorn.internal.runtime.JSONFunctions;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.util.NumberUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * describe: 导出Excel 表格
 *
 * @author 
 * @date 
 */
@Slf4j
public class WriteExcelUtils {

    public static void main(String[] args) {
        List<String> titleList = new ArrayList<>();
        titleList.add("客户名称");
        titleList.add("客户编号");
        titleList.add("供应商名称");
        titleList.add("合同名称");
        titleList.add("合同编号");
        titleList.add("要合并");

        List<String> mergeTitles = new ArrayList<>();
        mergeTitles.add("客户名称");
        mergeTitles.add("供应商名称");
        mergeTitles.add("合同编号");

        List<List<Object>> dataList = new ArrayList<>();
        for (int i = 0; i< 10; i++) {
            List<Object> objList = new ArrayList<>();
            objList.add("客户名称");
            objList.add("客户编号"+i);
            objList.add("供应商名称"+i);
            objList.add("合同名称"+i);
            objList.add("合同编号");
            objList.add("要合并"+i);
            dataList.add(objList);
        }

        WriteExcelUtils writeExcelUtils = new WriteExcelUtils();
        writeExcelUtils.customDynamicExport("测试导出excel" + Math.random(),titleList, mergeTitles, dataList);
    }


    /**
     * 自定义动态导出excel
     *
     * @param fileName 文件名称 不带后缀
     * @param titleList excel标题名称
     * @param mergeTitles 需要合并的标题列
     * @param dataList 导出的数据 按顺序
     */
    public void customDynamicExport(String fileName, List<String> titleList,
                                    List<String> mergeTitles, List<List<Object>> dataList) {
        fileName = fileName + ".xlsx";

        // 导出的数据转换为Map数据结构, k -> 标题,v -> 此标题下的数据按顺序
        Map<String, List<Object>> dataMap = new HashMap<>(titleList.size());
        for (int i = 0 ; i < titleList.size(); i++) {
            // 当前列数据
            List<Object> currectTitleDatas = new ArrayList<>();
            for (int j = 0; j < dataList.size(); j++) {
                currectTitleDatas.add(dataList.get(j).get(i));
            }
            dataMap.put(titleList.get(i), currectTitleDatas);
        }

        // 获取标题信息
        List<List<String>> headTitleInfo = excelTitle(titleList);
        // 获取数据信息
        List<List<Object>> excelDataInfo = excelData(dataList);

        // 获取合并单元格信息
        List<LoopMergeStrategy> mergeStrategies = mergeCells(titleList, mergeTitles, dataMap);
        ExcelWriterBuilder excelWriterBuilder = EasyExcel.write(fileName);
        if (!CollectionUtils.isEmpty(mergeStrategies)) {
            log.info("开始进行合并单元格操作 mergeStrategies ===> {}", mergeStrategies);
            mergeStrategies.forEach(m -> {
                    excelWriterBuilder.registerWriteHandler(m);
            });
        }

        excelWriterBuilder.head(headTitleInfo).sheet("模板")
                // 当然这里数据也可以用 List<List<String>> 去传入
                .doWrite(excelDataInfo);
    }

    /**
     * 获取excel标题
     *
     * @param titleList
     * @return
     */
    private List<List<String>> excelTitle(List<String> titleList) {
        if (CollectionUtils.isEmpty(titleList)) {
            log.error("====> 导出excel标题为空");
            throw new RuntimeException();
        }

        List<List<String>> excelTitleList = new ArrayList<>(titleList.size());
        titleList.forEach(k -> {
            List<String> titles = new ArrayList<>(1);
            titles.add(k);
            excelTitleList.add(titles);
        });
        return excelTitleList;
    }

    private List<List<Object>> excelData(List<List<Object>> dataList) {
        if (CollectionUtils.isEmpty(dataList)) {
            log.error("===> 导出excel数据为空");
            throw new RuntimeException();
        }

        return dataList;
    }

    private List<LoopMergeStrategy> mergeCells(List<String> titleList, List<String> mergeTitles, Map<String, List<Object>> dataMap) {
        if (CollectionUtils.isEmpty(titleList)) {
            log.error("====> 导出excel标题为空");
            throw new RuntimeException();
        }
        if (CollectionUtils.isEmpty(mergeTitles)) {
            log.warn("该次导出无合并单元格操作");
            return new ArrayList<>();
        }

        // 将需要合并的项转换为Map,以便获取合并位置
        Map<String, String> mergeTitleMap = mergeTitles.stream().collect(Collectors.toMap(k -> k, k -> k));

        // 获取合并位置
        Map<String, Integer> mergeLocationMap = new HashMap<>(mergeTitles.size());
        for (int i = 0; i < titleList.size(); i++) {
            if (Objects.nonNull(mergeTitleMap.get(titleList.get(i)))) {
                mergeLocationMap.put(titleList.get(i), i);
            }
        }

        List<LoopMergeStrategy> mergeStrategyList = new ArrayList<>();

        mergeTitles.forEach(k -> {
            // 合并数据所在的列数
            Integer columnIndex = mergeLocationMap.get(k);

            List<Object> mergeDatas = dataMap.get(k);

            // 需要合并的数量
            Integer currectMergeNum = 1;
            for (int m = 0; m < mergeDatas.size(); m++) {
                // 是否存在合并环节
                Boolean isMerge = false;
                if (m != 0 && Objects.equals(mergeDatas.get(m), mergeDatas.get(m - 1))) {
                    isMerge = true;
                    currectMergeNum = currectMergeNum + 1;

                    if (m == mergeDatas.size() - 1) {
                        isMerge = false;
                    }
                }
                if (!isMerge && currectMergeNum > 1) {
                    // 合并的行数
                    Integer eachRow = currectMergeNum;
                    mergeStrategyList.add(new LoopMergeStrategy(eachRow, columnIndex));
                    currectMergeNum = 1;
                }
            }
        });
        return mergeStrategyList;
    }
}
View Code

 

标签:自定义,excel,EasyExcel,List,mergeTitles,add,new,动态化,titleList
From: https://www.cnblogs.com/zxy-come-on/p/17461303.html

相关文章

  • CKEditor (Toolbar Definition)工具栏自定义配置
    CKEditor中的工具栏默认显示所有功能按钮。出于安全的原因、或者是简化的原因,需要对这个工具栏进行自定义设置。CKEditor工具栏自定义配置非常简单。编辑ckeditor目录下的的config.js文件,默认的是下面的工具栏代码,注意工具按钮是分组的,一个name内的大括号就是一个工具按钮......
  • ubuntu自定义服务
    ubuntu自定义服务,以SRT Server为例① 创建编辑sudovi/etc/systemd/system/srt.service1[Unit]2Description=SRTServerService3After=network.targetsyslog.target4Wants=network.target56[Service]7Type=simple8ExecStart=/home/vikin/sr......
  • 《深度剖析CPython解释器》19. Python类机制的深度解析(第三部分): 自定义类的底层实
    https://www.cnblogs.com/traditional/p/13593927.html楔子Python除了给我提供了很多的类之外,还支持我们定义属于自己的类,那么Python底层是如何做的呢?我们下面就来看看。自定义class老规矩,如果想知道底层是怎么做的,那么就必须要通过观察字节码来实现。classGirl:nam......
  • SpringMVC里通过ResponseBodyAdvice接口实现统一自定义返回逻辑
    这个org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice接口。publicinterfaceResponseBodyAdvice<T>{//返回true代表走自定义逻辑booleansupports(MethodParameterreturnType,Class<?extendsHttpMessageConverter<?>>converte......
  • 8. 自定义映射resultMap
    ‍在Mybatis中,resultType和resultMap都用于定义查询结果的映射关系。它们的使用场景如下:resultTyperesultType用于指定返回结果的数据类型,通常用于返回简单类型的结果以及返回vo或dto等自定义类型的结果。例如:‍<selectid="findUserById"parameterType="int"r......
  • Vue自定义指令-让你的业务开发更简单
    1、使用场景在日常开发中,我们会将重复代码抽象为一个函数或者组件,然后在需要时调用或者引入。但是,对于某些功能,这种方法可能不够优雅或者不够灵活。例如,我们可能需要在DOM元素上添加一些自定义属性或者绑定一些事件,这些操作可能难以通过函数或组件来实现。这时,自定义指令就派上用......
  • qt 中的自定义pushbutton
       ......
  • WPF自学入门(四)WPF路由事件之自定义路由事件
      在上一篇博文中写到了内置路由事件,其实除了内置的路由事件,我们也可以进行自定义路由事件。接下来我们一起来看一下WPF中的自定义路由事件怎么进行创建吧。创建自定义路由事件分为3个步骤:1、声明并注册路由事件。2、利用CLR事件包装路由事件(封装路由事件)。3、创建可以激发路由......
  • 二、Spring Reactive Security自定义登录页
    添加配置类:@ConfigurationpublicclassMyReactiveSecurityConfig{@BeanpublicReactiveUserDetailsServicereactiveUserDetailsService(){UserDetailsuser=User.withUsername("user").password("12345")......
  • 为什么在stdio.h写自定义的宏不行?
    在自定义的头文件写可以: 这样写不行: ......