• 监听器(用MyBatis的IService接口做了封装)
package io.github.talelin.latticy.listener;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.IService;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.Map;

@Slf4j
public class ExcelReaderListener<T> extends AnalysisEventListener<T> {

    /**
     * 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收
     */
    private static final int BATCH_COUNT = 100;
    /**
     * 缓存的数据
     */
    private List<T> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
    /**
     * 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
     */
    private IService<T> service;

    /**
     * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
     *
     * @param service
     */
    public ExcelReaderListener(IService<T> service) {
        this.service = service;
    }

    /**
     * 这个每一条数据解析都会来调用
     *
     * @param data    one row value. Is is same as {@link AnalysisContext#readRowHolder()}
     * @param context
     */
    @Override
    public void invoke(T data, AnalysisContext context) {
        log.info("解析到一条数据:{}", JSON.toJSONString(data));
        cachedDataList.add(data);
        // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM

        if (cachedDataList.size() >= BATCH_COUNT) {
            saveData();
            // 存储完成清理 list
            //注意ListUtils.newArrayListWithExpectedSize是在EasyExcel3.1.1版本之后才有的
            cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
        }
    }
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        log.info("表头数据 excelHead= {}", headMap);
    }
    /**
     * 所有数据解析完成了 都会来调用
     *
     * @param context
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 这里也要保存数据,确保最后遗留的数据也存储到数据库
        saveData();
        log.info("所有数据解析完成!");
    }

    /**
     * 加上存储数据库
     */
    private void saveData() {
        log.info("{}条数据,开始存储数据库!", cachedDataList.size());
        service.saveBatch(cachedDataList);
        log.info("存储数据库成功!");
    }
}
  • 控制层代码
@PostMapping("/import")
public AjaxResult importExcel(MultipartFile file) throws IOException {
    AjaxResult ajaxResult = new AjaxResult();
    try {
        //file.getInputStream()是获取导入的文件数据
        //SStbkSmbsnFncDtlI01ADO.class是对应的实体类
        //YwtzTyrzmxCwbListener是对应的监听器,这里是自定义对导入的数据做判断限制
        //sStbkSmbsnFncDtlI01AService是对应的Service类
        //.sheet()第一个参数是Excel哪个中sheet,第二个参数是sheet名称
        //.headRowNumber()是表头行数
        //.doRead()开始读取
        EasyExcel.read(file.getInputStream(), SStbkSmbsnFncDtlI01ADO.class, new YwtzTyrzmxCwbListener(sStbkSmbsnFncDtlI01AService)).sheet(1, "02表内容").headRowNumber(3).doRead();
        return ajaxResult.success("success");
    } catch (ExcelAnalysisException e) {
        e.printStackTrace();
        return ajaxResult.fail("500", e.getMessage());
    }
}
  • 实体类
package io.github.talelin.latticy.model;

import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.io.Serializable;
import java.math.BigDecimal;

/**
 * B_H01_同业融资信息_财务部_补录
 *
 * @author generator@TaleLin
 * @since 2022-09-05
 */
@Data
public class SStbkSmbsnFncInfH01ADO implements Serializable {

    /**
     * 客户号
     */
    //强制读取第一个 
    //这里不建议 index 和 name 同时用,要么一个对象只用index,要么一个对象只用name去匹配
    //用名字去匹配,这里需要注意,如果名字重复,会导致只有一个字段读取到数据
    @ExcelProperty(index = 0)
    private String cstNo;

    /**
     * 业务编码
     */
    @ExcelProperty(index = 1)
    private String bsnEcd;

    /**
     * 业务种类
     */
    @ExcelProperty(index = 2)
    private String bsnCtlg;

    /**
     * 起始日期
     */
    @ExcelProperty(index = 3)
    private String begDt;

    /**
     * 到期日
     */
    @ExcelProperty(index = 4)
    private String exdy;

    /**
     * 实际终止日期
     */
    @ExcelProperty(index = 5)
    private String actTmdt;

    /**
     * 期限
     */
    @ExcelProperty(index = 6)
    private String ddln;

    /**
     * 利率类型
     */
    @ExcelProperty(index = 7)
    private String intrtTp;

    /**
     * 实际利率
     */
    @ExcelProperty(index = 8)
    private BigDecimal actIntrt;

    /**
     * 借贷定价基准类型
     */
    @ExcelProperty(index = 9)
    private String dbtcrPrcgBssTp;

    /**
     * 基准利率
     */
    @ExcelProperty(index = 10)
    private BigDecimal bssIntrt;

    /**
     * 计息方式
     */
    @ExcelProperty(index = 11)
    private String intarMod;

    /**
     * 利率浮动频率
     */
    @ExcelProperty(index = 12)
    private String intrtFltFrq;

    /**
     * 余额
     */
    @ExcelProperty(index = 13)
    private BigDecimal bal;

    /**
     * 内部机构号
     */
    @ExcelProperty(index = 14)
    private String inrInsno;

    /**
     * 币种
     */
    @ExcelProperty(index = 15)
    private String ccy;

    /**
     * 数据来源
     */
    @ExcelIgnore
    private String dtsrc;

    /**
     * 业务日期
     */
    //忽略这个字段
    @ExcelIgnore
    private String parDate;

    /**
     * 源系统代码
     */
    @ExcelIgnore
    private String srcSysCd;

    /**
     * 加载时间戳
     */
    @ExcelIgnore
    private String loadTime;

    /**
     * 金融机构代码
     */
    @ExcelProperty(index = 16)
    private String fncLcnsNo;

    /**
     * 交易对手代码
     */
    @ExcelProperty(index = 17)
    private String txnOpntCd;

    /**
     * 交易对手证件类别
     */
    @ExcelProperty(index = 18)
    private String txnOpntCrdtCgy;

    /**
     * 资产负债类型
     */
    @ExcelProperty(index = 19)
    private String alTp;

    /**
     * 余额折人民币
     */
    @ExcelProperty(index = 20)
    private BigDecimal balFoldCny;

    /**
     * 存款协议代码
     */
    @ExcelProperty(index = 21)
    private String depAgrmCd;

    /**
     * 缴存准备金方式
     */
    @ExcelProperty(index = 22)
    private String depRsrvfndMtd;

    /**
     * 合同编码
     */
    @ExcelProperty(index = 23)
    private String ctrEcd;
}