前言
在大型电商系统中,数据导出是一个高频且重要的功能需求。
传统的同步导出方式在面对大数据量时往往会导致请求超时、内存溢出等问题,严重影响用户体验。
苏三商城项目创新性地设计并实现了一套完整的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. 分页大数据处理
[code]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 |