easyexcel文件上传

easyexcel文件上传

前言:功能开发中,难免碰到数据上传下载功能,excel上传常见用于报表上传,绩效上传,考勤上传...

使用步骤:

1,编写业务层:

1,添加easyexcel依赖

c 复制代码
 			<dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>easyexcel</artifactId>
                <version>3.2.0</version>
            </dependency>

2,导入模板excel下载

通常有个模版下载功能,在模板里面添加表头,以及数据格式...

3,在导入Excel模版中添加导入数据

4,导入
controller

c 复制代码
	@PostMapping("/importxxxRoster")
    @ApiOperation("导入xxx信息")
    public void importxxxRoster(MultipartFile file, HttpServletResponse response) {
        dutyRosterService.importDutyRoster(file, response);
    }

service

c 复制代码
 /**
     * 导入xxx信息
     *
     * @param file
     *            文件
     * @param response
     *            响应
     */
    void importxxxRoster(MultipartFile file, HttpServletResponse response);

serviceImpl

c 复制代码
 @Override
    public void importxxxRoster(MultipartFile file, HttpServletResponse response) {
        try {
            InputStream is = file.getInputStream();
            // 监听器不能放在容器里面,要通过构造器的方式,放入监听器使用
            xxxxRosterDataListener listener = new xxxxRosterDataListener(this.baseMapper);
            // xxxRosterData 接收导入Excel 实体类
            EasyExcel.read(is, xxxRosterData.class, listener).doReadAll();
            // 获取错误信息集合
            List<xxxRosterErrorData> errorDataList = listener.getErrorDataList();
            if (!CollectionUtils.isEmpty(errorDataList)) {
                response.setContentType("application/vnd.ms-excel");
                response.setCharacterEncoding("utf-8");
                String fileName = URLEncoder.encode("xxx导入错误详情", "UTF-8");
                response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
                // 导出错误Excel数据
                EasyExcel.write(response.getOutputStream(), xxxRosterErrorData.class).sheet("错误详情").doWrite(errorDataList);
            }
        } catch (IOException e) {
            log.error("导入xxexcel异常:{}", e);
            // 编写异常信息
        }
    }

接收导入Excel 数据实体
xxxRosterData

c 复制代码
package com.xx.xx.xx.entity.excel;

import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;

/**
 * @author psd xxx导入excel 接收数据实体
 *
 */
@Data
public class xxxRosterData {

    /**
     * 值班时间str
     */
    @ExcelProperty(value = "日期",order = 0)
    private String dutyTimeStr;

    /**
     * 人员名称
     */
    @ExcelProperty(value = "人员名称",order = 1)
    private String person;

}

2,编写监听器

c 复制代码
package com.xxx.xx.xx.listener;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.xx.xx.common.result.ResultCodeEnum;
import com.xx.xx.common.utils.DateUtils;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author psd 创建xx信息导入监听器
 */
@Data
public class xxxRosterDataListener extends AnalysisEventListener<xxxRosterData> {

    XXXRosterMapper xxxRosterMapper;

    /**
     * 记录批量导入数据
     */
    private List<xxxRosterEntity> batchInsertDutyList = new ArrayList<>();

    /**
     * 记录需要更新的数据
     */
    private List<xxxRosterEntity> batchUpdateDutyList = new ArrayList<>();

    /**
     * 记录错误的数据
     */
    private List<xxxRosterErrorData> errorDataList = new ArrayList<>();

    /**
     * 记录没有问题的数据集合
     */
    private List<xxxxRosterEntity> normalData = new ArrayList<>();


	// 创建构造器 引入用到的service mapper...
    public xxRosterDataListener(xxxRosterMapper dutyRosterMapper) {
        this.xxRosterMapper = xxxRosterMapper;
    }

    /**
     * 每一条数据都会解析
     * 
     * @param data
     *            每行数据
     * @param analysisContext
     */
    @Override
    public void invoke(xxxRosterData data, AnalysisContext analysisContext) {
        // 1、添加常见的行数校验
        
        // 2、参数校验
        if (validateData(data)) {
            // 说明没有问题
           // 3、编写要导入的数据对象信息放入
           normalData.add(xxx);
        }
    }

    /**
     * 常见的数据校验
     * 
     * @param data
     *            每一行的数据集
     * @return 是否异常 true 数据基本判断没有问题,false 说明有异常
     */
    private boolean validateData(xxxxRosterData data) {
        StringBuffer errorMsg = new StringBuffer();
        // 清空字符串
        errorMsg.setLength(ConstantUtils.ZERO);
        // 添加数据校验
        if (StringUtils.isBlank(errorMsg)) {
        	// 说明没有问题	
            return true;
        } else {
            // 记录错误信息 
            errorDataList.add();
            return false;
        }
    }

    /**
     * 所有数据执行完才会调用
     * 
     * @param analysisContext
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
       	// 1、获取没有问题的数据
       	// 2、判断哪些是新增的 哪些是需要修改的
       	// 3、批量入库
       	。。。
    }
}

常见遇到的问题:

问题一:

下载模板导入Excel时候明明写了数据,但是错误数据还是为空的问题,或者导入不成功?

原因是:

1,Excel的表头字段名字要和接收的数据Vo对象里面的字段名称一致

比如:

Excel模板中的表头为:

数据接收对象的字段名称为

导致接收不到

2,有可能是排序的问题,比如上图日期在第一位,但是数据xxxData实体类接收对象

order = 不是0,也会导致没有接收到数据

问题二:

在监听器添加注解比如@Component ... 或者其他注解,使用@Autowired 、或者@Resources注解引入xxxService 、xxxMapper ,引入的service和mapper无法使用

这个是因为监听器不支持这种引入,可以通过构造器方式将数据传递过去,监听器不是放在spring容器中【这点是自己的理解,可能有误】

问题三:

错误信息如何导出?

我们可以在监听器添加@Data注解通过getxxx()方式获取错误数据,可以做成导出Excel功能。

c 复制代码
@Data
public class xxxRosterDataListener extends AnalysisEventListener<xxxRosterData> {

    /**
     * 记录错误的数据
     */
    private List<xxxRosterErrorData> errorDataList = new ArrayList<>();
    ......
}
c 复制代码
 @Override
    public void importxxxRoster(MultipartFile file, HttpServletResponse response) {
        try {
  			.....
            // 获取错误信息集合
            List<DutyRosterErrorData> errorDataList = listener.getErrorDataList();
            if (!CollectionUtils.isEmpty(errorDataList)) {
				// 导出Excel
            }
        } catch (IOException e) {
			// 抛异常 ...
        }
    }

喜欢我的文章的话,点个阅读或者点个点赞,是我编写博客的动力,持续更新中 ing...

相关推荐
xlsw_3 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
神仙别闹4 小时前
基于java的改良版超级玛丽小游戏
java
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭4 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
暮湫4 小时前
泛型(2)
java
超爱吃士力架4 小时前
邀请逻辑
java·linux·后端
南宫生4 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
转码的小石5 小时前
12/21java基础
java
李小白665 小时前
Spring MVC(上)
java·spring·mvc
GoodStudyAndDayDayUp5 小时前
IDEA能够从mapper跳转到xml的插件
xml·java·intellij-idea
装不满的克莱因瓶5 小时前
【Redis经典面试题六】Redis的持久化机制是怎样的?
java·数据库·redis·持久化·aof·rdb