EasyExcel实现文件导入
导入
准备工作
见:https://www.cnblogs.com/wywblogs/p/16095576.html
异步导入
接口代码
public Map importMemberList(@RequestPart("file") MultipartFile file) {
log4.info("数据导入");
ImportTask importTask = new ImportTask();
importTask.setCreateBy(getCurrentUser.get().getID());
// 读取每一行的监听器
ExcelDataListener<AreaImportDto> excelDataListener = new ExcelDataListener<>();
// excel文件校验
Map<String, Object> check = ExcelUtil.importCheck(file, importTask, excelDataListener, AreaImportDto.class, "导入功能模块名");
// 保存导入记录
importTaskMapper.save(importTask);
// 提交事务,否则下面异步service查询不到保存的importTask
sqlSessionTemplate.flushStatements();
String taskCode = importTask.getCode();
// 如果校验不通过则不进行导入
if (!check.get("code").equals(200)) {
check.put("taskCode",taskCode);
return check;
}
// 进行导入
iAreaService.importMemberList(getCurrentUser.get().getID(), excelDataListener, taskCode);
return new HashMap<String, Object>() {{
put("msg", "数据导入成功!详情请查看导入任务列表");
put("taskCode", taskCode);
put("code", 200);
}};
}
ps:
AreaImportDto:导入的实体类
ImportTask :保存导入任务记录的实体类(包含错误信息)
导入工具类方法
/**
* 校验导入的数据正确性
* @param file 上传的文件
* @param importTask 导入任务记录
* @param excelDataListener 导入监听器
* @param clazz 导入的类对象
* @param importType 导入类型(属于哪个模块的导入)
* @param <T> 导入实体类类型
* @return
*/
public static <T> Map<String, Object> importCheck(MultipartFile file,ImportTask importTask, ExcelDataListener<T> excelDataListener,
Class<T> clazz, String importType) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
Date date = new Date();
importTask.setImportType(importType);
importTask.setCode(sdf.format(date));
importTask.setImportTime(date);
importTask.setFileName(file.getOriginalFilename());
importTask.setCreateAt(date);
importTask.setImportStart(date);
HashMap<String, Object> result = new HashMap<String, Object>() {{
put("code", 200);
}};
try {
if (!checkExcelType(file)) {
importTask.setErrorMessage(importType+"数据导入文件类型错误");
importTask.setStatus(2l);
result.put("code", 401);
result.put("msg", importType+"数据导入文件类型错误");
} else {
// 异步执行上传的file临时文件会被清理掉,在异步service中会获取不到文件
EasyExcel.read(file.getInputStream(),excelDataListener)
.head(clazz)
.sheet()
.doRead();
List<String> errorCol = checkExcelHead(clazz, excelDataListener.getHeadMap());
if (errorCol.size() > 0) {
importTask.setErrorMessage(importType+"数据导入文件列名错误:" + String.join(",",errorCol));
importTask.setStatus(2l);
result.put("code", 401);
result.put("msg", importType+"数据导入文件列名错误");
} else {
// 导入的数据的正确性
List<String> nullFields = excelDataListener.getNullFields();
if (nullFields.size() > 0) {
importTask.setErrorMessage(importType+"数据导入文件必要列为空:"+
String.join(";",nullFields) + ";");
importTask.setStatus(2l);
if (excelDataListener.getDataList().size() == 0) {
result.put("code", 401);
result.put("msg", importType+"数据导入文件必要列为空:"+
String.join(";",nullFields));
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
log4.error(importType+"数据导入文件读取异常"+e.getMessage());
importTask.setErrorMessage(importType+"数据导入文件读取异常"+e.getMessage());
importTask.setStatus(2l);
result.put("code", 401);
result.put("msg", importType+"数据导入文件读取异常"+e.getMessage());
}
return result;
}
/**
* excel文件类型校验
*
* @param file
* @return
*/
public static boolean checkExcelType(MultipartFile file) {
String filename = file.getOriginalFilename();
if (filename == null)
return false;
return filename.endsWith("xlsx") || filename.endsWith("xls");
}
/**
* excel表头校验
* @param clazz 导入实体的类对象
* @param headMap 导入excel的表头
* @return
*/
public static List<String> checkExcelHead(Class<?> clazz,Map<Integer, String> headMap) {
Field[] fields = clazz.getDeclaredFields();
ArrayList<String> errorCol = new ArrayList<>();
// 实体类的head
List<String> entityHead = new ArrayList<>();
for (Field field : fields) {
ExcelProperty annotation = field.getDeclaredAnnotation(ExcelProperty.class);
if (annotation != null) {
List<String> head = Arrays.asList(annotation.value());
entityHead.addAll(head);
}
}
for (Map.Entry<Integer, String> entry : headMap.entrySet()) {
// 解析的表头是否在实体类中
if (!entityHead.contains(entry.getValue()))
errorCol.add(entry.getValue());
}
return errorCol;
}
service开始进行数据导入
/**
* excel数据导入
* @param userId 当前用户id (由于异步方法执行时注入的用户信息service获取不到,因此要在controller中获取后传入)
* @param excelDataListener excel读取监听器
* @param taskCode 导入任务记录的code
*/
@Async
@Transactional(rollbackFor = Exception.class)
public void importMemberList(String userId,ExcelDataListener<AreaImportDto> excelDataListener,String taskCode) {
// 导入任务记录
ImportTask importTask = importTaskMapper.findByCode(taskCode);
log4.info("开始进行数据导入");
// 解析错误的数据
List<Map<String, String>> errorDataList = excelDataListener.getErrorDataList();
if (!CollectionUtils.isEmpty(errorDataList)) {
importTask.setErrorData(errorDataList.toString() + ";");
importTask.setErrorMessage(String.join(";",excelDataListener.getErrorMsg())+ ";");
importTask.setStatus(2l);
} else {
importTask.setStatus(1l);
}
// 解析成功的数据
List<AreaImportDto> dataList = excelDataListener.getDataList();
try {
// 将导入实体类转为数据表对应的实体类
// 调用service方法进行保存(其中出错或者出现异常的数据根据起行索引字段构造错误信息保存在importTask中)
} catch (Exception e) {
String errorMessage = importTask.getErrorMessage();
importTask.setErrorMessage(errorMessage + ";数据导入异常");
importTask.setStatus(2l);
}
importTask.setImportEnd(new Date());
importTask.setDataNum((long)(dataList.size()) + (long)(errorDataList.size()));
// 保存任务记录
importTaskMapper.update(importTask);
log4.info("数据导入完成!");
}
EasyExcel实现文件导入的更多相关文章
- 按照TYPE的文件导入导出功能
/** * 导入文件Action;*/private File excelFile;// 保存原始文件名private String excelFileFileName;// 保存原始文件名priva ...
- 将.dat文件导入数据库
*最近在搞文本分类,就是把一批文章分成[军事].[娱乐].[政治]等等. 但是这个先需要一些样本进行训练,感觉文本分类和"按图索骥"差不多,训练的文章样本就是"图&quo ...
- 怎样将多个CSS文件导入一个CSS文件中
问题: 在HTML中引入css的其中的两个方法: 导入式和链接式的目的都是将一个独立的css文件引入一个文件中,二者的区别不大,事实上,二者最大的区别在于链接式使用html的标记引入外部css文 ...
- 将DBF文件导入Sqlserver数据库
项目中的问题:用户选择N个dbf文件导入sql2005数据库,由于每年dbf表结构都在变化,所以在sql2005中根本就不存在,需要每年根据dbf的结构自动建表.(文章来自http://blog.cs ...
- [转载]将别人的项目或JAVA文件导入到自己的Eclipse中时,常常会出现JAVA文件的中文注释变成乱码的情况,解决办法
eclipse 代码中文注释乱码 求解决 将别人的项目或JAVA文件导入到自己的Eclipse中时,常常会出现JAVA文件的中文注释变成乱码的情况,主要原因就是别人的IDE编码格式和自己的Eclips ...
- unity3d教程游戏包含的一切文件导入资源
http://www.58player.com/blog-2327-954.html 导入资源 将文件增加至工程文件夹的资源 (Assets) 文件夹后,Unity 将自动检测文件.将任何资源 (As ...
- Apache Spark技术实战之4 -- 利用Spark将json文件导入Cassandra
欢迎转载,转载请注明出处. 概要 本文简要介绍如何使用spark-cassandra-connector将json文件导入到cassandra数据库,这是一个使用spark的综合性示例. 前提条件 假 ...
- 【转】SVN的dump文件导入
转载地址:http://erniu.sz.blog.163.com/blog/static/11517292220103282813176/ 把SVN的dump文件导入SVN数据库的方法: 在SVN ...
- python 从文件导入分类
# -*- coding:utf-8 -*- """ 从文件导入分类 根据行首制表符或空格确定层级关系(4个空格等于一个制表符 同一行制表符和空格不能混用 ) 必须是 u ...
随机推荐
- range函数的使用
循环结构终于会出现了 这章讲完差不多读者可以实现大部分程序了 range()函数 用于生成一个整数序列 内置函数:前面不需要加任何前缀,可以直接使用的函数 创建range对象的三种方式 range(s ...
- FileFilter过滤器的原理和使用和FileNameFilter过滤器的使用
FileFilter过滤器的原理和使用 package com.yang.Test.FileStudy; import java.io.File; /** * 在File类中有两个和ListFiles ...
- dockerfile操作
简介 Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明. 上下文路径 如下是一个简单的基于dockerfile创建镜像的命令,我们注意到启动处理镜像名和 ...
- ML.NET相关资源整理
在人工智能领域,无论是机器学习,还是深度学习等,Python编程语言都是绝对的主流,尽管底层都是C++实现的,似乎人工智能和C#/F#编程语言没什么关系.在人工智能的工程实现,通常都是将Pytho ...
- SpringBoot定时任务 - 经典定时任务设计:时间轮(Timing Wheel)案例和原理
Timer和ScheduledExecutorService是JDK内置的定时任务方案,而业内还有一个经典的定时任务的设计叫时间轮(Timing Wheel), Netty内部基于时间轮实现了一个Ha ...
- C 语言 时间函数使用技巧(汇总)
time.h 头文件 是 C 语言中 有关 时间的函数所储存的头文件 #include <time.h> 在介绍时间函数用法之前,我们首先要了解在 time.h 头文件中已经声明了的一个结 ...
- Git 01 介绍
参考源 https://www.bilibili.com/video/BV1FE411P7B3?spm_id_from=333.999.0.0 版本 本文章基于 Git 2.35.1.2 版本控制 版 ...
- 275. H 指数 II--Leetcode_二分
来源:力扣(LeetCode) 链接:https://leetcode.cn/problems/h-index-ii 著作权归领扣网络所有.商业转载请联系官方授权,非商业转载请注明出处. 题目的大意是 ...
- LOJ2312 LUOGU-P3733「HAOI2017」八纵八横 (异或线性基、生成树、线段树分治)
八纵八横 题目描述 Anihc国有n个城市,这n个城市从1~n编号,1号城市为首都.城市间初始时有m条高速公路,每条高速公路都有一个非负整数的经济影响因子,每条高速公路的两端都是城市(可能两端是同一个 ...
- 【java】学习路线13-多态继承
/*多态创建一个父类的对象,用子类去初始化如果要使用子类的方法,则需要把对象强制转换为子类的(xx)xxx*/public class Learn01{ public static void m ...