SpringBoot中使用Easyexcel实现Excel导入导出功能(二)

news2024/11/16 17:26:57

目录

常规导出

大批量数据导出

复杂表头的导出

日期、数字、自定义格式转换后导出


常规导出

        常规导出excel有两种,个人比较推荐第一种:

        1、新建一个导出数据的实体类,用@ExcelProperty()注解标明excel中列的中文名称;如果实体的类某些列不想导出,可以使用@ExcelIgnore进行忽略就可以了。

        2、使用easyexcel的工厂类EasyExcel直接导出数据到excel表格中;

   第一种

@Data
public class EmpSalary  {
    @ExcelProperty("姓名")
    private String realName;
    @ExcelProperty("员工编号")
    private String empNo;
    @ExcelProperty(value = "工资日期")
    private String salaryDate;
    @ExcelProperty("基本工资")
    private Float baseAmount;
    @ExcelProperty("全勤奖")
    private Float fullAttendAmount;
    @ExcelProperty("五险一金")
    private Float insurance;
    //特别资金
    @ExcelIgnore
    private Float specialAmount;
}
@Test
public void write() {
    String userDir = System.getProperty("user.dir");
    String exportPath = userDir + File.separator + "export";
    File file = new File(exportPath);
    if (!file.exists()) {
        file.mkdirs();
    }
    String exportFile = exportPath + File.separator + "员工工资表-12月.xlsx";
    EasyExcel.write(exportFile, EmpSalary.class).sheet("12月").doWrite(empSalaryData());
}
public List<EmpSalary> empSalaryData() {
    List<EmpSalary> list = new ArrayList<>();
    SecureRandom random = new SecureRandom();
    for (int i = 0; i < 10; i++) {
        EmpSalary empSalary = new EmpSalary();
        empSalary.setEmpNo("CH" + (i + 1));
        empSalary.setRealName("张三" + (i + 1));
        empSalary.setSalaryDate("2022-12");
        empSalary.setBaseAmount(random.nextInt(100000) / 10.00f);
        empSalary.setFullAttendAmount(random.nextInt(1000) / 10.00f);
        empSalary.setInsurance(random.nextInt(1000) / 10.00f);
        list.add(empSalary);
    }
    return list;
}

 第二种:

        通常情况这种不推荐。为啥都呢?表头的数据格式太奇怪(List>),比较麻烦。当然有些情况可以例外,如果表头比较复杂,或者表头需要动态生成。

 public List<List<String>> headList(){
        List<List<String>> headList=new ArrayList<>();
        List<String> head1=new ArrayList<>();
        head1.add("姓名");
        headList.add(head1);
        List<String> head2=new ArrayList<>();
        head2.add("员工编号");
        headList.add(head1);
        List<String> head3=new ArrayList<>();
        head3.add("工资日期");
        headList.add(head3);
        List<String> head4=new ArrayList<>();
        head4.add("基本工资");
        headList.add(head4);
        List<String> head5=new ArrayList<>();
        head5.add("全勤奖");
        headList.add(head5);
        List<String> head6=new ArrayList<>();
        head6.add("保险");
        headList.add(head6);
        return headList;
    }
    @Test
    public void write2(){
        String userDir = System.getProperty("user.dir");
        String exportPath = userDir + File.separator + "export";
        File file = new File(exportPath);
        if (!file.exists()) {
            file.mkdirs();
        }
        String exportFile = exportPath + File.separator + "员工工资表-12月_v2.xlsx";
        EasyExcel.write(exportFile).head(headList()).sheet().doWrite(empSalaryData());
    }
}

大批量数据导出

        有时候会遇到这样的的导出需求,比如上万、几十万,这种大批量数据的导出,如果还是使用常规的导出,在效能上不好,可以用下面的方法:

        1、先通过easyexcel的工厂类(EasyExcel)构建出一个写入器(ExcelWriter);

        2、构建出写出用的sheet页(WriteSheet);

        3、把数据分批,使用第一步构建好的数据写入器(ExcelWriter)往第二步构建好的sheet页(ExcelSheet)里写入数据;

        4、在全部数据写入完成后一定要关闭数据写入器(ExcelWriter);

        注:示例里是把大批量的数据写入的同一个sheet页里面;如果想要把大量数据写入到不同的sheet页里,就需要把sheet页构建放到循环里面;

public String getExportPath() {
    String userDir = System.getProperty("user.dir");
    String exportPath = userDir + File.separator + "export";
    File file = new File(exportPath);
    if (!file.exists()) {
        file.mkdirs();
    }
    return exportPath;
}
public List<EmpSalary> empSalaryData(int rows) {
    List<EmpSalary> list = new ArrayList<>();
    SecureRandom random = new SecureRandom();
    for (int i = 0; i < rows; i++) {
        EmpSalary empSalary = new EmpSalary();
        empSalary.setEmpNo("CH" + (i + 1));
        empSalary.setRealName("张三" + (i + 1));
        empSalary.setSalaryDate("2022-12");
        empSalary.setBaseAmount(random.nextInt(100000) / 10.00f);
        empSalary.setFullAttendAmount(random.nextInt(1000) / 10.00f);
        empSalary.setInsurance(random.nextInt(1000) / 10.00f);
        list.add(empSalary);
    }
    return list;
}
@Test
public void writeBigData() {
    String exportPath = this.getExportPath();
    String exportFile = exportPath + File.separator + "超过10000万人的员工工资表.xlsx";
    ExcelWriter excelWriter =null;
    try {
            excelWriter = EasyExcel.write(exportFile, EmpSalary.class).build();
            WriteSheet writeSheet = EasyExcel.writerSheet(1).build();
            for (int i = 0; i < 10; i++) {
                List<EmpSalary> empSalaries = this.empSalaryData(1000);
                excelWriter.write(empSalaries, writeSheet);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if (excelWriter != null) {
            excelWriter.finish();
        }
    }
}

复杂表头的导出

        特别是一些财务类型的报表导出,表头往往是复合表头,比较复杂

         easyexcel对于这种场景提供了两种方法,一种是注解;另外一种是通过一种特殊的数据结构List<List<string>>;根据我的感受,我是推荐使用注解的;

第一种:

        如果是所在列是复合表头,则使用@ExcelProperty()注解,从上到下标明表头组成;如果是普通表头,按普通的用法标明表头名称即可;是不是很简单?

@Data
public class EmpSalary  {
    @ExcelProperty({"基本信息","姓名"})
    private String realName;
    @ExcelProperty({"基本信息","员工编号"})
    private String empNo;
    //,converter = SalaryDateConverter.class
    @ExcelProperty(value = "工资日期")
    private String salaryDate;
    @ExcelProperty({"工资构成","基本工资"})
    private Float baseAmount;
    @ExcelProperty({"工资构成","全勤奖"})
    private Float fullAttendAmount;
    @ExcelProperty({"工资构成","五险一金"})
    private Float insurance;
    //特别资金
    @ExcelIgnore
    private Float specialAmount;
}
@Test
public void writeHead() {
    String exportPath = this.getExportPath();
    String exportFile = exportPath + File.separator + "员工工资表v3.xlsx";
    EasyExcel.write(exportFile, EmpSalary.class).sheet().doWrite(this.empSalaryData(10));
}

第二种:

        使用List<List<string>>结构来组织表头数据,开始的时候还不是很理解表头的数据结构为什么这么奇怪,到这里是不是明白了。对于普通表头List<String>肯定就可以了,但是在一些复杂的场景就不行了。这么制定的话,什么场景都不在话下,关键还可以动态生成表头,这一点确实比注解的方式要灵活一些;所以具体使用哪种,要根据业务场景决定了。

@Test
public void writeHead() {
    String exportPath = this.getExportPath();
    String exportFile = exportPath + File.separator + "员工工资表v4.xlsx";
    List<List<String>> headList = new ArrayList<>();
    List<String> head1 = new ArrayList<>();
    head1.add("基本信息");
    head1.add("姓名");
    headList.add(head1);
    List<String> head2 = new ArrayList<>();
    head2.add("基本信息");
    head2.add("员工编号");
    headList.add(head2);
    List<String> head3 = new ArrayList<>();
    head3.add("工资日期");
    headList.add(head3);
    List<String> head4 = new ArrayList<>();
    head4.add("工资构成");
    head4.add("基本工资");
    headList.add(head4);
    List<String> head5 = new ArrayList<>();
    head5.add("工资构成");
    head5.add("全勤奖");
    headList.add(head5);
    List<String> head6 = new ArrayList<>();
    head6.add("工资构成");
    head6.add("保险");
    headList.add(head6);
    EasyExcel.write(exportFile).head(headList).sheet().doWrite(this.empSalaryData(10));
}

日期、数字、自定义格式转换后导出

        自定义格式转换的后导出可以参考上一篇《Springboot+Easyexcel:导入excl》中的日期、数字及其他自定义格式的转换部分,SalaryDateConverter#convertToExcelData(),导出时候的数据格式转换逻辑可以写在这里面;SalaryDateConverter#convertToJavaData()导入时候的数据格式转换的实现逻辑可以写在这里;SalaryDateConverter实现了com.alibaba.excel.converters.Converter接口;

        除了实现com.alibaba.excel.converters.Converterr接口,easyexcel也预置了一些常用的注解来实现格式转换,导入导出的时候都能用,如@DateTimeFormat、@NumberFormat;

这里特别注意别导错类了:

        com.alibaba.excel.annotation.format.DateTimeFormat;

        com.alibaba.excel.annotation.format.NumberFormat;

@Data
public class EmpSalary  {
    @ExcelProperty({"基本信息","姓名"})
    private String realName;
    @ExcelProperty({"基本信息","员工编号"})
    private String empNo;
    @DateTimeFormat("yyyy年MM月")
    @ExcelProperty(value = "工资日期")
    private Date salaryDate;
    @ExcelProperty({"工资构成","基本工资"})
    private Float baseAmount;
    @ExcelProperty({"工资构成","全勤奖"})
    private Float fullAttendAmount;
    @ExcelProperty({"工资构成","五险一金"})
    private Float insurance;
    //特别资金
    @ExcelIgnore
    @NumberFormat
    private Float specialAmount;
    @NumberFormat("#.##%")
    @ExcelProperty("绩效完成百分比")
    private Double jixiao;
}
@Test
public void writeByConverter(){
    String exportPath = this.getExportPath();
    String exportFile = exportPath + File.separator + "员工工资表v5.xlsx";
    List<EmpSalary> list=new ArrayList<>();
    EmpSalary empSalary = new EmpSalary();
    empSalary.setEmpNo("CH" + ( 1));
    empSalary.setRealName("张三" + ( 1));
    empSalary.setSalaryDate(new Date());
    empSalary.setBaseAmount(5000f);
    empSalary.setFullAttendAmount(500f);
    empSalary.setInsurance(300f);
    empSalary.setJixiao(0.9877);
    list.add(empSalary);
    EasyExcel.write(exportFile, EmpSalary.class).sheet("12月").doWrite(list);
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

maven学习手册

maven学习手册1.maven简介1.1 传统项目的弊端1.2 Maven是什么2.maven的安装和配置2.1 maven的安装2.2 为阿里云设置代理仓库2.3 maven常用命令简单说明3.maven实战3.1 一个简单的maven项目3.2 maven常用命令简单说明3.3 为这个简单的maven项目安装依赖3.4 maven常见标签说明4.依…

在搭载 M1 及 M2 芯片 MacBook 设备上玩 Stable Diffusion 模型

本篇文章&#xff0c;我们聊了如何使用搭载了 Apple Silicon 芯片&#xff08;M1 和 M2 CPU&#xff09;的 MacBook 设备上运行 Stable Diffusion 模型。 写在前面 在上一篇文章《使用 Docker 来快速上手中文 Stable Diffusion 模型&#xff1a;太乙》中&#xff0c;我们聊过…

传感器和变送器有什么区别?工业网关能用吗?

传感器和变送器在自动控制领域都有重要作用&#xff0c;但很容易混淆掉&#xff0c;两者有区别也有联系。 传感器是可以将感受到的信息转换成电信号或者其他信号&#xff0c;如将温度、压力、物料、气体等信息转换成电信号&#xff0c;从而使得这些数据可以网络中传输。 变送器…

软件测试必须知道的方法和知识

“软件测试技术是软件开发过程中的一个重要组成部分&#xff0c;是贯穿整个软件开发生命周期、对软件产品&#xff08;包括阶段性产品&#xff09;进行验证和确认的活动过程&#xff0c;其目的是尽快尽早地发现在软件产品中所存在的各种问题——与用户需求、预先定义的不一致性…

C++ 实现前缀树

一 、前缀树是什么 前缀树是一种查找结构&#xff0c;常用于指定字符串或是数组、线性表等连续信息的存储和查找。他的作用类似于哈希表&#xff0c;但是它相对于哈希表来说&#xff0c;限制更多&#xff0c;通用性较差&#xff0c;但是它的功能更加强大&#xff0c;可定制性也…

c#入门-字段类型访问权限低于字段本身

字段类型访问权限低于字段本身 现在假设你有一个小兵类&#xff0c;他的访问权限是仅限当前程序集。 internal class 小兵 {public int hp 12;public int atk 10;public int def 5; }然后声明一个兵营&#xff0c;用来创造小兵 public class 兵营 {public 小兵 模板;publ…

深度学习课件-实验1_PyTorch基本操作实验

文章目录一、Pytorch基本操作考察1.11.21.3二、动手实现 logistic 回归2.12.2三、动手实现softmax回归3.13.2一、Pytorch基本操作考察 使用 &#x1d413;&#x1d41e;&#x1d427;&#x1d42c;&#x1d428;&#x1d42b; 初始化一个 &#x1d7cf;&#x1d7d1; 的矩阵 &a…

第五、六章

第五章程序控制结构 5.1switch分支结构 每一个分支结构最后要记得加break;表示退出。 import java.util.Scanner; public class Switch01 { //编写一个 main 方法 public static void main(String[] args) { /* 请编写一个程序&#xff0c;该程序可以接收一个字符&#xff0…

我逛遍各大论坛,分享这份大厂招聘总结:涵盖Java岗位95%+真题

我们程序员这一群体&#xff0c;大家都知道最好的涨薪方法是通过跳槽&#xff0c;在你把一个公司的精华都吸收完之后&#xff0c;有追求的肯定会跳去更好的公司发展自己&#xff0c;特别在金三银四&#xff0c;金九银十这样的招聘旺季里 &#xff0c;会有很多需要准备的面试会有…

Snort入侵检测系统使用示例

1998年&#xff0c;Martin Roesch用C语言开发了开源的入侵检测系统Snort。现如今Snort已发展成为一个具有多平台、实时流量分析、网络IP数据包记录等特性的强大的网络入侵检测/防御系统&#xff0c;是世界最顶尖的开源入侵检测系统。Snort IDS利用一系列的规则去定义恶意网络活…

Qt-数据库开发-QDataWidgetMapper(5)

Qt-数据库开发-使用QDataWidgetMapper将数据库数据映射到小部件 文章目录Qt-数据库开发-使用QDataWidgetMapper将数据库数据映射到小部件1、概述2、实现效果3、主要代码4、完整源代码更多精彩内容&#x1f449;个人内容分类汇总 &#x1f448;&#x1f449;数据库开发 &#x1…

MYSQL数据库-复合查询

MYSQL数据库-复合查询零、前言一、基本查询二、多表查询三、自连接四、子查询1、单行子查询2、多行子查询3、多列子查询3、在from子句中使用子查询五、合并查询1、union2、union all零、前言 本章主要讲解学习MYSQL数据库中的复合查询&#xff0c;前面我们讲解的mysql表的查询都…

嵌入式分享合集119

一、传感器的数据处理算法 在传感器使用中&#xff0c;我们常常需要对传感器数据进行各种整理&#xff0c;让应用获得更好的效果&#xff0c;以下介绍几种常用的简单处理方法&#xff1a; 加权平滑&#xff1a;平滑和均衡传感器数据&#xff0c;减小偶然数据突变的影响。 抽取…

502问题怎么排查?

刚工作那会&#xff0c;有一次&#xff0c;上游调用我服务的老哥说&#xff0c;你的服务报"502错误了&#xff0c;快去看看是为什么吧"。 当时那个服务里正好有个调用日志&#xff0c;平时会记录各种200,4xx状态码的信息。于是我跑到服务日志里去搜索了一下502这个数…

【负荷预测】基于贝叶斯网络的考虑不确定性的短期电能负荷预测(Python代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

408 考研《操作系统》第二章第四节:进程同步和进程互斥

文章目录教程1. 进程同步2. 进程互斥3. 总结4. 进程互斥的软件实现方法4.1 单标志法4.2 双标志先检查法4.3 双标志后检查法4.4 Peterson算法4.5 总结5. 进程互斥的硬件实现方法5.1 中断屏蔽方法5.2 TestAndSet指令5.3 Swap指令5.4 总结教程 进程同步和进程互斥 https://www.bi…

【OpenCV学习】第11课:图像金字塔 - 上采样与降采样(高斯金字塔,放大与缩小图像)

仅自学做笔记用,后续有错误会更改 理论 参考文章链接:https://blog.csdn.net/qq_54185421/article/details/124350723 图像金字塔的概念&#xff1a; 从上往下&#xff08;采样点越来越多&#xff09;&#xff1a;上采样 从下往上&#xff08;采样点越来越少&#xff09;&a…

代码随想录刷题|LeetCode 503.下一个更大元素II 42. 接雨水 84.柱状图中最大的矩形

目录 503.下一个更大元素II 思路 下一个更大元素|| 42. 接雨水 思路 双指针法 动态规划 单调栈 接雨水 双指针法 动态规划 单调栈 84.柱状图中最大的矩形 思路 柱状图最大的矩形 动态规划 单调栈 503.下一个更大元素II 题目链接&#xff1a;力扣 思路 与 739. 每日温度 基本相…

STM32 | hex文件、bin文件、axf文件的区别?

已剪辑自: https://mp.weixin.qq.com/s/1EQRooYYpDeKvHpqguik6w 在STM32开发中&#xff0c;经常会碰到hex文件、bin文件与axf文件&#xff0c;这些都是可以烧写到板子里运行的文件。这三个文件有什么区别呢&#xff1f;在这之前&#xff0c;先来一起回顾一下C语言编译的过程&a…

详解c++---模板(初阶)

这里写目录标题为什么会有模板函数模板如何解决类型不同而导致模板无法实例化的问题类的模板为什么会有模板 c语言在面对同一个功能不同的类型的数据时得创建出来多个不同名的函数来依次达到目的&#xff0c;比如说我们下面的代码&#xff1a; #include<stdio.h> int a…