hutool poi、apache poi实现导入导出以及解析excel

news2024/11/25 20:24:46

一、前言

看了例子之后后续需要更加深入学习或者更多理解其他API的话,建议看官方文档。hutool项目是中国人维护的,有中文文档,阅读起来很方便。apache poi比较底层一点,可以更加自由去二次开发自己所需的功能。

hutool官方文档
hutool官方gitee
apache poi官方文档

二、基于hutool poi 实现导出excel文件到本地

有两种写法,可以一开始就为ExcelWriter 指定要写的文件,另一种是等到要flush的时候再指定对应文件的输出流。两种写法都能实现,不过第二种写法会显得更灵活一点,可以到后面再慢慢决定要输出到哪个文件。

具体实现逻辑

import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class PoiTest {
    private int age;
    private String name;

   
    public PoiTest() {
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public PoiTest(int age, String name) {
        this.age = age;
        this.name = name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        PoiTest poiTest = (PoiTest) o;
        return age == poiTest.age && Objects.equals(name, poiTest.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(age, name);
    }

    @Override
    public String toString() {
        return "PoiTest{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }

    public static void main(String[] args) throws IOException {
    	//方式一
        File file=new File("E:\\自测资料\\test.xlsx");
        file.createNewFile();
        ExcelWriter bigWriter = ExcelUtil.getBigWriter();
        bigWriter.setDestFile(file);
        List<PoiTest> list=new ArrayList<>();
        for (int i=0;i<10;i++){
            list.add(new PoiTest(18+i,"小明"+i));
        }
        //将数据写入到ExcelWriter的workbook中
        bigWriter.write(list);
        //将数据写入excel表
        bigWriter.flush();
        //关闭资源
        bigWriter.close();
		
//		//方式二
//        ExcelWriter bigWriter = ExcelUtil.getBigWriter();
//        List<PoiTest> list=new ArrayList<>();
//        for (int i=0;i<10;i++){
//            list.add(new PoiTest(18+i,"小明"+i));
//        }
//        bigWriter.write(list);
//
//        File file=new File("E:\\自测资料\\test.xlsx");
//        file.createNewFile();
//        OutputStream outputStream=new FileOutputStream(file);
//        bigWriter.flush(outputStream);
//        bigWriter.close();
    }
}

运行结果

在这里插入图片描述

三、基于hutool poi 实现从本地导入excel文件并转成对象列表

导入可以用map,list,对象来存储一行记录,推荐使用对象,方便后期使用。

具体实现逻辑

import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class PoiTest {
    private int age;
    private String name;

   
    public PoiTest() {
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public PoiTest(int age, String name) {
        this.age = age;
        this.name = name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        PoiTest poiTest = (PoiTest) o;
        return age == poiTest.age && Objects.equals(name, poiTest.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(age, name);
    }

    @Override
    public String toString() {
        return "PoiTest{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }

    public static void main(String[] args) throws IOException {
//方式一
        File file=new File("E:\\自测资料\\test.xlsx");
        ExcelReader reader = ExcelUtil.getReader(file);
        //list中的每个map对应excel表中的一行记录,excel表第一行(字段名)当作key,value就是行记录对应列的值
        List<Map<String, Object>> maps = reader.readAll();
        for(Map map:maps){
            Set<String> set = map.keySet();
            for(String key:set){
                System.out.println(key+"-->"+map.get(key));
            }
            System.out.println("-----------");
        }
        reader.close();
	
//方式二	
//        //list返回,内部的list,每一个list代表一行记录,第一行记录可以当作表头。
//        List<List<Object>> read = reader.read();
//        for(List list:read){
//            for (Object o:list){
//                System.out.println(o);
//            }
//            System.out.println("-----");
//        }
//        reader.close();

//方式三
//        //根据表头名和实体对象字段名来匹配记录,并返回实体列表
//        File file=new File("E:\\自测资料\\test.xlsx");
//        ExcelReader reader = ExcelUtil.getReader(file);
//        /**
//         *  第一个参数是表头所在行;第二个参数是读取数据开始行,会自动过滤掉表头行;第三个参数是实体类
//         *  如果行记录所有列都为空,则会跳过该行记录,不创建对象。只要有一个列是不为空的,就会创建对象
//         **/
//        List<PoiTest> read = reader.read(0, 0, PoiTest.class);
//        reader.close();
//        for(PoiTest poiTest:read){
//            System.out.println(poiTest);
//        }
    }
}

运行结果

map方式返回结果

在这里插入图片描述
list方式返回结果:(excel中只要行记录存在,那么空的列会保存为空字符串)
在这里插入图片描述
对象列表方式返回结果:
在这里插入图片描述

四、基于apache poi实现根据传入的类将excel的输入流解析成类对象(必学***)

这个就是我们日常使用的excel上传功能,因此非常有必要掌握。
一开始就想过可以通过传入类名,结合反射机制来创建对象,还可以获取对象的字段并赋值,实际上思路也确实大概这样。我从chat-gpt拿到了一个解析excel输入流的demo,不过这个demo并没有把excel表第一行当作表头;因此,我在这个基础上做了一些修改,实现了解析excel文件输入流成对象的工具类方法。(tips:支持的数据类型只能是比较基础的类型,不能是复杂的对象,复杂对象先json字符串接收,后面再自己转)
动态代理太酷啦!!!

实体类对象(也就是要解析成的对象)

package com.yumoxuan.pojo;
import java.util.Date;
import java.util.Objects;
public class Person {
    private int age;
    private String name;
    private Date birthday;
    private double high;

    public Person() {
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public double getHigh() {
        return high;
    }

    public void setHigh(double high) {
        this.high = high;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age &&
                Double.compare(person.high, high) == 0 &&
                Objects.equals(name, person.name) &&
                Objects.equals(birthday, person.birthday);
    }

    @Override
    public int hashCode() {
        return Objects.hash(age, name, birthday, high);
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", birthday=" + birthday +
                ", high=" + high +
                '}';
    }
}

具体实现逻辑

import com.yumoxuan.pojo.Person;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.lang.reflect.Field;
public class ExcelParser {
    public static <T> List<T> parseExcelFile(InputStream inputStream, Class<T> clazz) {
        List<T> objectList = new ArrayList<>();

        try (Workbook workbook = new XSSFWorkbook(inputStream)) {
            Sheet sheet = workbook.getSheetAt(0); // Assuming the data is in the first sheet

            // Get the field names from the class
            Field[] fields = clazz.getDeclaredFields();
             List<String> objectFieldNameList= Arrays.stream(fields).map(o->o.getName()).collect(Collectors.toList());
            //获取excel第一行作为对象的字段名
                       List<String> excelFieldNameList = new ArrayList<>();
            boolean firstRow = true;
            // Iterate over rows in the sheet
            for (Row row : sheet) {
                T object = clazz.newInstance(); // Create an instance of the class

                // Map cell values to object fields
                int i = 0;
                for (Cell cell : row) {
                    if (firstRow) {
                        //获取excel表的第一行作为字段名
                        excelFieldNameList.add(cell.getStringCellValue());
                        continue;
                    }
                   	
                    if(!objectFieldNameList.contains(excelFieldNameList.get(i))){
                        //过滤excel中存在,但类中不存在的字段
                        continue;
                    }
                    //注意,这里如果尝试获取类里面没有的字段,会抛异常,因此excel表结构最好协商定下来。当然有了上一步的判断,这个问题不会发生
                    Field field = clazz.getDeclaredField(excelFieldNameList.get(i));
                    //开启编辑权限
                    field.setAccessible(true);
                    Class<?> fieldType = field.getType();

                    // 这里只需要把可能的数据类型都加上就可以了;不过一般也就那么基本数据类型加上字符串
                    if (fieldType == String.class) {
                        field.set(object, cell.getStringCellValue());
                    } else if (fieldType == int.class || fieldType == Integer.class) {
                        field.set(object, (int) cell.getNumericCellValue());
                    } else if (fieldType == boolean.class || fieldType == Boolean.class) {
                        field.set(object, cell.getBooleanCellValue());
                    } else if (fieldType == double.class || fieldType == Double.class) {
                        field.set(object, cell.getNumericCellValue());
                    } else if (fieldType == float.class || fieldType == Float.class) {
                        field.set(object, (float) cell.getNumericCellValue());
                    } else if (fieldType == Date.class) {
                        field.set(object, cell.getDateCellValue());
                    } else {
                        //暂不支持的类型
                    }
                    i++;
                    //关闭编辑权限
                    field.setAccessible(false);
                }
                if (!firstRow) {
                    objectList.add(object);
                }
                firstRow = false;
            }
        } catch (IOException | ReflectiveOperationException e) {
            e.printStackTrace();
        }

        return objectList;
    }

    public static void main(String[] args) throws FileNotFoundException {
        File file = new File("F:\\JAVA\\test.xlsx");
        InputStream inputStream = new FileInputStream(file);
        List<Person> people = ExcelParser.parseExcelFile(inputStream, Person.class);
        for (Person person : people) {
            System.out.println(person);
        }
    }
}

excel文件路径及数据

在这里插入图片描述

运行结果

Person{age=18, name=‘张三’, birthday=Mon Dec 25 12:13:00 CST 2000, high=163.25}
Person{age=19, name=‘李四’, birthday=Tue Dec 26 12:13:00 CST 2000, high=180.25}

学无止境,共勉。如果有帮到你,给我点个赞吧。

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

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

相关文章

zkML零知识机器学习介绍

1. 引言 零知识证明技术的2大基石为&#xff1a; 1&#xff09;succinctness&#xff1a;相比于直接运行整个计算本身&#xff0c;验证该计算完整性证明要简单很多。2&#xff09;zero-knowledge&#xff1a;可在不泄露计算隐私的情况下&#xff0c;证明计算的完整性。 生成…

【Java入门】-- Java基础详解之 [数组、冒泡排序]

目录 1.为什么需要数组&#xff1f; 2.数组的介绍 3.数组的快速入门 4.数组的使用 5.动态初始化 6.静态初始化 7.数组的细节 8.数组的赋值机制 9.数组拷贝 10.数组反转 11.二维数组 12.冒泡排序 1.为什么需要数组&#xff1f; 有五个学生&#xff0c;他们英语成绩…

探索不同学习率对训练精度和Loss的影响

验证精度、验证Loss的影响 1 问题 在探索mnist数据集过程中&#xff0c;学习率的不同&#xff0c;对我们的实验结果&#xff0c;各种参数数值的改变有何变化&#xff0c;有何不同。 学习率对精度和损失的影响研究。训练周期100学习率 [0.1, 0.01, 0.001, 0.0001](1) 不同学习率…

蓝牙网关Gateway_数据采集,连接控制,室内定位VDB2602

蓝牙网关&#xff0c;内部集成了WiFi、蓝牙、4G等多种无线通信方式&#xff0c;因此也继承了蓝牙、WiFi的有扫描功能、连接功能、数据透传功能&#xff0c;被应用于智能家居的各种场景中&#xff0c;例如&#xff1a;远程控制BLE装置&#xff0c;接收BLE设备发送的数据&#xf…

线程的创建和使用(一)

1、线程 1.1、线程的概念 一个线程就是一个 "执行流". 每个线程之间都可以按照顺讯执行自己的代码. 多个线程之间 "同时" 执行着多份代码. 1.2、创建线程 方法一&#xff1a;继承Thread类 public class Exe_01 {public static void main(String[] args…

pandas与pyspark计算效率对比

日常工作中&#xff0c;主要还是应用HQL和SparkSQL&#xff0c;数据量大&#xff0c;分布式计算很快&#xff1b; 本地数据处理&#xff0c;一般会使用python的pandas包&#xff0c;api丰富&#xff0c;写法比较简单&#xff0c;但只能利用单核性能跑数&#xff0c;数据量大可…

【MySQL入门】-- 数据库简单的SELECT语句详解

目录 1.SQL分类 2.注释 3.数据导入指令 4.基本的SELECT语句 5.列的别名 6.去重复行 7.显示表结构 8.一些数据库基本操作 1.SQL分类 SQL语言在功能上主要分为三大类&#xff1a; DDL(Data Defintion Language)数据定义语言&#xff1a;定义不同的数据库&#xff0c;表…

【C#】并行编程实战:任务并行性(中)

本章继续介绍任务并行性&#xff0c;因篇幅所限&#xff0c;本章为中篇。 4、取消任务 .NET Framework 提供了以下两个类来支持任务取消&#xff1a; CancellationTokenSource &#xff1a;此类负责创建取消令牌&#xff0c;并将取消请求传递给通过源创建的所有令牌。 Cancell…

关于xinput1_3.dll丢失的详细解决方法

xinput1_3.dll是电脑文件中的dll文件&#xff08;动态链接库文件&#xff09;。如果计算机中丢失了某个dll文件&#xff0c;可能会导致某些软件和游戏等程序无法正常启动运行&#xff0c;并且导致电脑系统弹窗报错。 在我们打开软件或者游戏的时候&#xff0c;电脑提示xinput1_…

8、共享模型之工具

目录 8.1 线程池2、ThreadPoolExecutor&#xff08;及其重要&#xff09;1) 线程池状态2) 构造方法3) newFixedThreadPool4) newCachedThreadPool5) newSingleThreadExecutor6) 提交任务7) 关闭线程池8) 任务调度线程池 8.1 线程池 2、ThreadPoolExecutor&#xff08;及其重要…

中国电子学会2023年05月份青少年软件编程Python等级考试试卷六级真题(含答案)

2023-05 Python六级真题 分数&#xff1a;100 题数&#xff1a;38 测试时长&#xff1a;60min 一、单选题(共25题&#xff0c;共50分) 1. 明明每天坚持背英语单词&#xff0c;他建立了英语单词错题本文件“mistakes.txt”&#xff0c;将每天记错的单词增加到该文件中&…

DuiLib的编译和运行

文章目录 1、原生DuiLib的编译和运行1.1、下载并解压成这个样子1.2、打开.sln解决方案文件1.3、编译成功 2、网易DuiLib编译和运行2.1、下载并解压成这个样子2.2、打开.sln解决方案文件2.3、编译成功 3、腾讯DuiLib编译和运行vs 20173.1、下载并解压成这个样子3.2、打开.sln解决…

使用 Node.js、K8s 和分布式 SQL 构建世界上最具弹性的待办事项列表应用程序

本文演示了如何使用 Kubernetes (K8s) 和分布式 SQL 构建云原生 Node.js 应用程序。 开发可扩展且可靠的应用程序是一项热爱的工作。一个云原生系统可能包括单元测试、集成测试、构建测试&#xff0c;以及用于构建和部署应用程序的完整管道&#xff0c;只需单击一个按钮即可。 …

【计算机网络】第二章应用层-电子科技大学2023期末考试

第二章 应用层 应用层协议原理 网络应用程序体系结构 客户机/服务器体系结构&#xff1a;至少有一个服务器&#xff0c;一个客户机&#xff0c;其中服务器总是打开的&#xff0c;具有固定的众所周知的IP地址&#xff0c;主机群集常被用于创建强大的虚拟服务器&#xff0c;而客…

【Trino实战】Trino下ORC与Parquet查询性能分析

Trino下ORC与Parquet查询性能分析 环境 OS&#xff1a;CentOS 6.5 JDK&#xff1a;1.8 内存&#xff1a;256G 磁盘&#xff1a;HDD CPU&#xff1a;Dual 8-core Intel Xeon CPU (32 Hyper-Threads) E5-2630 v3 2.40GHz HDFS&#xff1a;2.9.2 Hive&#xff1a;2.3.9 T…

[n00bzCTF 2023] CPR 全

Crypto AES 给了java的加密原码&#xff0c;AES加密&#xff0c;有key import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.SecretKeySpec; import java.n…

arima模型原理及实战

目录 1&#xff0c;概念 2&#xff0c;数学知识 3&#xff0c;前提条件 4&#xff0c;序列不平稳时的平稳性方法 5&#xff0c;模型定阶&#xff0c;确定P和Q 6&#xff0c;模型训练与检验 1&#xff0c;概念 ARIMA模型&#xff08;英语&#xff1a;Autoregressive Integr…

grep及文本处理命令

正则表达式 一.基础命令 1.grep命令 对文本的内容进行过滤&#xff0c;针对行处理 1.1grep格式 grep [选项]…查找条件 目标文件 1.2grep命令选项 -m数字——————匹配几次后停止eg&#xff1a;grep -m 1 root /etc/passwd————————————多个匹配只取 -v …

【编程语言 · C语言 · 递归函数】

递归函数 C 语言的函数都支持递归, 也就是说&#xff0c;每个函数都可以直接或者间接第调用自己。所谓的间接调用&#xff0c;是指在递归函数调用的下层函数中再调用自己。 递归关系图如下&#xff1a; 递归之所以能实现&#xff0c;是因为函数的每个执行过程在栈中都有自己的…

深入理解 SpringBoot 日志框架:从入门到高级应用——(三)Logback 输出日志到 MySQL 数据库

文章目录 添加依赖导入 SQL 文件配置 logback-spring.xml运行结果 Logback 是一个开源的日志框架&#xff0c;它支持多种日志输出方式&#xff0c;包括控制台输出、文件输出、邮件输出等。如果要将 Logback 输出的日志保存到 MySQL 数据库中&#xff0c;可以按照以下步骤进行配…