基于easyexcel实现Excel表格导入

前瞻
项目中需要使用Excel表格来导入数据,基于easyexcel实现Excel表格进行数据导入

问题
由于导入表格的种类较多,使用的依赖过于频繁,使用该方法时,如果使用pio的依赖来实现下载excle表格时,会出现冲突的现象,原因是由于依赖冲突导致,所以在使用该方法之前,如果使用pio方法进行下载表格时,可能会发生异常

建议
在使用该方法进行导入时,可使用之前的一篇文档,基于easyexcel实现的Excel表格下载
链接:https://blog.csdn.net/ldy15729357137/article/details/139521745

下面进入正题,Excel导入

Maven依赖

<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.2.1</version>
        </dependency>
        
         <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.9</version>
        </dependency>

实现类
由于导入的Excel表格中,表头信息和校验信息不相同,无法实现统一的方法,只能实现定制化的功能,针对功能进行实现,但基本的外壳是相同的,只不过业务逻辑有所不同

实体类
创建实体类,用于接收表格的信息
其中@ExcelProperty注解中的内容即为插入表格中表头的名称,要于实体类中的一一对应

package com.ponshine.applets.excle.entity;

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

/**
 * @author LiDongYang
 * @description:
 * @date 2024/6/11 13:02
 */
@Data
public class ImportBachDto {

    @ExcelProperty("编码")
    private String id;

    @ExcelProperty("名称")
    private String name;

    @ExcelProperty("类型")
    private String type;


}

表格内容处理类
继承AnalysisEventListener类,实现对应的方法,执行顺序如下
1、invokeHeadMap: 读取第一行数据,表头信息,校验表头信息是否符合要求
2、invoke: 循环执行,一次读取一条数据进行校验
3、doAfterAllAnalysed: 当表格中所有的数据执行完之后,执行该方法,一般情况是时将数据进行插入
4、onException: 数据抛异常时的处理类

package com.ponshine.applets.excle.listener;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.metadata.CellExtra;
import com.google.gson.Gson;
import com.ponshine.applets.excle.entity.ImportBachDto;
import lombok.extern.slf4j.Slf4j;
import java.util.*;

/**
 * @author Li DongYang
 * @description:
 * @date: 2023/4/13 15:25
 */
@Slf4j
public class DeviceImportListener extends AnalysisEventListener<ImportBachDto> {

    /**
     * Excle表头信息,这里做校验使用
     */
    private static String[] COLUMN = new String[]{"编码","名称","类型"};

    public DeviceImportListener() {
    }


    /**
     * 所有数据解析完成了 都会来调用
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 这里也要保存数据,确保最后遗留的数据也存储到数据库
        log.info("所有数据解析完成!");

    }


    /**
     * 读取时,每条数据都会从这里解析
     */
    @Override
    public void invoke(ImportBachDto data, AnalysisContext context) {

    }


    /**
     * 读取表头数据
     */
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        Gson gson = new Gson();
        log.info("解析到一条头数据:{}", gson.toJson(headMap));
        if (headMap.size() == COLUMN.length) {
            for (int i = 0; i < headMap.size(); i++) {
                if (!COLUMN[i].equals(headMap.get(i))) {
                    System.out.println("文件头部错误");
                    break;
                }
            }
        } else {
            System.out.println("文件头部错误");
        }
    }

    /**
     * 读取额外信息
     *
     * @param extra
     * @param context
     */
    @Override
    public void extra(CellExtra extra, AnalysisContext context) {
        Gson gson = new Gson();
        log.info("读取到了一条额外信息:{}", gson.toJson(extra));
        switch (extra.getType()) {
            case COMMENT:
                log.info("额外信息是批注,在rowIndex:{},columnIndex;{},内容是:{}", extra.getRowIndex(), extra.getColumnIndex(),
                        extra.getText());
                break;
            case HYPERLINK:
                if ("Sheet1!A1".equals(extra.getText())) {
                    log.info("额外信息是超链接,在rowIndex:{},columnIndex;{},内容是:{}", extra.getRowIndex(),
                            extra.getColumnIndex(), extra.getText());
                } else if ("Sheet2!A1".equals(extra.getText())) {
                    log.info(
                            "额外信息是超链接,而且覆盖了一个区间,在firstRowIndex:{},firstColumnIndex;{},lastRowIndex:{},lastColumnIndex:{},"
                                    + "内容是:{}",
                            extra.getFirstRowIndex(), extra.getFirstColumnIndex(), extra.getLastRowIndex(),
                            extra.getLastColumnIndex(), extra.getText());
                } else {
                    log.info("Unknown hyperlink!");
                }
                break;
            case MERGE:
                log.info(
                        "额外信息是超链接,而且覆盖了一个区间,在firstRowIndex:{},firstColumnIndex;{},lastRowIndex:{},lastColumnIndex:{}",
                        extra.getFirstRowIndex(), extra.getFirstColumnIndex(), extra.getLastRowIndex(),
                        extra.getLastColumnIndex());
                break;
            default:
        }
    }

    /**
     * 用日期去接字符串 肯定报错,此时需要用到异常处理
     * 在转换异常获取其他异常下会调用本接口。
     * 抛出异常则停止读取。如果这里不抛出异常则 继续读取下一行。
     */
    @Override
    public void onException(Exception exception, AnalysisContext context) {
        log.error("解析失败,但是继续解析下一行:{}", exception.getMessage());
        // 如果是某一个单元格的转换异常 能获取到具体行号
        // 如果要获取头的信息 配合invokeHeadMap使用
        if (exception instanceof ExcelDataConvertException) {
            ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException) exception;
            log.error("第{}行,第{}列解析异常", excelDataConvertException.getRowIndex(),
                    excelDataConvertException.getColumnIndex());
        }
    }
}

业务层调用
上面的工具类时对数据进行处理,下面的是如何调用

public String importBach(MultipartFile file) {
        StringBuilder result = new StringBuilder();
        try {
            String name = file.getOriginalFilename();
            //校验文件大小
            if (file.getSize() > 10485760) {
                System.out.println("上传文件过大,请上传10M以内的文件!");
            }
            if (StringUtils.isEmpty(name) || (!name.endsWith(".xlsx") && !name.endsWith(".xls"))) {
                System.out.println("文件格式错误!");
            }
            //测站信息导入,先获取原测站基本信息
            //获取字典配置信息(区域、流域、测站类型)
            ImportListener siteImportListener = new ImportListener();
            ExcelReaderBuilder read = EasyExcelFactory.read(file.getInputStream(), ImportBachDto.class, siteImportListener);
            read.sheet().doRead();
            Integer successCount = siteImportListener.getSuccessCount();
            Integer errorCount = siteImportListener.getErrorCount();
            Integer totalCount = successCount + errorCount;
            result.append("批量导入结束,此次导入总量为 ").append(totalCount).append("条")
                    .append(", 其中成功 ").append(successCount).append("条, ").append("失败 ").append(errorCount).append("条");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("批量导入异常");
        }
        return result.toString();
    }

到此到此的功能就结束了,针对不同的需求,可对代码进行优化调整

  • 10
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值