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
publicclass 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切面編程:實現橫切關注點的分離
- 反射機制:動態獲取注解信息和方法參數
- 任務持久化:將任務信息保存到數據庫,確??煽啃?/span>
3. 定時任務調度機制
@Component
publicclass 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
publicclass 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);
}
}
}處理流程:
- 狀態管理:完整的任務狀態流轉(等待→執行中→成功/失?。?/span>
- 異常處理:完善的異常捕獲和失敗重試機制
- 動態調用:通過反射動態獲取Service實例
- 通知機制:任務完成后自動發送通知
5. 消息通知機制
@RocketMQMessageListener(
topic = "${mall.mgt.excelExportTopic:EXCEL_EXPORT_TOPIC}",
consumerGroup = "${mall.mgt.excelExportGroup:EXCEL_EXPORT_GROUP}"
)
@Component
publicclass 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 <= sheetCount; sheetIndex++) {
List<K> dataEntities = getBaseMapper().searchByCondition(conditionEntity);
// 寫入數據到Sheet
WriteSheet writeSheet = EasyExcel.writerSheet("Sheet" + sheetIndex)
.head(Class.forName(clazzName)).build();
excelWriter.write(dataEntities, writeSheet);
conditionEntity.setPageNo(conditionEntity.getPageNo() + 1);
}
excelWriter.finish();
return uploadToOSS(file);
}處理策略:
- 內存優化:分頁查詢避免大量數據加載到內存
- 流式處理:使用EasyExcel的流式API
- 多Sheet支持:大數據自動分割到多個Sheet
- 進度可控:分頁處理便于監控和中斷
技術優勢
1. 用戶體驗優勢
- 即時響應:用戶請求后立即返回,無需等待
- 實時通知:通過WebSocket實時推送導出結果
- 進度可見:用戶可以實時查看導出進度
- 錯誤友好:導出失敗時提供詳細的錯誤信息
2. 系統性能優勢
- 高并發:異步處理支持高并發導出請求
- 資源優化:分頁處理避免內存溢出
- 負載均衡:任務隊列支持負載均衡
- 可擴展性:支持水平擴展和垂直擴展
3. 開發維護優勢
- 代碼簡潔:注解驅動,業務代碼簡潔
- 易于擴展:新增業務類型只需添加注解
- 統一管理:所有導出任務統一管理和監控
- 錯誤處理:完善的異常處理和重試機制
4. 運維管理優勢
- 任務監控:完整的任務執行監控
- 狀態管理:清晰的任務狀態流轉
- 日志記錄:詳細的操作日志記錄
- 告警機制:完善的異常告警機制
總結
蘇三商城的Excel異步導出機制是一個設計精良、功能完善的企業級解決方案。
它通過以下技術手段實現了高效、穩定、可擴展的異步導出功能:
核心技術棧
- 注解驅動:
@ExcelExport注解實現聲明式編程 - AOP切面:
CommonTaskAspect實現橫切關注點分離 - 策略模式:
AsyncTaskStrategyContextFactory實現任務策略管理 - 定時調度:Quartz實現任務定時調度
- 消息隊列:RocketMQ實現異步通知
- 實時通信:WebSocket實現實時推送
- 文件存儲:OSS實現文件云端存儲
設計亮點
- 異步解耦:通過任務隊列實現請求與處理的解耦
- 狀態管理:完整的任務狀態流轉和持久化
- 錯誤處理:完善的異常處理和重試機制
- 性能優化:分頁處理、流式寫入、內存優化
- 擴展性強:支持業務類型、導出格式、通知方式的擴展
業務價值
- 提升用戶體驗:異步處理避免長時間等待
- 提高系統性能:支持大數據量導出和高并發請求
- 降低開發成本:注解驅動減少重復代碼
- 便于運維管理:統一的任務管理和監控
這套異步導出機制不僅解決了傳統同步導出的技術難題,還提供了良好的擴展性和維護性,是蘇三商城項目的技術亮點之一,值得在其他項目中推廣和應用。
責任編輯:武曉燕
來源:
蘇三說技術





























