easyexcel使用小结-未完待续

官网:https://easyexcel.opensource.alibaba.com/docs/current/

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>4.0.1</version>
        </dependency>

一、读

1.1简单读

在这里插入图片描述

@Getter
@Setter
@EqualsAndHashCode
public class khTable {
    //@ExcelProperty(index = 0)
    @ExcelProperty("字段名称")
    private String filedEN;
    @ExcelProperty("字段说明")
    private String filedCN;
    @ExcelProperty("类型")
    private String type;
}

fileName 文件路径
khTable.class 实体类
sheet1:读哪个sheet页,默认第一个sheet,可以输入sheetName也可以输入sheetNO
headRowNumber 表头所在行数

  • 0 表示没有表头
  • 1默认值,表示表头占1行,数据从第2行开始
  • 2表示表示表头占2行,数据从第3行开始
        List<khTable> list = new ArrayList<>();
        EasyExcel.read(fileName, khTable.class, new PageReadListener<khTable>(c -> {
                 list.addAll(c);
        })).sheet("sheet1").headRowNumber(2).doRead();
        System.out.println(list);

1.2 读-自定义监听器

读取条额外信息:批注、超链接、合并单元格信息等

以读合并单元格为例

        //创建监听器
        ExcelDateListener<HisTable> listener = new ExcelDateListener<>();
        //读取excel
        EasyExcel.read(hisExcel, HisTable.class,listener).extraRead(CellExtraTypeEnum.MERGE).sheet(1).doRead();
        //从监听器中获取合并单元格的数据
        List<CellExtra> extraMergeInfoList = listener.getExtraMergeInfoList();
        //从监听器中获取其他数据
        List<HisTable> cacheList = listener.getCacheList();
        //把合并单元格的数据和其他数据进行合并
        List<HisTable> list1 = EasyExcelUtil.explainMergeData(cacheList, extraMergeInfoList, 1);
        System.out.println(list1);

自定义监听器

@Slf4j
public class ExcelDateListener<M> extends AnalysisEventListener<M> {


    // 表头数据
    Map<Integer,String> headMap=new HashMap<>();
    // 缓存数据
    List<M> cacheList = new ArrayList<>();
    // 合并单元格
    private final List<CellExtra> extraMergeInfoList = new ArrayList<>();


    /**
     * 获取合并单元格
     */
    public List<CellExtra> getExtraMergeInfoList() {
        return this.extraMergeInfoList;
    }

    /**
     * 获取合并单元格
     */
    public List<M> getCacheList() {
        return this.cacheList;
    }

    /**
     * 这里会一行行的返回头
     */
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        this.headMap=headMap;
    }


    @Override
    public void invoke(M data, AnalysisContext analysisContext) {
        cacheList.add(data);
    }

    /**
     * 所有数据解析完成了 都会来调用
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
    }


    /**
     * 在转换异常 获取其他异常下会调用本接口。抛出异常则停止读取。如果这里不抛出异常则 继续读取下一行
     */
    @Override
    public void onException(Exception exception, AnalysisContext context) {
        // 如果是某一个单元格的转换异常 能获取到具体行号
        // 如果要获取头的信息 配合invokeHeadMap使用
        if (exception instanceof ExcelDataConvertException) {
            ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception;
            log.error("第{}行,第{}列解析异常", excelDataConvertException.getRowIndex(),
                    excelDataConvertException.getColumnIndex());
        }
    }

    /**
     * 读取条额外信息:批注、超链接、合并单元格信息等
     */
    @Override
    public void extra(CellExtra extra, AnalysisContext context) {
        switch (extra.getType()) {
            case COMMENT:
                log.info("额外信息是批注,在rowIndex:{},columnIndex;{},内容是:{}", extra.getRowIndex(), extra.getColumnIndex(),
                        extra.getText());
                break;
            case HYPERLINK:
                if ("Sheet1!A1".equals(extra.getText())) {
                    log.info("额外信息是超链接,在rowIndex:{},columnIndex;{},内容是:{}", extra.getRowIndex(),
                            extra.getColumnIndex(), extra.getText());
                } else if ("Sheet2!A1".equals(extra.getText())) {
                    log.info(
                            "额外信息是超链接,而且覆盖了一个区间,在firstRowIndex:{},firstColumnIndex;{},lastRowIndex:{},lastColumnIndex:{},"
                                    + "内容是:{}",
                            extra.getFirstRowIndex(), extra.getFirstColumnIndex(), extra.getLastRowIndex(),
                            extra.getLastColumnIndex(), extra.getText());
                } else {
                    log.error("Unknown hyperlink!");
                }
                break;
            case MERGE:
                log.info(
                        "额外信息是合并单元格,而且覆盖了一个区间,在firstRowIndex:{},firstColumnIndex;{},lastRowIndex:{},lastColumnIndex:{}",
                        extra.getFirstRowIndex(), extra.getFirstColumnIndex(), extra.getLastRowIndex(),
                        extra.getLastColumnIndex());
                extraMergeInfoList.add(extra);
                break;
            default:
        }
    }
}


package com.wang.ahlht.utils;

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.metadata.CellExtra;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.List;

@Slf4j
public class EasyExcelUtil {

    /**
     * 初始化响应体
     * @param response 请求头
     * @param fileName 导出名称
     */
    public static void initResponse(HttpServletResponse response, String fileName) {
        String finalFileName = fileName + "_(截止"+ System.currentTimeMillis()+")";
        // 设置content—type 响应类型
        // response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        try {
            // 这里URLEncoder.encode可以防止中文乱码
            finalFileName = URLEncoder.encode(finalFileName, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        response.setHeader("Content-disposition", "attachment;filename=" + finalFileName + ".xlsx");
    }

    /**
     * 处理合并单元格
     * @param data               解析数据
     * @param extraMergeInfoList 合并单元格信息
     * @param headRowNumber      起始行
     * @return 填充好的解析数据
     */
    public static <T> List<T> explainMergeData(List<T> data, List<CellExtra> extraMergeInfoList, Integer headRowNumber) {
        // 循环所有合并单元格信息
        extraMergeInfoList.forEach(cellExtra -> {
            int firstRowIndex = cellExtra.getFirstRowIndex() - headRowNumber;
            int lastRowIndex = cellExtra.getLastRowIndex() - headRowNumber;
            int firstColumnIndex = cellExtra.getFirstColumnIndex();
            int lastColumnIndex = cellExtra.getLastColumnIndex();
            // 获取初始值
            Object initValue = getInitValueFromList(firstRowIndex, firstColumnIndex, data);
            // 设置值
            for (int i = firstRowIndex; i <= lastRowIndex; i++) {
                for (int j = firstColumnIndex; j <= lastColumnIndex; j++) {
                    setInitValueToList(initValue, i, j, data);
                }
            }
        });
        return data;
    }

    /**
     * 设置合并单元格的值
     *
     * @param filedValue  值
     * @param rowIndex    行
     * @param columnIndex 列
     * @param data        解析数据
     */
    private static <T> void setInitValueToList(Object filedValue, Integer rowIndex, Integer columnIndex, List<T> data) {
        if (rowIndex >= data.size()) return;

        T object = data.get(rowIndex);

        for (Field field : object.getClass().getDeclaredFields()) {
            // 提升反射性能,关闭安全检查
            field.setAccessible(true);
            ExcelProperty annotation = field.getAnnotation(ExcelProperty.class);
            if (annotation != null) {
                if (annotation.index() == columnIndex) {
                    try {
                        field.set(object, filedValue);
                        break;
                    } catch (IllegalAccessException e) {
                        log.error("设置合并单元格的值异常:{}", e.getMessage());
                    }
                }
            }
        }
    }

    /**
     * 获取合并单元格的初始值
     * rowIndex对应list的索引
     * columnIndex对应实体内的字段
     *
     * @param firstRowIndex    起始行
     * @param firstColumnIndex 起始列
     * @param data             列数据
     * @return 初始值
     */
    private static <T> Object getInitValueFromList(Integer firstRowIndex, Integer firstColumnIndex, List<T> data) {
        Object filedValue = null;
        T object = data.get(firstRowIndex);
        for (Field field : object.getClass().getDeclaredFields()) {
            // 提升反射性能,关闭安全检查
            field.setAccessible(true);
            ExcelProperty annotation = field.getAnnotation(ExcelProperty.class);
            if (annotation != null) {
                if (annotation.index() == firstColumnIndex) {
                    try {
                        filedValue = field.get(object);
                        break;
                    } catch (IllegalAccessException e) {
                        log.error("设置合并单元格的初始值异常:{}", e.getMessage());
                    }
                }
            }
        }
        return filedValue;
    }

}

二、写

1.1 一次写多个sheet

    private void writeExcel3(Map<String,List<Hbgxys>> map) {
        int sheetNum = 1;
        try (ExcelWriter excelWriter = EasyExcel.write(outPutExcel, Hbgxys.class).registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).build()) {
            for (Map.Entry<String, List<Hbgxys>> stringListEntry : map.entrySet()) {
                // 每次都要创建writeSheet 这里注意必须指定sheetNo 而且sheetName必须不一样
                String key = stringListEntry.getKey();
                List<Hbgxys> value = stringListEntry.getValue();
                WriteSheet writeSheet = EasyExcel.writerSheet(sheetNum, key).build();
                excelWriter.write(value, writeSheet);
                sheetNum++;
            }
        }
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/783186.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Vue 与 OpenAI 接口交互实战:发送请求的全流程解析(一)

前言 本文讲解使用vue去搭建一个项目&#xff0c;然后向OpenAI发送请求&#xff0c;并获取数据 文章分为两篇书写&#xff0c;本篇文章侧重于书写API的封装与调用&#xff0c;第二篇文章侧重于页面逻辑的处理 接下来就让我们开始吧! 调用OpenAI的本质是什么&#xff1f; 本…

基于AD8232的心电图套件的测试

基于AD8232的心电图套件的测试 1、测试设备2、电源的选择3、 用于测试心电图套件的模拟心电图电路基本4017B的电路基于multisim的电路仿真基于STM32F103RCT6 参考测试数据 1、测试设备 1、AD8232心电模块 2、手持示波器 3、心电信号模拟发生器 4、NI multisim 14.3 5、实物待补…

关于振动盘正反料下料逻辑编写

写在前文 借鉴某个程序的逻辑套路写的 1.就是第一个料是正方向&#xff0c;第二个料是反方向。 (* 基础逻辑应该都差不多&#xff0c;这个是一个振动盘&#xff0c;振动盘的末端是一个上下对射的感应器&#xff0c;这个感应器的作用是对射感应到物料的到位信号&#xff0c;末端…

java LogUtil输出日志打日志的class文件内具体方法和行号

最近琢磨怎么把日志打的更清晰&#xff0c;方便查找问题&#xff0c;又不需要在每个class内都创建Logger对象&#xff1b;利用堆栈的方向顺序拿到日志的class问题。看效果&#xff0c;直接上代码。 1、demo test 2、输出效果 3、完整的LogUtil文件 import org.jetbrains.anno…

导入项目,JAVA文件是咖啡杯图标

问题 从图中可以看到&#xff0c;JAVA文件是咖啡杯图标 原因 项目没有识别为MAVEN项目 解决办法 进入pom.xml文件&#xff0c;右键点击Add as Maven Project即可

详解Linux的shell脚本基础指令

一、shell简介 是Linux系统的用户界面&#xff0c;它提供用户与内核的一种交互方式。它接收用户输入的命令&#xff0c;并把它送入内核去执行&#xff0c;是一个命令解释器。 脚本&#xff1a;本质是一个文件&#xff0c;文件里面存放的是 特定格式的指令&#xff0c;系统可以…

CC4利用链分析

我的Github主页Java反序列化学习同步更新&#xff0c;有简单的利用链图 分析版本 Commons Collections 4.0 JDK 8u65 环境配置参考JAVA安全初探(三):CC1链全分析 分析过程 在Commons Collections 4.0中&#xff0c;TransformingComparator类变为可序列化类&#xff0c;增…

myeclipse开发ssm框架项目图书管理系统 mysql数据库web计算机毕业设计项目

摘 要 随着计算机的广泛应用&#xff0c;其逐步成为现代化的标志。图书馆的信息量也会越来越大&#xff0c;因此需要对图书信息、借书信息、还书信息等进行管理&#xff0c;及时了解各个环节中信息的变更&#xff0c;要对因此而产生的单据进行及时的处理&#xff0c;为了提高高…

吴恩达老师推荐的大模型分析网站 Artificial Analysis

是吴恩达老师推荐的一个提供各大模型的质量、输出速度、价格对比等多维度分析的网站。 比起 LMSYS Chatbot Arena 或者 HF 上的其他竞技场&#xff0c;它们更注重的输出的质量而这个网站其实更利于我们选择一个合适的大模型 API&#xff0c;强烈安利&#xff01;

千帆大模型平台升级十大能力,企业级 RAG 全面升级

7 月 5 日&#xff0c;2024 世界人工智能大会&#xff08;WAIC&#xff09;期间&#xff0c;百度智能云大模型助力新质生产力发展论坛在在上海世博展览馆举办。会上&#xff0c;百度智能云宣布文心大模型 4.0 Turbo&#xff08;ERNIE 4.0 Turbo&#xff09;面向企业客户全面开放…

人工智能在三级淋巴结:肿瘤浸润淋巴细胞领域的系统研究进展|顶刊速递·24-07-08

小罗碎碎念 本期文献主题&#xff1a;人工智能在三级淋巴结/肿瘤浸润淋巴细胞领域的系统分析 关于三级淋巴结和肿瘤浸润淋巴细胞的文献&#xff0c;会是接下来的分析重点&#xff0c;期间也会穿插临床文献&项目复现的推文。 另外再说点科研道路上的题外话&#xff0c;也算是…

GitLab CI/CD实现项目自动化部署

1 GitLab CI/CD介绍 GitLab CI/CD 是 GitLab 中集成的一套用于软件开发的持续集成&#xff08;Continuous Integration&#xff09;、持续交付&#xff08;Continuous Delivery&#xff09;和持续部署&#xff08;Continuous Deployment&#xff09;工具。这套系统允许开发团队…

一手洞悉泰国slot线上游戏投放本土网盟CPI计费广告优势

一手洞悉泰国slot线上游戏投放本土网盟CPI计费广告优势 ​在泰国这个拥有独特文化背景和审美观念的国家&#xff0c;Slots游戏以其丰富的玩法和刺激的体验迅速赢得了玩家们的喜爱。然而&#xff0c;要在竞争激烈的市场中脱颖而出&#xff0c;有效的推广策略显得尤为重要。本土…

JVM专题之垃圾收集器

JVM参数 3.1.1 标准参数 -version -help -server -cp 3.1.2 -X参数 非标准参数,也就是在JDK各个版本中可能会变动 ``` -Xint 解释执行 -Xcomp 第一次使用就编译成本地代码 -Xmixed 混合模式,JVM自己来决定 3.1.3 -XX参数 > 使用得最多的参数类型 > > 非…

Docassemble interview 未授权任意文件读取漏洞复现(CVE-2024-27292)

0x01 产品简介 Docassemble是一款强大的开源工具,主要用于自动化生成和定制复杂文档,特别是在法律文档处理领域表现出色。由Jonathan Pyle个人开发者开发,是一个免费的开源专家系统,用于指导访谈和文档组装。Docassemble基于Python编写,充分利用了Python的灵活性和广泛的…

【论文阅读】-- Visual Traffic Jam Analysis Based on Trajectory Data

基于轨迹数据的可视化交通拥堵分析 摘要1 引言2 相关工作2.1 交通事件检测2.2 交通可视化2.3 传播图可视化 3 概述3.1 设计要求3.2 输入数据说明3.3 交通拥堵数据模型3.4 工作流程 4 预处理4.1 路网处理4.2 GPS数据清理4.3 地图匹配4.4 道路速度计算4.5 交通拥堵检测4.6 传播图…

Spring Cloud: OpenFeign 超时重试机制

超时重试是一种用于网络通信的常用策略&#xff0c;目的是在请求未能在规定时间内获得响应或响应超时的情况下&#xff0c;重新发送请求。具体来说&#xff0c;当发起请求后&#xff0c;如果在设定的时间内未能收到预期的响应&#xff0c;就会启动超时重试机制&#xff0c;重新…

EPICS数据库示例

本文目标是使用EPICS数据库示例帮助新手理解如何使用不同的示例。 1、使用seq和mbbo的简单选择器 这个简单示例展示了如何使用一个mbbo和一个seq来旋转哪个值将被设置到一个PV。 # 这个mbbo记录将选择将运行seq的哪段 record(mbbo, "CHOOSE") {field(VAL, "…

LVS+Nginx高可用集群--基础篇(二)

1.虚拟主机-使用nginx为静态资源提供服务 静态资源服务器&#xff1a;主要包括两类资源&#xff0c;网页&#xff1b;图片&#xff0c;音频等&#xff1b; 也可以通过别名设置静态资源路径。 配置代码&#xff1a; server {listen 88;server_name localhost;locatio…

DFS回溯剪枝|KMP通过数组记录减少判断子字符串|思路

KMP|DFS回溯剪枝 #1、NC149kmp 初步思路&#xff1a; 两层for循环&#xff0c;一个T的字符开始与 S的字符比较&#xff0c;挨个比较&#xff0c;遇到不同就continue当前T的字符&#xff0c;重复步骤》效率太低&#xff0c;超时 eg: TABSABABABD SABABD S&#xff01;A时&#…