java通过EasyExcel实现导入导出(导入、模板导出、和不需要模板的导出)

此文章只是涉及到简单的导入导出

  1. 通过实体模板导入数据
  2. 无实体模板导入数据
  3. 导出数据
  4. 通过模板导出数据

使用到的maven依赖

<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional>
</dependency>
<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.16</version>
</dependency>
<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.3.0</version>
</dependency>

用到的实体和工具类

package com.example.entity;import cn.hutool.core.date.DatePattern;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import lombok.Data;import java.util.Date;/*** @Author user* @Date 2023/5/6 12:03* @Description*/@Data
public class User {@ExcelProperty(value = "姓名",index = 0)private String name;@ExcelProperty(value = "年龄",index = 1)private Integer age;@ExcelProperty(value = "性别",index = 2)private String sex;@ExcelProperty(value = "生日",index = 3)@DateTimeFormat(value = DatePattern.NORM_DATE_PATTERN)private Date birthday;@ExcelProperty(value = "备注",index = 4)private String remark;
}
package com.example.util;import com.alibaba.excel.annotation.ExcelProperty;
import org.apache.poi.ss.usermodel.*;import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;/*** @Author user* @Date 2023/5/6 12:38* @Description*/
public class ExcelUtil {/*** 手写校验表头* @param is excel文件流* @param clazz 模板类*/public static void checkExcelHeaders(InputStream is, Class clazz) {List<String> inputList = new ArrayList<>();List<String> requiredList = new ArrayList<>();Field[] allFields = clazz.getDeclaredFields();for (int i = 0; i < allFields.length; ++i) {Field field = allFields[i];ExcelProperty attr = field.getAnnotation(ExcelProperty.class);if (null != attr) {//excel里面加入多余的字段requiredList.add(attr.value()[0]);}}try {Workbook wb = WorkbookFactory.create(is);Sheet sheet = wb.getSheetAt(0);Row row = sheet.getRow(0);for (Iterator<Cell> iter = row.cellIterator(); iter.hasNext(); ) {Cell cell = iter.next();inputList.add(cell.getStringCellValue());}} catch (IOException e) {e.printStackTrace();}if (requiredList.stream().anyMatch(e -> !inputList.contains(e))|| inputList.stream().anyMatch(e -> !requiredList.contains(e))) {throw new RuntimeException("Excel表头不一致");}}/*** 设置返回的头部信息* @param response 返回流信息* @param fileName 文件名称*/public static void setResponse(HttpServletResponse response, String fileName){//设置头response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding("utf-8");String excelFileName = null;try {excelFileName = URLEncoder.encode(fileName, String.valueOf(StandardCharsets.UTF_8)).replaceAll("\\+", "%20");} catch (UnsupportedEncodingException e) {e.printStackTrace();}response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");/*** attachment这个代表要下载的,如果去掉就直接打开了(attachment-作为附件下载,inline-在线打开)* excelFileName是文件名,另存为或者下载时,为默认的文件名*/response.setHeader("Content-disposition", "attachment;filename=" + excelFileName + ".xlsx");response.setHeader("Content-Type", "application/octet-stream;charset=utf-8");}
}

导入(读)数据的几个方式

  • 无实体模板都数据
// 无模板读取数据,此处read的重载方法很多,这里用到的是输入流的方式
List<Object> list = EasyExcel.read(file.getInputStream()).sheet(0).doReadSync();
  • 通过实体模板的方式导入数据
// 有模板读取数据无监听器
List<Object> doReadSync = EasyExcel.read(file.getInputStream(), User.class, null).sheet(0).doReadSync();

读取到对应的数据后通过序列化的方式转换为我们所使用到的对象列表

/通过序列化转换成对应的数据
List<User> users = JSONUtil.toList(JSONUtil.toJsonStr(doReadSync), User.class);
  • 通过监听器的方式读取数据
//通过监听器读取文件
/*** headRowNumber:当读数据时, 0 -这个表没有头,因为第一行是数据 1 -该表有一个行头,这是默认的 2 -这张表有两行头,因为第三行是数据
*/
EasyExcel.read(file.getInputStream(), User.class, new UserListener()).headRowNumber(1).sheet().doRead();

监听器的类

package com.example.listener;import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.example.entity.User;import java.util.HashMap;
import java.util.Map;/*** 这里监听器不要托管Spring* @Author user* @Date 2023/5/6 14:42* @Description*/
public class UserListener extends AnalysisEventListener<User> {Map<Integer, String> headMap = new HashMap<>();Map<Integer, User> userMap = new HashMap<>();public UserListener() {}/*** 这里可以获取到Excel对应的表头* @param headMap 表头* @param context*/@Overridepublic void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {this.headMap = headMap;}/*** 这里会把解析到的每一行的数据在这里处理* 我这里用来获取了行号, 把每一行的数据放进map中* @param data 行数据* @param context*/@Overridepublic void invoke(User data, AnalysisContext context) {//获取当前行 || 这里也可以进行校验数据的空属性等问题Integer rowIndex = context.readRowHolder().getRowIndex() + 1;// 这里的话不需要行号的话可以放进list列表中userMap.put(rowIndex, data);}/*** 这里是把所有的数据解析完成后做的最后处理,我这里是用来校验入库。* @param context*/@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {//校验表头checkHead();/*** 校验是否符合入库标准*/// 保存入库}public void checkHead(){String[] headList = {"姓名", "年龄", "性别", "生日", "备注"};for (int i = 0; i < headList.length; i++) {if (!headMap.get(i).equals(headList[i])) {throw new RuntimeException("Excel模板不匹配, 请核对模板表头", null);}}}
}

推荐官网的监听器(可以进行分批读取和保存数据)监听器读数据 更专业清晰

导出数据的几个方式

  • 无模板导出 (很简单)
    实体类
package com.example.entity;import cn.hutool.core.date.DatePattern;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import lombok.Data;import java.util.Date;/*** @Author user* @Date 2023/5/6 12:03* @Description*/@Data
public class User {@ExcelProperty(value = "姓名",index = 0)private String name;@ExcelProperty(value = "年龄",index = 1)private Integer age;@ExcelProperty(value = "性别",index = 2)private String sex;@ExcelProperty(value = "生日",index = 3)@DateTimeFormat(value = DatePattern.NORM_DATE_PATTERN)private Date birthday;@ExcelProperty(value = "备注",index = 4)private String remark;
}
List<User> userList = new ArrayList<>();
//这里是初始化的数据,实际业务中是从数据库中查询出来的数据
DataList.initializationUser(userList);
ExcelUtil.setResponse(response, "测试用户数据导出");
try {EasyExcelFactory.write(response.getOutputStream(), User.class).sheet("用户信息").doWrite(userList);
} catch (IOException e) {e.printStackTrace();
}

复杂的导出请参考官网

  • 有模板导出

用到的实体

TotalTiWen

package com.example.entity.tiwen;import lombok.Data;/*** @Author user* @Date 2023/5/6 13:40* @Description*/@Data
public class TotalTiWen {private String a;private String b;private String c;private String d;private String e;private String f;private String g;private String h;
}

TiWen

package com.example.entity.tiwen;import lombok.Data;/*** @Author user* @Date 2023/5/6 13:40* @Description*/
@Data
public class TiWen {private String j;private String k;private String l;private String m;
}

有模板导出步骤

  1. 获取模板 (自定义的模板)
  2. 查询数据(从数据库查询的数据)
  3. 写入Excel数据

第一步: 准备模板(读取模板文件) - 模板的格式 (注意列表数据是带点的)

//我把模板文件放到了resource下面了,所以读取resource下的模板文件 && 这里也可以是从服务器获取到的文件
InputStream inputStream = ResourceUtil.getResourceObj("templates/tiwen.xlsx").getStream();

第二步:查询数据(我这里是初始化的数据)正常业务中是从数据库中查询出来的数据

//处理数据
TotalTiWen tiWen = new TotalTiWen();
List<TiWen> tiWenList = new ArrayList<>();
//TODO 初始化数据,这里的数据,实际是从数据库中查询出来的
DataList.initializationTiWen(tiWen, tiWenList);
public static void initializationTiWen(TotalTiWen totalTiWen, List<TiWen> tiWens){totalTiWen.setA("王小海");totalTiWen.setB("海克斯科技");totalTiWen.setC("15617223895");totalTiWen.setD("000023");totalTiWen.setE("20");totalTiWen.setF("MMOO99");totalTiWen.setG("34");totalTiWen.setH("测试机器");TiWen t = new TiWen();t.setJ("1");t.setK("2022-03-19");t.setL("103");t.setM("OOMM9923321312");TiWen t1 = new TiWen();t1.setJ("2");t1.setK("2022-06-19");t1.setL("552");t1.setM("OOMM99232312");TiWen t2 = new TiWen();t2.setJ("3");t2.setK("2022-10-30");t2.setL("423");t2.setM("OOMM99231123");TiWen t3 = new TiWen();t3.setJ("4");t3.setK("2022-12-24");t3.setL("674");t3.setM("OOMM99233");TiWen t4 = new TiWen();t4.setJ("5");t4.setK("2022-11-16");t4.setL("423423");t4.setM("OOMM99232");tiWens.add(t);tiWens.add(t1);tiWens.add(t2);tiWens.add(t3);tiWens.add(t4);}

第三步:设置response头部信息(这里是浏览器下载格式)下面用到的工具类在上面

ExcelUtil.setResponse(response, "文件名");

第四步:写入Excel

ServletOutputStream outputStream = null;
try {outputStream = response.getOutputStream();
} catch (IOException e) {e.printStackTrace();
}
//设置创建行的方式
FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
ExcelWriter excelWriter = EasyExcel.write(outputStream).withTemplate(inputStream).excelType(ExcelTypeEnum.XLSX).build();
//写入到sheet
WriteSheet oneSheet = EasyExcel.writerSheet(0).build();
//填充
excelWriter.fill(tiWen, oneSheet);
excelWriter.fill(tiWenList, fillConfig, oneSheet);

第五步:关闭对应的流

//关流
excelWriter.finish();
IOUtils.closeQuietly(inputStream);
IOUtils.closeQuietly(outputStream);
  • 多sheet导出 (替换上面第四步就行了)

多sheet导出其实和单个sheet一样,只不过是多写入了几次而已

sheet名称就是 打开excel的左下角名称(默认是sheet1 、sheet2、sheet3)

//设置创建行的方式
FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
ExcelWriter excelWriter = EasyExcel.write(outputStream).withTemplate(inputStream).excelType(ExcelTypeEnum.XLS).build();
//创建第一个sheet 这里是根据sheet的名称写入数据
WriteSheet oneSheet = EasyExcel.writerSheet("EXPORT BILL").build();
/**
* excelDto : 第一个sheet的头部
* goodList :第一个sheet的列表数据
*/
excelWriter.fill(excelDto, oneSheet);
excelWriter.fill(goodList, fillConfig, oneSheet);
//创建第二个sheet 这里是根据sheet的名称写入数据
WriteSheet twoSheet = EasyExcel.writerSheet("INV").build();
/**
* 第二个sheet
* totalExcelDto: 第二个sheet的头部
* informationList:第二个sheet的列表数据
*/
excelWriter.fill(informationList, fillConfig, twoSheet);
excelWriter.fill(totalExcelDto, twoSheet);//创建第三个sheet 这里是根据sheet的名称写入数据
WriteSheet thirdSheet = EasyExcel.writerSheet("PACKINGLIST").build();
/**
* 第三个sheet
* listExcelDto: 第三个sheet的头部
* infoExcelDtoList:第三个sheet的列表数据
*/
excelWriter.fill(infoExcelDtoList, fillConfig, thirdSheet);
excelWriter.fill(listExcelDto, thirdSheet);
// 下面就是关闭流了,同第五步

java使用EasyExcel实现导入导出几种方式(导入、模板导出、和不需要模板的导出)相关推荐

  1. 读取Java文件到byte数组的三种方式及Java文件操作大全(包括文件加密,String加密)

    读取Java文件到byte数组的三种方式 package zs;import java.io.BufferedInputStream; import java.io.ByteArrayOutputSt ...

  2. Android之Android Studio三种方式导入外部资源 以及 报错处理

    Android Studio三种方式导入外部资源 以及 报错处理 android studio提供了三种方式导入外部资源: 1. Library dependency – 在线添加.需联网下载 . 2 ...

  3. Java异步非阻塞编程的几种方式

    简介: Java异步非阻塞编程的几种方式 一. 从一个同步的Http调用说起 一个很简单的业务逻辑,其他后端服务提供了一个接口,我们需要通过接口调用,获取到响应的数据. 逆地理接口:通过经纬度获取这个 ...

  4. 【java】Java运行时动态生成类几种方式

    1.概述 转载:Java运行时动态生成类几种方式 这里发现自己不知道的,原来Java 还能自己编译自己,学到了. 最近一个项目中利用规则引擎,提供用户拖拽式的灵活定义规则.这就要求根据数据库数据动态生 ...

  5. java的如何创建js_[Java教程]JS创建事件的三种方式(实例)

    [Java教程]JS创建事件的三种方式(实例) 0 2016-05-11 14:00:16 1.普通的定义方式 οnclick="Sfont=prompt('请在文本框中输入红色','红色' ...

  6. Java中线程的创建有两种方式

    Java中继承thread类与实现Runnable接口的区别 Java中线程的创建有两种方式: 1.  通过继承Thread类,重写Thread的run()方法,将线程运行的逻辑放在其中 2.  通过 ...

  7. Java实现回文串的四种方式

    Java实现回文串的两种方式 1.什么是回文串? "回文串"是一个正读和反读都一样的字符串,如"level"或者"noon"等就是回文串. ...

  8. Java中遍历Map集合的5种方式总结

    这篇文章主要给大家介绍了关于Java中遍历Map集合的5种方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值. 方式一 通过Map.keySet使用iterator遍历 ...

  9. Java生成唯一标识码的三种方式

    Java生成唯一标识码的三种方式 前言 我们经常会遇到这样的场景,需要生成一个唯一的序列号来表明某一个数据的唯一性,在单节点的应用中我们可以简单地使用一个自增的整型来实现实现,但是在分布式情况下这个方 ...

  10. java的list遍历_【java】list集合遍历的5种方式

    平凡也就两个字: 懒和惰; 成功也就两个字: 苦和勤; 优秀也就两个字: 你和我. 跟着我从0学习JAVA.spring全家桶和linux运维等知识,带你从懵懂少年走向人生巅峰,迎娶白富美! 关注微信 ...

最新文章

  1. 计算机基本知识培训稿,计算机基础知识培训稿.doc
  2. 一个不错的SQL储存过程分页,储存过程+Repeater,如果只是浏览数据的话,快就一个字...
  3. boost::histogram::make_profile用法的测试程序
  4. 在GitHub中创建目录
  5. 【转】如何更改VS2010的[默认开发语言]默认环境设置 .
  6. 数据结构-顺序查找和折半查找
  7. redis源码剖析(十二)—— RDB持久化
  8. 你是第几名:Excel 中 Large 和 Small 的用法
  9. git merge 与 git rebase的区别
  10. python安装后无法打开文本_Python 安装zbar-py时出现 无法打开包括文件: “unistd.h” no such file or directory...
  11. html期末作业代码网页设计——代码质量好-宠物网(8页) HTML+CSS+JavaScript 学生DW网页设计作业成品 web课程设计网页规划与设计 计算机毕设网页设计源码
  12. 数据库系统原理练习题
  13. 美国加拿大结婚证公证及使馆认证流程时间用于国内法院离婚
  14. 十一假期,终于过上了理想的生活节奏
  15. Linux之yum 命令详解
  16. 魅力网络技术博客图像处理正文 ps入门教程、ps修图基本工具使用方法视频教学...
  17. 深度学习之LSTM案例分析(三)
  18. RT-Thread功耗调优项目实战 - 如何做好功耗
  19. pinyin4j使用示例(支持多音字)
  20. Java中的逻辑运算符/移位运算符简单总结

热门文章

  1. 我是如何逐步学会“好好说话”的
  2. 如何抢努比亚z9 max
  3. 一步步教你如何在SpringBoot项目中引入支付功能
  4. 达人评测 i9 12900hk和 i9 11980hk 差距大不大
  5. beoplay耳机序列号查询_BO PLAY推出全新无线蓝牙耳机BEOPLAY E8
  6. 计算某日期开始x天的日期(女票问题100天,521,1000天纪念日是哪一天?)
  7. DeFi借贷协议Euler完成由Paradigm领投的800万美元A轮融资
  8. mysql优化器RBO_RBO基于规则的优化器access paths优先级
  9. 腿难受酸胀刺痛好像有蚂蚁在爬晚上翻来覆去睡不着
  10. 【移动开发者沙龙 北京站】第二期 报名火热来袭