首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 導出多個 Excel 並打包 ZIP 下載:AEAI DP 平台實戰案例

     編輯:Java 相關知識

前言

Web 系統常見需求:使用者需一次導出多份 Excel 報表。若逐一下載體驗極差,最佳解法是伺服器端生成多個 Excel、打包成 ZIP、單一請求下載。本文基於 AEAI DP 低代碼平台實戰案例,完整記錄從模板設計、資料拼裝、Excel 導出、ZIP 壓縮、瀏覽器下載、暫存檔清理的全流程實作。

系統架構與技術棧

  • 平台:AEAI DP (AgileAI Development Platform)
  • 模板引擎:FreeMarker (.ftl)
  • Excel 導出:FileExportHelper (內建 IO 流處理)
  • 壓縮工具:ZipHelper (doZip / downZip / deleteZip)
  • 資料庫:MySQL (員工資料表 employee)

實作步驟詳解

1. 基礎建置:建立專案與單表模型

  • 建立專案 export_demo,初始化資料庫
  • 建立業務表 employee,對應實體類
  • 使用 DP 預置功能快速生成單表操作模型(列表、新增、修改、刪除)

2. 前端擴展:新增「導出 Excel」按鈕

在 EmployeeManageList.jsp 列表頁加入按鈕並綁定 JS 事件:


<input type="button" value="導出 Excel" onclick="exportExcel()" />

<script>
function exportExcel() {
    // 呼叫後端 Handler 導出方法
    window.location.href = "${ctx}/employee/exportExcel";
}
</script>

導出按鈕

3. 模板設計:FreeMarker Excel 模板

建立 EmployeeInfos.ftl,定義 Excel 結構與資料綁定:


<#-- EmployeeInfos.ftl -->
<table>
  <tr><th>員工編號</th><th>姓名</th><th>部門</th><th>職位</th><th>薪資</th></tr>
  <#list employees as emp>
  <tr>
    <td>${emp.id}</td>
    <td>${emp.name}</td>
    <td>${emp.deptName}</td>
    <td>${emp.position}</td>
    <td>${emp.salary}</td>
  </tr>
  </#list>
</table>

FTL 模板

4. 後端 Handler:資料拼裝與導出協調


public class EmployeeManageListHandler extends BaseHandler {
    // 導出 Excel 主入口
    public void exportExcelFile() {
        // 1. 查詢導出資料(可加條件篩選)
        List employees = employeeService.queryAll();

        // 2. 準備模板資料模型
        Map model = new HashMap<>();
        model.put("employees", employees);
        model.put("exportTime", new SimpleDateFormat("yyyy-MM-dd HH:mm").format(new Date()));

        // 3. 呼叫平台工具導出 Excel 到暫存目錄
        String tempDir = FileExportHelper.exportFile(
            "EmployeeInfos.ftl",  // 模板路徑
            model,                // 資料模型
            "員工資料_" + System.currentTimeMillis() + ".xls", // 檔名
            getRequest(), getResponse()
        );

        // 4. 壓縮為 ZIP(此處示範單檔,多檔案傳 List)
        List filePaths = Arrays.asList(tempDir);
        String zipPath = ZipHelper.doZip(filePaths, "員工資料導出_" + System.currentTimeMillis() + ".zip");

        // 5. 下載 ZIP 到瀏覽器
        ZipHelper.downZip(zipPath, getResponse());

        // 6. 清理暫存檔(非同步或排程清理更佳)
        ZipHelper.deleteZip(zipPath);
        // 同步刪除 Excel 暫存檔...
    }
}

Handler 程式碼

5. ZipHelper 核心方法實作


public class ZipHelper {
    // 壓縮多個檔案為 ZIP
    public static String doZip(List srcFiles, String zipName) {
        String zipPath = TEMP_DIR + zipName;
        try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipPath))) {
            for (String filePath : srcFiles) {
                File file = new File(filePath);
                try (FileInputStream fis = new FileInputStream(file)) {
                    ZipEntry entry = new ZipEntry(file.getName());
                    zos.putNextEntry(entry);
                    byte[] buffer = new byte[1024];
                    int len;
                    while ((len = fis.read(buffer)) > 0) {
                        zos.write(buffer, 0, len);
                    }
                    zos.closeEntry();
                }
            }
        } catch (IOException e) {
            throw new RuntimeException("壓縮失敗", e);
        }
        return zipPath;
    }

    // 輸出 ZIP 到瀏覽器
    public static void downZip(String zipPath, HttpServletResponse response) {
        File file = new File(zipPath);
        response.setContentType("application/zip");
        response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
        response.setContentLengthLong(file.length());
        try (FileInputStream fis = new FileInputStream(file);
             ServletOutputStream sos = response.getOutputStream()) {
            byte[] buffer = new byte[4096];
            int len;
            while ((len = fis.read(buffer)) > 0) {
                sos.write(buffer, 0, len);
            }
            sos.flush();
        } catch (IOException e) {
            throw new RuntimeException("下載失敗", e);
        }
    }

    // 刪除暫存 ZIP
    public static void deleteZip(String zipPath) {
        new File(zipPath).delete();
    }
}

doZip

downZip

deleteZip

執行效果展示

  1. 登入系統:https://localhost:6060/export_demo/index?Homepage (admin/admin)
  2. 進入員工管理列表
  3. 點擊「導出 Excel」按鈕
  4. 瀏覽器自動下載 員工資料導出_123456789.zip
  5. 解壓縮獲得 員工資料_123456789.xls,用 Excel 開啟資料完整

登入頁

員工列表

下載 ZIP

解壓縮檔案

Excel 內容

環境部署說明

  1. 下載 AEAI DP 開發平台與 HotServer:官網資源分享
  2. 建立 MySQL 資料庫 export,執行 export_mysql.sql
  3. 啟動 HotServer,導入專案部署
  4. 瀏覽器訪問驗證

下載介質

部署專案

通用化改良建議(脫離平台通用做法)


// Spring Boot 通用版本
@RestController
@RequestMapping("/export")
public class ExportController {
    @Autowired EmployeeService employeeService;
    @Autowired ExcelExportService excelExportService; // 封裝 POI/EasyExcel
    @Autowired ZipService zipService;

    @GetMapping("/employees")
    public void exportEmployees(HttpServletResponse response) throws IOException {
        List data = employeeService.findAll();
        
        // 1. 生成多個 Excel (ByteArrayOutputStream)
        Map excelMap = new LinkedHashMap<>();
        excelMap.put("員工基本資料.xlsx", excelExportService.export(data, "basic"));
        excelMap.put("員工薪資明細.xlsx", excelExportService.export(data, "salary"));
        
        // 2. 記憶體中壓縮 ZIP
        ByteArrayOutputStream zipBaos = zipService.zip(excelMap);
        
        // 3. 直接輸出
        response.setContentType("application/zip");
        response.setHeader("Content-Disposition", "attachment; filename=employee_export.zip");
        response.setContentLengthLong(zipBaos.size());
        response.getOutputStream().write(zipBaos.toByteArray());
    }
}

關鍵優化點

  • 記憶體 vs 暫存檔:小檔案用 ByteArrayOutputStream 純記憶體操作;大檔案需分塊寫入暫存檔避免 OOM
  • 非同步導出:大量資料採用異步任務 + 輪詢/WebSocket 通知下載
  • 暫存清理策略:定時任務掃描清理超過 1 小時的暫存檔
  • 檔名編碼:URLEncoder.encode(fileName, "UTF-8") 解決中文檔名亂碼

總結

「多 Excel 打包 ZIP 下載」是提升使用者體驗的經典模式。核心流程為:資料查詢 → 模板渲染生成 Excel → 記憶體/磁碟壓縮 ZIP → HTTP 響應輸出 → 暫存清理。掌握此模式並根據資料量選擇記憶體或磁碟策略,即可優雅解決批量導出需求。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved