Administrator
发布于 2024-12-08 / 6 阅读
0

Springboot 整合easyexcel 实现excel导入与导出功能

1.Excel 导出

entity:

@Getter
@Setter
@EqualsAndHashCode
public class DemoData {
    @ExcelProperty("字符串标题")
    private String string;
    @ExcelProperty("日期标题")
    private Date date;
    @ExcelProperty("数字标题")
    private Double doubleData;
    /**
     * 忽略这个字段
     */
    @ExcelIgnore
    private String ignore;
}

Controller:

    @ApiOperation("导出")
    @PostMapping("/export")
    @PreAuthorize("@ss.hasPermission('demo:demo:export')")
    public void export(HttpServletResponse response) {

        String fileName = "文件名称" + ".xlsx";
        String encodeName;
        try {
            encodeName = URLEncoder.encode(fileName, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new CustomException("导出失败");
        }
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setHeader("Content-disposition", "attachment;filename=" + encodeName);
        response.setCharacterEncoding("utf-8");
        opsContactsService.export(response);

    }

service:

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void export(HttpServletResponse response) {
        //获取所有通讯录信息
        List<OpsContacts> list = demoMapper.selectList();
        if (ObjectUtils.isEmpty(list)) {
            throw new RuntimeException("list 信息为空");
        }
      
        WriteCellStyle cellStyle = new WriteCellStyle();
        cellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER); // 设置水平居中对齐
        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); // 设置垂直居中对齐

        //头策略使用默认 设置字体大小
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        WriteFont headWriteFont = new WriteFont();
        headWriteFont.setFontHeightInPoints((short) 12);
        headWriteCellStyle.setWriteFont(headWriteFont);
        HorizontalCellStyleStrategy styleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, cellStyle);

        try {
            EasyExcel.write(response.getOutputStream(), OpsContactsVo.class)
                    .registerWriteHandler(styleStrategy)
                    .sheet("sheet名称")
                    .doWrite(list);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

2.Excel 导入

controller:

    @ApiOperation("导入excel")
    @PostMapping("/import")
    @PreAuthorize("@ss.hasPermission('demo:demo:import')")
    public Result<Void> importExcel(MultipartFile file) {
        if (file.getSize() > 30 * 1024 * 1024) {
            return Result.error("文件大小不能超过30M");
        }
        if (!isExcelFile(file)) {
            return Result.error("文件格式错误");
        }
        Service.importExcel(file);
        return Result.ok();
    }

service:

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importExcel(MultipartFile file) {
       
        log.info("=====开始读取数据=====");
        try {
            EasyExcel.read(file.getInputStream(), DemoExportDto.class, new ReadListener<DemoExportDto>() {
                /**
                 * 单次缓存的数据量
                 */
                public static final int BATCH_COUNT = 100;
                /**
                 *临时存储
                 */
                private List<DemoExportDto> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

                @Override
                public void invoke(DemoExportDto data, AnalysisContext context) {
                    cachedDataList.add(data);
                    if (cachedDataList.size() >= BATCH_COUNT) {
                        //单次入库
                        try {
                            saveData();
                        } catch (ParseException e) {
                            throw new RuntimeException(e);
                        }
                        // 存储完成清理 list
                        cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
                    }
                }

                @Override
                public void doAfterAllAnalysed(AnalysisContext context) {
                    try {
                        saveData();
                    } catch (ParseException e) {
                        throw new RuntimeException(e);
                    }
                }

                /**
                 * 加上存储数据库
                 */
                private void saveData() throws ParseException {
                    log.info("{}条数据,开始存储数据库!", cachedDataList.size());
                    List<Demo> demoList = new ArrayList<>();
                    for (DemoExportDto demoData : cachedDataList) {
                        log.info("读取到一条数据{}", JSON.toJSONString(demoData));
                        //数据处理入库
                        Demo demo= toDemo(demoData);

                        demoList.add(demo);
                    }
                    log.info("清理后数据{}", JSON.toJSONString(opsContactsList));
                    demoMapper.batchInsert(demoList);
                }
            }).sheet().doRead();
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        
    }

EasyExcel.read(...):使用 EasyExcel 进行 Excel 文件的读取。file.getInputStream()获取上传的文件流,DemoExportDto.class 表示 Excel 中的每一行数据将会被转换成 DemoExportDto 类型的对象。

new ReadListener<DemoExportDto>():定义了一个读取监听器 ReadListener,用于处理读取到的数据。

BATCH_COUNT:定义了每次批处理的数量为 100。当缓存的 DemoExportDto 数据达到 100 条时,就会触发一次批量插入操作。

  • invoke(DemoExportDto data, AnalysisContext context):每读取一条数据(即一行 Excel 数据),就会调用这个方法。data 是当前读取到的 DemoExportDto 类型的数据,AnalysisContext 是上下文对象。

  • 将读取到的数据添加到 cachedDataList 中。

  • 如果缓存的大小达到了 BATCH_COUNT(100条),就会调用 saveData() 方法进行数据存储。

  • 存储后,重新初始化 cachedDataList,为下一批数据做准备

  • doAfterAllAnalysed:该方法在所有数据都读取完毕后调用。这里仍然会调用 saveData() 方法将剩余的数据存入数据库。

这个方法的主要目的是从上传的 Excel 文件中读取数据,并将其批量插入到数据库中。为了避免内存溢出,使用了 EasyExcelReadListener 来分批读取和处理数据。每读取 100 条数据就会批量存入数据库,直到所有数据都处理完成。