当前位置: 首页 > article >正文

使用@FunctionalInterface进行异步导出Excel数据

项目场景:

项目中需要使用Excel导出大量数据,首先要进行大量的查询,但是由于数据量太大,导出的时候会让前端在pending,所以需要使用异步的方式先让前端返回。


解决方案:

使用@FunctionalInterface方式来进行异步导出。

首先,我们来确定函数式接口在哪里

@FunctionalInterface
public interface ExportDataQueryInterface {

    List<?> queryExportData();

}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SheetInfoBean2 {

    /**
     * sheet页名称
     */
    private String sheetName;

    /**
     * sheet标题bean
     */
    private Class<?> headClass;

    /**
     * sheet页数据
     */
    private ExportDataQueryInterface dataList;
}

如代码所示,函数式接口隐藏在SheetInfoBean中,我们在通过异步方法调用Bean时,函数式接口的作用就是执行耗时较长的查询。也就是说,把不同的查询方法作为参数包裹进异步方法中。从而达到查询,导出异步的结果。

这里则是实际执行导出的方法

@Override
    public void exportToExcelFileAsync(Map<String,Object> context, TaskModule exportType,List<SheetInfoBean2> sheetInfoBeans) {
        String fileName = exportType.getDescription()+"-"+new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())+".xlsx";

        TaskDto taskDto = new TaskDto();
        taskDto.setFileName(fileName);
        taskDto.setType(TaskTypeEnum.EXPORT);
        taskDto.setTaskState(TaskStateEnum.EXECUTE);
        taskDto.setTaskModule(exportType);
        Long taskId = taskClient.add(taskDto);
        taskDto.setId(taskId);
        SpringUtils.getBean(ExcelExportService.class).exportToExcelFileAsync(taskDto,context,sheetInfoBeans);
    }

异步执行,lambda在这里开始真正执行。因为这里调用了SheetInfobeans

@Async
    @Override
    public void exportToExcelFileAsync(TaskDto taskDto, Map<String, Object> context, List<SheetInfoBean2> sheetInfoBeans){
        ThreadContext.set(context);

        String filePath = System.getProperty("java.io.tmpdir")+taskDto.getFileName();
        File file = new File(filePath);
        FileInputStream fileInputStream = null;

        try{
            //创建excel文件
            ExcelWriter excelWriter = EasyExcel.write(filePath).build();

            WriteSheet writeSheet;
            for (SheetInfoBean2 bean : sheetInfoBeans) {
                List<?> list = bean.getDataList().queryExportData();
                // 构建sheet对象
                writeSheet = EasyExcel.writerSheet(bean.getSheetName()).head(bean.getHeadClass()).build();
                // 写出sheet数据
                excelWriter.write(list, writeSheet);
            }


            excelWriter.close();
            fileInputStream = new FileInputStream(filePath);
            //更新状态
            UploadResp upload = fileClient.upload(new MockMultipartFile(file.getName(),file.getName(), ContentType.APPLICATION_OCTET_STREAM.toString(),fileInputStream), null, BizType.EXPORT.getName());
            Long fileId = upload.getFileId();
            taskDto.setFileId(fileId);
            taskDto.setSize(file.length());
            taskDto.setTaskState(TaskStateEnum.FINISHED);
            taskClient.update(taskDto);
        }catch (Exception e){
            log.error(e.getMessage(),e);
        }finally {
            if(file.exists()){
                file.deleteOnExit();
            }
            if(fileInputStream != null){
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    log.error(e.getMessage(),e);
                }
            }
            ThreadContext.clear();
        }
    }

Lambda 表达式的执行:
当 bean.getDataList().queryExportData() 被调用时,才会触发 Supplier<List<?>> 中的 Lambda 表达式执行。也就是说,Lambda 表达式是在这里开始执行的。

使用示例:

excelExportService.exportToExcelFileAsync(
                ThreadContext.get(),
                TaskModule.COUPON_RECORD,
                List.of(new SheetInfoBean2("优惠券记录", CouponRecordExcelDto.class, (() -> {
                    return SpringUtils.getBean(this.getClass()).query(params, pageRequest)
                            .getContent()
                            .stream().map(
                                    genericDto -> {
                                        Map<String, Object> flattenedFields = genericDto.getFlattenedFields();
                                        return BeanUtil.copyProperties(flattenedFields, CouponRecord.class);
                                    }).collect(Collectors.toList());
                }))));
    }


http://www.kler.cn/a/470726.html

相关文章:

  • 简单的jmeter数据请求学习
  • 【C++面向对象——类的多态性与虚函数】编写教学游戏:认识动物(头歌实践教学平台习题)【合集】
  • STM32 I2C通信外设
  • asp.net core 属性路由和约定路由
  • 网络层协议之IP数据包层分片随笔
  • C++进阶——用Hash封装unordered_map和unordered_set
  • Docker如何把openjdk:8镜像打到本地镜像中,避免每次构建项目重新拉取openjdk,极度耗时
  • CCF考试知识点
  • 计算机网络学习
  • 【Qt】Qt 存储应用程序数据到.ini文件
  • JSON基础知识:Web开发中的数据交换格式
  • 【NLP自然语言处理】Transformer模型的几大核心优势与应用前景
  • 用 C++ 创建控制台计算器
  • Java Spring Boot监听事件和处理事件
  • 校园约拍微信小程序设计与实现ssm+论文源码调试讲解
  • Kafka 消费者
  • C++二十三种设计模式之桥接模式
  • 一文读懂51单片机的中断系统
  • 【React】如何高效使用条件渲染
  • 使用C++对SQLite3数据库进行增、删、改、查操作实例
  • 2024 华为开发者大会介绍(附大会PPT下载)
  • PyTorch 自动混合精度AMP Grad Scaler 源码解析:_unscale_grads_ 与 unscale_ 函数
  • 【C++数据结构——树】二叉树的性质(头歌实践教学平台习题)【合集】
  • Excel 技巧02 - 如何批量输入百分号 (★),如何输入百分号并指定小数位数,如何批量删除百分号,如何批量删除小数最后的0?
  • iOS - Tagged Pointer
  • 使用vue项目中,使用webpack模板和直接用vue.config来配置相关插件 区别是什么,具体有哪些提现呢