Springboot+Easyexcel:导出excel表格

news2025/1/11 14:05:23

常规导出

        常规导出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/76518.html

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

相关文章

彻底理解Python中浅拷贝和深拷贝的区别

目录 前言 1. 浅拷贝和深拷贝的概念 2. is和的区别 3. 赋值操作 4. copy模块里面的copy()方法 5. copy模块里面的deepcopy()方法 6.字典自带的copy方法 7.切片表达式拷贝 前言 Python 的所有变量其实都是指向内存中的对象的一个指针&#xff0c;这确实和之前学过的强类…

JDBC基本使用(第一个jdbc程序)

在web开发中&#xff0c;不可避免的地要使用数据库来存储和管理数据。为了在java语言中提供数据库访问的支持&#xff0c;Sun公司于1996年提供了一套访问数据的标准Java类库&#xff0c;即JDBC。 JDBC的全称是Java数据库连接(Java Database connect)&#xff0c;它是一套用于执…

Web3中文|AI机器人ChatGPT如何看待DeFi?

如果还没有玩过OpenAI最新的聊天机器人ChatGPT&#xff0c;那您真的应该体验一下。 从电影推介到编程查询&#xff0c;ChatGPT几乎可以对您向它提出的任何提示做出类似人类的逻辑响应。这种新奇的感觉就像乔布斯第一次滑动解锁iPhone屏幕时那样。 与加密货币一样&#xff0c;…

nacos配置在代码中如何引用

1、在代码的模块服务中安装nacos 配置依赖 <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency>2、在nacos配置中心中进行服务配置 注意不是模块名&#…

LeetCode刷题复盘笔记—一文搞懂动态规划之213. 打家劫舍 II问题(动态规划系列第十八)

今日主要总结一下动态规划完全背包的一道题目&#xff0c;213. 打家劫舍 II 题目&#xff1a;213. 打家劫舍 II Leetcode题目地址 题目描述&#xff1a; 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋&#xff0c;每间房内都藏有一定的现金。这个地方所有的房屋都 围成一…

电力系统短期负荷预测(Python代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

莲花-第10届蓝桥杯Scratch选拔赛真题精选

[导读]&#xff1a;超平老师计划推出Scratch蓝桥杯真题解析100讲&#xff0c;这是超平老师解读Scratch蓝桥真题系列的第99讲。 蓝桥杯选拔赛每一届都要举行4~5次&#xff0c;和省赛、国赛相比&#xff0c;题目要简单不少&#xff0c;再加上篇幅有限&#xff0c;因此我精挑细选…

16. 模型选择,欠拟合和过拟合 代码实现

我们现在可以通过多项式拟合来探索这些概念。 import math import numpy as np import torch from torch import nn from d2l import torch as d2l1. 生成数据集 max_degree 20 # 多项式的最大阶数&#xff0c;20个特征 n_train, n_test 100, 100 # 训练和测试数据集大小…

Kafka概念以及参数

概念&#xff1a; Concept: 主题&#xff1a;Topic。主题是承载消息的逻辑容器&#xff0c;在实际使用中多用来区分具体的业务。 Subject: Topic. A topic is a logical container that carries messages. In practice, it is often used to distinguish specific services.…

[附源码]计算机毕业设计的高校车辆租赁管理系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

在软件定义网络中使用机器学习的方法进行 DDOS 攻击检测与缓解--实验

在软件定义网络中使用机器学习的方法进行 DDOS 攻击检测与缓解--实验〇、拉取代码一、 配置环境二、 正常流量收集三、攻击流量数据四、DDoS攻击检测与缓解4.1 正常流量的检测4.2 攻击流量的检测与缓解五&#xff0c;精准度和检测率申明&#xff1a; 未经许可&#xff0c;禁止以…

Existence theorem

In mathematics, an existence theorem is a theorem which asserts the existence of a certain object.[1] It might be a statement which begins with the phrase “there exist(s)”, or it might be a universal statement whose last quantifier is existential (e.g., …

ADI Blackfin DSP处理器-BF533的开发详解22:SD卡的设计和实现原理及应用(含源码)

硬件准备 ADSP-EDU-BF533&#xff1a;BF533开发板 AD-HP530ICE&#xff1a;ADI DSP仿真器 软件准备 Visual DSP软件 硬件链接 功能介绍 ADSP-EDU-BF53x 板卡上设计了一个 SD/MMC 接口&#xff0c;可以通过该接口实现对 SD/MMC 卡数据的访问。 SD 卡有两种工作模式&#x…

C#使用 Async 和 Await 的异步编程

总目录 文章目录总目录前言一、概述二、命名规范三、await/async的作用四、基本使用五、使用Async和Await实现多任务顺序执行且不阻塞1.同步执行2.并行执行3.并行且可指定顺序执行总结前言 C# 中的 Async 和 Await 关键字是异步编程的核心。 通过这两个关键字&#xff0c;可以…

spring依赖查找、依赖注入深入学习及源码分析

文章目录一、依赖查找1、单一类型依赖查找&#xff08;接口 - BeanFactory&#xff09;根据Bean名称查找根据Bean类型实时查找根据Bean类型延迟查找&#xff08;Spring 5.1&#xff09;根据Bean名称类型查找2、集合类型依赖查找&#xff08;接口 - ListableBeanFactory&#xf…

Metal每日分享,颜色转换滤镜效果

本案例的目的是理解如何用Metal实现像素颜色转换滤镜&#xff0c;通过对像素颜色的不同读取方式获取到相应像素颜色&#xff0c;灰度图移除场景中除了黑白灰以外所有的颜色&#xff0c;让整个图像灰度化&#xff1b; Demo HarbethDemo地址 实操代码 // 转成灰度图滤镜 let f…

js深拷贝浅拷贝与lodash

title: js深拷贝浅拷贝与lodash date: 2022/9/27 14:46:25 categories: lodashjs入门 深拷贝和浅拷贝 ref&#xff1a;JS传递参数时的内部存储逻辑 JS 變數傳遞探討&#xff1a;pass by value 、 pass by reference 還是 pass by sharing&#xff1f; 在这个问题前&#xff…

LeetCode HOT 100 —— 169.多数元素

题目 给定一个大小为 n 的数组 nums &#xff0c;返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。 你可以假设数组是非空的&#xff0c;并且给定的数组总是存在多数元素。 思路 方法一&#xff1a;哈希表 遍历整个数组&#xff0c;记录每个数值出…

JAVA IO详解

目录 一、流的概念与作用 二、Java IO的用途和特征 三、流的使用详解 一、流的概念与作用 流(Stream)&#xff1a; 在Java IO中&#xff0c;流是一个核心的概念。流从概念上来说是一个连续的数据传输过程。人们根据数据传输特性将流抽象为各种类&#xff0c;方便更直观的进…

【服务器数据恢复】服务器raid5崩溃导致上层应用不可用的数据恢复案例

服务器数据故障&#xff1a; 某公司服务器8块硬盘组成raid5磁盘阵列&#xff0c;其中有2块硬盘故障指示灯报警&#xff0c;其他硬盘指示灯正常&#xff0c;上层应用不可用。 服务器数据恢复过程&#xff1a; 1、服务器数据恢复工程师拿到故障服务器所有硬盘后对出现物理故障的…