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 新版吗?好像是停更了吧。 喜欢鼓捣这些软件,现在用得少,谢谢分享! 喜欢鼓捣这些软件,现在用得少,谢谢分享! 这个好,看起来很实用
页:
[1]