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 ... 
随机推荐
- k8s配置集ConfigMap详解
			ConfigMap介绍 ConfigMap和Secret是Kubernetes系统上两种特殊类型的存储卷,ConfigMap对象用于为容器中的应用提供配置文件等信息.但是比较敏感的数据,例如密钥.证书 ... 
- 用VS Code搞Qt6:编译源代码与基本配置
			先说明一下,本水文老周仅讨论新版的 Qt 6,旧版的 Qt 不讨论. 尽管 Qt 有自己的开发环境,但老周必须说句不装逼的话:真的不好用.说起写代码,当然了,用记事本也能写.但是,有个高逼格的工具,写 ... 
- springmvc源码笔记-HandlerMapping注入
			在springmvc中,如何根据url找到controller以及对应方法,依赖的是HandlerMapping接口的getHandler方法 在spring容器中默认注册的HandlerMappin ... 
- 剑指offer——day-1
			今天开始记录一下剑指offer的题目训练,提升一下自己的编程能力吧 题目一: 用两个栈实现一个队列.队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列 ... 
- 利用Css3样式属性Cursor来更换自定义个性化鼠标指针(光标)
			现而今,我们纵向的回顾整个大前端的历史,不难发现,人们对前端的审美要求越来越高,越来越严苛,与此同时,人们对追求美的体验是也极致的,从理性到感性,从平面到几何,从现实到虚拟,所以从某种角度来说,作为前 ... 
- 技术分享|闪回在MySQL中的实现和改进
			GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. 3306π 福州站,以下内容是由万里数据库,研发工程师唐洁分享的MySQL闪回方案完整PPT. Enjoy GreatSQ ... 
- 万答#15,都有哪些情况可能导致MGR服务无法启动
			欢迎来到 GreatSQL社区分享的MySQL技术文章,如有疑问或想学习的内容,可以在下方评论区留言,看到后会进行解答 本文转载自微信公众号 "老叶茶馆" 欢迎大家关注! 1.都有 ... 
- P1980 计数问题 - 记录
			P1980 计数问题 题目描述 试计算在区间 1 到 n的所有整数中,数字x(0 ≤ x ≤ 9)共出现了多少次?例如,在 1到11中,即在 1,2,3,4,5,6,7,8,9,10,11中,数字1出 ... 
- JAVA语言基础组成(2)
			函数 函数的定义 1.什么是函数? 函数就是定义在类中的具有特定功能的一段独立小程序.函数也称为方法. 2.函数的格式: 修饰符 返回值类型 函数名(参数类型 形式参数1,参数类型 形式参数2,.. ... 
- Java多线程超级详解(只看这篇就够了)
			多线程能够提升程序性能,也属于高薪必能核心技术栈,本篇会全面详解Java多线程.@mikechen 主要包含如下几点: 基本概念 很多人都对其中的一些概念不够明确,如同步.并发等等,让我们先建立一个数 ... 
