EasyExcel实现导入+各种数据校验功能
作者:扬落 发布时间:2022-05-12 13:05:26
标签:EasyExcel,导入,数据校验
实现的功能
1.导入非xls和xlsx格式的文件
2.导入空数据的excel文件
3.数据缺失
4.导入的excel文件中有重复的数据
5.导入的excel文件数据错误
6.导入的模板不是正确模板
前置条件: 1)传的参数是 MultipartFile file
2)编写一个接收excel文件的实体类,保证@ExcelProperty(“表头1”)中的属性和excel导入的一致
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class ConfigVO {
@ExcelProperty("表头1")
private String head1;
@ExcelProperty("表头2")
private String head2;
}
3)在Impl中使用EasyExcel读数据,就会执行 *
EasyExcel.read(multipartFile.getInputStream(), ConfigVO.class, new ConfigListener(this)).sheet().doRead();
4)自定义 *
@Slf4j
public class ConfigListener extends AnalysisEventListener<ConfigVO> {
private static int count = 0;
List<ConfigVO> list = new ArrayList<>();
// 此map用来存储模板错误的提示,由于我的全局异常捕获没有处理在 * 内抛出的异常信息,
//所以就将数据挪到service层处理抛异常
Map<String, String> errMap = new HashMap<>();
@Autowired
private IConfigService configcService;
public ConfigListener(ConfigService configService) {
this.configService = configService;
}
@Override
public void invoke(ConfigVO configVO, AnalysisContext analysisContext) {
count++;
list.add(configVO);
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
log.info("成功读取" + count + "条数据");
//保存读取到的数据到serviceImpl处理
configService.saveConfig(list, errMap);
}
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
// 验证表头
String head1 = "表头1";
String head2 = "表头2";
if (headMap.size() <= 0) {
errMap.put("msg", "导入的模板不符合,请检查后重新导入!");
}
//value值才是表头信息
if (!headMap.containsValue(head1) || !headMap.containsValue(head2)) {
errMap.put("msg", "导入的模板不符合,请检查后重新导入!");
}
}
}
5)serviceImpl层处理单个数据校验+存储
public void saveConfig(List<ConfigVO> list, Map<String, String> errMap) {
//批量存储数据的list
List<ConfigVO> customerlist = new ArrayList<>();
//提示错误的list
List<Integer> errList = new ArrayList<>();
//用来去重的map
Map<String, Integer> map = new HashMap<>();
//遍历list进行校验
for (int i = 0; i < list.size(); i++) {
//原因是因为我想获取出错的当前行,但是excel表格是从1开始,一条数据就是2
Integer count = 2;
count = count + i;
ConfigVO configVO = list.get(i);
//判有无空数据
if (!ObjectUtils.isEmpty(configVO.getHead1()) && !ObjectUtils.isEmpty(configVO.getHead2())) {
//判类型是否错误
if (("1").equals(configVO.getHead1()) || ("2").equals(configVO.getHead1())) {
String customerName = configVO.getHead2();
//去前后空格
customerName = StrUtil.trim(customerName);
//校验单个数据是否超出字数限制
if (customerName.length() > 255) {
errList.add(count);
}
//map去重的key
String mapStr = configVO.getHead2() + ":" + configVO.getHead1();
//去除excel中重复数据
if (map.containsKey(mapStr)) {
//如果已经有了,那说明有重复数据,更新行数为最新的
map.put(mapStr, count);
//放到错误提示的list,遍历展示错误
errList.add(map.get(mapStr));
} else {
//没有重复也放到map中便于去重
map.put(mapStr, count);
//放到需要存储的list
customerlist.add(configVO);
}
} else {
errList.add(count);
}
} else {
errList.add(count);
}
}
//判断是否是错误模板
if (!errMap.isEmpty()) {
throw new CommonException(errMap.get("msg"));
}
//是否有导入错误的数据
if (!errList.isEmpty()) {
StringBuilder str = new StringBuilder();
str.append("第");
for (Integer err : errList) {
str.append("" + err + "行,");
}
str.append("导入失败,请确认信息是否有误或数据是否有重复");
throw new CommonException(str.toString());
} else {
//需要存到数据库的数据
//查数据库查是否已经存在
//存在就跳过,不存在就添加到list
}
//新增数据到数据库
}
}
}
1.导入非xls和xlsx格式的文件
//获取文件名+后缀
String filename = file.getOriginalFilename();
if (filename != null) {
//获取其后缀
String extension = filename.substring(filename.lastIndexOf(".") + 1);
if (!(extension.equals("xls") || extension.equals("xlsx"))) {
//此处为自定义异常捕获,可使用其他方式
throw new CommonException("文件格式有误,请检查上传文件格式!!");
}
}
2.导入空数据的excel文件
//校验导入的是空模板
try {
InputStream inputStream = file.getInputStream();
ExcelReader reader = ExcelUtil.getReader(inputStream, 0);
int rowCount = reader.getRowCount();
if (rowCount <= 1) {
throw new CommonException("导入的为空模板,请检查后重新导入!!");
}
}catch (IOException e) {
log.error("文件获取失败:{}", e);
throw new CommonException(e.getMessage());
}
3.导入的模板不是正确模板
判断导入的excel是否是提供的表
使用EasyExcel实现
1)首先要自定义 * ,继承AnalysisEventListener<转换excel的对象>
2)实现他的三个方法
invoke 逐行解析excel,每一行都会执行
doAfterAllAnalysed 解析完全部的excel,会调用该方法
invokeHeadMap 验证表头的方法
3)在invokeHeadMap方法中编写
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
// 验证表头
String head1 = "表头1";
String head2 = "表头2";
if (headMap.size() <= 0) {
errMap.put("msg", "导入的模板不符合,请检查后重新导入!");
}
//value值才是表头信息
if (!headMap.containsValue(head1) || !headMap.containsValue(head2)) {
errMap.put("msg", "导入的模板不符合,请检查后重新导入!");
}
}
headMap中存放的就是导入的excel全部的表头信息,
只要判断hashMap中是否包含我们的表头就可以校验是否是我们提供的模板
来源:https://blog.csdn.net/qq_43759721/article/details/129295156


猜你喜欢
- Android开发文档上专门有一小节解释这个问题。简单来说,Activity是负责与用户交互的最主要机制,任何“设置”(Configurat
- 简介本文用示例介绍SpringBoot如何向容器注册bean(即:将对象加入容器)。法1:@Component(@Controller/@S
- 本文所要介绍的简易天气App主要用RxAndroid、MVP、Retrofit实现,首先来看看效果:主页内容:右侧栏天气列表:左侧栏城市列表
- 废话不多说了,一切尽在代码中,具体代码如下所示:界面<?xml version="1.0" encoding=&q
- 一、首先看下支付宝上芝麻信用分的效果图:二、思路 1、确定雷达图中心点坐标 &nb
- 本文实例为大家分享了Android登录邮箱自动补全功能的实现方法,供大家参考,具体内容如下效果:实现原理:1、继承重写简单控件AutoCom
- Spring和SpringMVC的容器具有父子关系,Spring容器为父容器,SpringMVC为子容器,子容器可以引用父容器中的Bean,
- 在Android平台上面,应用程序OOM异常永远都是值得关注的问题。通常这一块也是程序这中的重点之一。这下我就如何解决OOM作一点简单的介绍
- 本文实例讲述了C#实现更改MDI窗体背景颜色的方法。分享给大家供大家参考。具体实现方法如下:/// <summary>/// 设
- Android本地存储SharedPreferences详解存储位置SharedPreferences数据保存在: /data /data/
- 本文实例为大家分享了Android系统级悬浮按钮的具体代码,供大家参考,具体内容如下具体的需求1、就是做一个系统级的悬浮按钮,就像iPhon
- synchronized关键字synchronized,我们谓之锁,主要用来给方法、代码块加锁。当某个方法或者代码块使用synchroniz
- 前言在开发中,或多或少会使用唤醒锁(wake lock),有的是为了保持屏幕长亮,有的是为了保持 CPU 运行。唤醒锁的本质,其实是对屏幕状
- 前言C#基于NAudio工具对Wav音频文件进行剪切,将一个音频文件剪切成多个音频文件注:调用方法前需要导入NAudio.dll或者在NuG
- 前言不知道小伙伴们是否注意到,用AS创建一个默认的新项目后,MainActivity已经有了很大的不同,最大的区别就是新增加了两个Fragm
- 先看代码://设置可以同时处于活动状态的线程池的请求数目。 bool pool = ThreadPool.SetMaxThreads(8,
- Java线程池并发执行多个任务Java在语言层面提供了多线程的支持,线程池能够避免频繁的线程创建和销毁的开销,因此很多时候在项目当中我们是使
- 方法1 :利用Struts 2的支持的可配置结果,可以达到过滤器的效果。Action的处理结果配置支持正则表达式。但是如果返回的对象是一个数
- 需要用到的知识:注解、AOP、ExpiringMap(带有有效期的映射)我们可以自定义注解,把注解添加到我们的接口上。定义一个切面,执行方法
- 这篇文章主要介绍了Java import导入及访问控制权限修饰符过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考