能氐吨 发表于 2025-10-27 18:50:01

Excel高性能异步导出完整方案!

前言

在大型电商系统中,数据导出是一个高频且重要的功能需求。
传统的同步导出方式在面对大数据量时往往会导致请求超时、内存溢出等问题,严重影响用户体验。
苏三商城项目创新性地设计并实现了一套完整的Excel异步导出机制,通过注解驱动、任务队列、定时调度、消息通知等技术手段,完美解决了大数据量导出的技术难题,成为项目的重要技术亮点。
系统架构设计

整体架构图


核心组件说明


[*]注解驱动层:通过@ExcelExport注解实现声明式编程
[*]切面处理层:CommonTaskAspect负责拦截和任务创建
[*]任务管理层:ExcelExportTask执行具体的导出逻辑
[*]调度引擎层:基于Quartz的定时任务调度
[*]消息通知层:RocketMQ + WebSocket实现异步通知
[*]存储层:MySQL存储任务状态,OSS存储导出文件
异步导出流程详解

完整流程图


关键步骤分析

1. 注解驱动任务创建

@ExcelExport(ExcelBizTypeEnum.USER)
@ApiOperation(notes = "导出用户数据", value = "导出用户数据")
@PostMapping("/export")
public void export(HttpServletResponse response, UserConditionEntity userConditionEntity) {
    // 方法体可以为空,切面会自动处理
}设计亮点:

[*]声明式编程:通过注解实现功能声明,代码简洁
[*]零侵入性:业务方法无需修改,切面自动处理
[*]类型安全:通过枚举确保业务类型的正确性
2. 切面拦截与任务创建

@Aspect
@Component
public class CommonTaskAspect {
   
    @Before("@annotation(cn.net.susan.annotation.ExcelExport)")
    public void before(JoinPoint joinPoint) throws Throwable {
      // 获取注解信息
      ExcelBizTypeEnum excelBizTypeEnum = method.getAnnotation(ExcelExport.class).value();
      
      // 创建任务实体
      CommonTaskEntity commonTaskEntity = createCommonTaskEntity(excelBizTypeEnum);
      
      // 保存任务到数据库
      commonTaskMapper.insert(commonTaskEntity);
    }
}技术特色:

[*]AOP切面编程:实现横切关注点的分离
[*]反射机制:动态获取注解信息和方法参数
[*]任务持久化:将任务信息保存到数据库,确保可靠性
3. 定时任务调度机制

@Component
public class CommonTaskJob extends BaseJob {
   
    @Override
    public JobResult doRun(String params) {
      // 查询待执行任务
      CommonTaskConditionEntity condition = new CommonTaskConditionEntity();
      condition.setStatusList(Arrays.asList(
            TaskStatusEnum.WAITING.getValue(),
            TaskStatusEnum.RUNNING.getValue()
      ));
      
      List<CommonTaskEntity> tasks = commonTaskMapper.searchByCondition(condition);
      
      // 执行任务
      for (CommonTaskEntity task : tasks) {
            AsyncTaskStrategyContextFactory.getInstance()
                .getStrategy(task.getType())
                .doTask(task);
      }
      
      return JobResult.SUCCESS;
    }
}核心机制:

[*]定时扫描:通过Quartz定时扫描任务队列
[*]策略模式:根据任务类型选择对应的处理器
[*]并发处理:支持多个任务并发执行
4. 异步任务处理器

@AsyncTask(TaskTypeEnum.EXPORT_EXCEL)
@Service
public class ExcelExportTask implements IAsyncTask {
   
    @Override
    public void doTask(CommonTaskEntity commonTaskEntity) {
      try {
            // 1. 更新任务状态为执行中
            commonTaskEntity.setStatus(TaskStatusEnum.RUNNING.getValue());
            commonTaskMapper.update(commonTaskEntity);
            
            // 2. 获取业务类型和请求参数
            ExcelBizTypeEnum excelBizTypeEnum = getExcelBizTypeEnum(commonTaskEntity.getBizType());
            String requestParam = commonTaskEntity.getRequestParam();
            Object toBean = JSONUtil.toBean(requestParam, aClass);
            
            // 3. 获取对应的Service并执行导出
            String serviceName = this.getServiceName(requestEntity);
            BaseService baseService = (BaseService) SpringBeanUtil.getBean(serviceName);
            String fileName = getFileName(excelBizTypeEnum.getDesc());
            String fileUrl = baseService.export(toBean, fileName, this.getEntityName(requestEntity));
            
            // 4. 更新任务状态为成功
            commonTaskEntity.setFileUrl(fileUrl);
            commonTaskEntity.setStatus(TaskStatusEnum.SUCCESS.getValue());
            
      } catch (Exception e) {
            // 5. 处理失败情况
            handleTaskFailure(commonTaskEntity, e);
      } finally {
            // 6. 更新任务记录并发送通知
            commonTaskMapper.update(commonTaskEntity);
            sendNotifyMessage(commonTaskEntity);
      }
    }
}处理流程:

[*]状态管理:完整的任务状态流转(等待→执行中→成功/失败)
[*]异常处理:完善的异常捕获和失败重试机制
[*]动态调用:通过反射动态获取Service实例
[*]通知机制:任务完成后自动发送通知
5. 消息通知机制

@RocketMQMessageListener(
    topic = "${mall.mgt.excelExportTopic:EXCEL_EXPORT_TOPIC}",
    consumerGroup = "${mall.mgt.excelExportGroup:EXCEL_EXPORT_GROUP}"
)
@Component
public class ExcelExportConsumer implements RocketMQListener<MessageExt> {
   
    @Override
    public void onMessage(MessageExt message) {
      String content = new String(message.getBody());
      CommonNotifyEntity commonNotifyEntity = JSONUtil.toBean(content, CommonNotifyEntity.class);
      pushNotify(commonNotifyEntity);
    }
   
    private void pushNotify(CommonNotifyEntity commonNotifyEntity) {
      // 通过WebSocket推送通知
      WebSocketServer.sendMessage(commonNotifyEntity);
      
      // 更新通知状态
      commonNotifyEntity.setIsPush(1);
      commonNotifyMapper.update(commonNotifyEntity);
    }
}通知特色:

[*]异步解耦:通过消息队列实现系统解耦
[*]实时推送:WebSocket确保用户及时收到通知
[*]可靠性保证:消息队列确保通知的可靠传递
技术架构亮点

1. 策略模式 + 工厂模式

public class AsyncTaskStrategyContextFactory {
    private static Map<Integer, IAsyncTask> asyncTaskMap;
   
    public IAsyncTask getStrategy(Integer taskType) {
      return asyncTaskMap.get(taskType);
    }
}设计优势:

[*]扩展性强:新增任务类型只需实现IAsyncTask接口
[*]维护性好:每种任务类型独立实现,互不影响
[*]配置灵活:通过工厂模式统一管理任务策略
2. 注解驱动编程

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelExport {
    ExcelBizTypeEnum value();
}编程范式:

[*]声明式编程:通过注解声明功能,而非命令式实现
[*]元数据驱动:注解携带的元数据驱动系统行为
[*]代码简洁:业务代码保持简洁,关注点分离
3. 异步任务状态机


状态管理:

[*]状态流转:清晰的状态转换逻辑
[*]重试机制:失败任务自动重试,提高成功率
[*]状态持久化:任务状态持久化到数据库
4. 分页大数据处理

private String doExport(V v, String fileName, String clazzName) {    RequestConditionEntity conditionEntity = (RequestConditionEntity) v;      // 计算分页参数    int totalCount = getBaseMapper().searchCount(conditionEntity);    int sheetCount = totalCount % sheetDataSize == 0 ?         totalCount / sheetDataSize : totalCount / sheetDataSize + 1;      // 创建ExcelWriter    ExcelWriter excelWriter = EasyExcel.write(file).build();      // 分页处理数据    for (int sheetIndex = 1; sheetIndex

季卓然 发表于 2025-10-29 11:19:15

新版吗?好像是停更了吧。

兑谓 发表于 2025-10-31 17:56:18

喜欢鼓捣这些软件,现在用得少,谢谢分享!

蟠鲤 发表于 2025-11-30 21:24:19

喜欢鼓捣这些软件,现在用得少,谢谢分享!

疝镜泛 发表于 前天 16:52

这个好,看起来很实用
页: [1]
查看完整版本: Excel高性能异步导出完整方案!