使用EasyExcel实现数据导入功能 监听器配置 直接用!!!

一.介绍

阿里巴巴的EasyExcel是一种Java语言编写的开源库,用于简化Excel文件的导入和导出操作。在Java中解析Excel,比有名的框架有Apache POI和jxl,但是他们都有个严重的问题就是非常耗内存。相比EasyExcel在处理大型Excel文件时,EasyExcel能够有效地管理内存,避免出现内存溢出等问题,而且也比较简单。

 二.需要引入的pom依赖
 
    com.alibaba
    easyexcel
    3.3.2
 
三.导入数据

1.准备ExcelModel实体类对应Excel表格

 使用EasyExcel实现数据导入功能 监听器配置 直接用!!!_第1张图片

@Data
public class ExcelModel {

  @ExcelProperty("ID")
  private Long id;
  @ExcelProperty("姓名")
  private String name;
  @ExcelProperty("性别")
  private String sex;
  @ExcelProperty("年龄")
  private Integer age;

@ExcelProperty()注解里面的值对应Excel表格里面的第一行的内容,循序无所谓

2.准备 文件读取监听器

1.创建一个DataListener监听器类,然后直接implements实现ReadListener接口,接口里面放写好的Excel实体类,只需要重写invoke()方法和doAfterAllAnalysed()方法

invoke()方法的参数是你对应的Excel实体类 (ExcelModel) 和(AnalysisContext context)

咱们直接看代码

@Component
public class DataListener implements ReadListener {
  //日志 
  private static final Logger LOGGER = LoggerFactory.getLogger(DataListener.class);
  //每次最多导入条数
  private static final int BATCH_COUNT = 2000;

  //执行批量添加的service
  @Resource
  private SysUserService sysUserService;

  //数据集合
  List poList = new ArrayList<>();
  //读取失败的Excel文件索引行数集合
  List failedRowIndexList = new ArrayList<>();

  //无参构造方法
  public MailDataListener() {

  }

  //使用这个构造方法,Listener是不被spring所管理的
  //所以我们自己在外面new Listener的时候把service传进来
  public MailDataListener(SysUserService sysUserService) {
    this.sysUserService = sysUserService;
  }

  //这个是按照Excel表格来进行每行读取的 一行一行读取
  @Override
  public void invoke(ExcelModel excelModel, AnalysisContext context) {
    ReadRowHolder readRowHolder = context.readRowHolder();
    //Excel的行索引
    Integer rowIndex = readRowHolder.getRowIndex() + 1;
    try {
      //对应数据库的实体类
      SysUser sysUser = new SysUser();
      //通过get获取Excel中的数据
      //可以在这做一些数据处理,看自己需求
      Long id = excelModel.getId();
      String name = excelModel.getName();
      ....
      sysUser.setId(id);
      sysUser.setName(name);
      ....

      //把实体类存到集合中
      poList.add(sysUser);

      //读取数超过2000进行一次数据写入
      //防止一次读取的数据量过大做的一个限制
      //因为在doAfterAllAnalysed()方法里面执行批量导入,这个方法是在读取完Excel才会执行
      if (poList.size() >= BATCH_COUNT) {
        sysUserService.insertByPoListCheck(poList);
        poList.clear();//清除list中的数据
      }
      LOGGER.info("行索引数: [%s] -> Excel数据: [%s]", rowIndex,
        JsonUtil.toJsonString(excelModel));
    //try catch 用的Exception这样不管什么异常都捕获得到出错的Excel行数
    } catch (Exception e) {
      LOGGER.error("行索引数: [%s] -> 失败的Excel数据: [%s]", rowIndex,
        JsonUtil.toJsonString(excelModel));
      //收集失败的Excel行索引 通过getFailedRows()返回
      failedRowIndexList.add(rowIndex);
    }
  }

  //最后执行,读取完整个Excel执行
  //先打印下日志,然后直接批量导入操作
  @Override
  public void doAfterAllAnalysed(AnalysisContext context) {
    LOGGER.info("所有数据读取完毕!");
    try {
      if (!poList.isEmpty()) {
        sysUserService.insertByPoListCheck(poList);
      }
    } catch (ResDBEffectCheckException e) {
      throw new RuntimeException("Insert User Check Error!");
    }
  }

  //获取读取失败的Excel行索引数集合
  public List getFailedRows() {
    return failedRowIndexList;
  }

}

JsonUtil的方法就是自己封装的ObjectMapper的writeValueAsString方法

public class JsonUtil {

  private static final Logger LOGGER = LoggerFactory.getLogger(JsonUtil.class);

  private static final ObjectMapper objectMapper = new ObjectMapper();

  public static  String toJsonString(T obj) {
    try {
      return objectMapper.writeValueAsString(obj);
    } catch (JsonProcessingException e) {
      LOGGER.error("Failed to convert object to JSON string", e);
      return null;
    }
  }

}

 剩下的就比较简单了

3.service层和mapper层代码

service 对应 controller

public class SendService {

  @Resource
  private SysUserService sysUserService;

  public List batchSending(MultipartFile file) {
      if (file == null) {
        throw new NullInvokeParamRuntimeException();
      }
      try {
        //文件转成流的形式
        InputStream inputStream = file.getInputStream();
        //new一个监听器  把service传进去 
        DataListener dataListener = new DataListener(sysUserService);
        //使用这个的.read方法 参数为 文件 对应excel的实体类 new好的监听器
        EasyExcelFactory.read(inputStream, ExcelModelBo.class, dataListener)
          .sheet(0) //指定读取第一个工作表
          .headRowNumber(1)  //指定标题行在第一行
          .doRead();  //执行实际的读取操作

        //最后返回监听器里写好的获取读取失败行数的方法
        return dataListener.getFailedRows();

      } catch (IOException e) {
        throw new RuntimeException();
      }
    }

}

service 对应mapper

public class SysUserService {

  @Resource
  private SysUserMapper sysUserMapper;

  public int insertByPoList(List poList) {
    return sysUserMapper.insertByPoList(poList);
  }

  public void insertByPoListCheck(List poList) throws ResDBEffectCheckException {
    int i = insertByPoList(poList);
    if (i == 0) {
      throw new ResDBEffectCheckException("Insert Mail DB Effect Check Error! Source [%s]", 
  poList);
    }
  }
}

mapper

  @Insert("""
    
    """)
  int insertByPoList(@Param("list") List list);

4.controller层代码

@Resource
SendService sendService


@PostMapping("/batch")
public ResponseEntity batchSend(@RequestPart("file") MultipartFile file) {
  return new ResponseEntity<>(ResponseCode.OK, sendService.batchSending(file));
} 
  

                                             有用的话大家可以点个赞啊  蟹蟹!!!

你可能感兴趣的:(spring,boot,后端,java)