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

Java Excel 導入導出通用組件:基於 Apache POI SXSSF 的百萬級數據高效處理

     編輯:Java 相關知識

技術選型:為什麼選 SXSSF?

  • SXSSF (Streaming XSSF):只在內存保留滑動窗口(默認 100 行),其餘刷入臨時文件,支援百萬行導出不 OOM
  • XSSF:全內存,適合 < 5 萬行
  • HSSF:舊 .xls 格式,65535 行限制

ExportExcel 核心類(精簡版)

public class ExportExcel {
    private final SXSSFWorkbook wb;
    private final Sheet sheet;
    private final Map<String, CellStyle> styles = new HashMap<>();
    private int rownum = 0;

    public ExportExcel(String title, List<String> headers) {
        wb = new SXSSFWorkbook(500); // 窗口 500 行
        sheet = wb.createSheet("Data");
        createStyles();
        if (title != null) createTitleRow(title, headers.size());
        createHeaderRow(headers);
    }

    private void createStyles() {
        // 標題樣式:大字體、加粗、居中、合併儲存格
        // 表頭樣式:深灰背景、白字、加粗、邊框
        // 數據樣式:左/中/右對齊、日期格式、數值格式
    }

    public Row addRow() { return sheet.createRow(rownum++); }

    public Cell addCell(Row row, int col, Object val, int align) {
        Cell cell = row.createCell(col);
        CellStyle style = styles.get("data" + (align >= 1 && align <= 3 ? align : ""));
        // 根據類型設置值:String/Integer/Long/Double/Date/Boolean
        cell.setCellStyle(style);
        return cell;
    }

    /** 註解驅動導出:實體類字段標註 @ExcelField */
    public <E> ExportExcel setDataList(List<E> list) {
        for (E e : list) {
            Row row = addRow();
            // 反射獲取字段值,按 @ExcelField.sort() 排序
            // 支援字典轉換、日期格式化、數值精度控制
        }
        return this;
    }

    public void write(HttpServletResponse response, String fileName) throws IOException {
        response.setContentType("application/octet-stream");
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
        wb.write(response.getOutputStream());
        dispose();
    }

    public void dispose() { wb.dispose(); } // 釋放臨時文件
}

ImportExcel 核心類

public class ImportExcel {
    private final Workbook wb;
    private final Sheet sheet;
    private final int headerRow;

    public ImportExcel(InputStream is, String fileName, int headerRow) throws IOException {
        this.headerRow = headerRow;
        wb = fileName.endsWith(".xlsx") ? new XSSFWorkbook(is) : new HSSFWorkbook(is);
        sheet = wb.getSheetAt(0);
    }

    public <E> List<E> getDataList(Class<E> clazz) {
        List<E> list = new ArrayList<>();
        // 解析 @ExcelField 註解構建字段映射
        for (int i = headerRow + 1; i <= sheet.getLastRowNum(); i++) {
            Row row = sheet.getRow(i);
            if (row == null) continue;
            E entity = clazz.getDeclaredConstructor().newInstance();
            // 遍歷字段,根據類型轉換單元格值
            // String/Integer/Long/Double/Date/Boolean + 字典反查
            list.add(entity);
        }
        return list;
    }
}

實體類註解定義

@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelField {
    String title() default "";
    int sort() default 0;
    String dictType() default "";      // 字典類型,導出時自動轉換
    int align() default 0;             // 1左 2中 3右
    Class<?> fieldType() default void.class; // 自定義類型轉換器
}

使用示例

// 導出
@GetMapping("/export")
public void export(HttpServletResponse response) {
    List users = userService.findAll();
    List headers = Arrays.asList("ID", "姓名", "部門", "入職日期");
    new ExportExcel("用戶列表", headers)
        .setDataList(users)
        .write(response, "users_" + System.currentTimeMillis() + ".xlsx");
}

// 導入
@PostMapping("/import")
public Result importExcel(@RequestParam MultipartFile file) {
    List users = new ImportExcel(file.getInputStream(), file.getOriginalFilename(), 0)
        .getDataList(User.class);
    userService.batchInsert(users);
    return Result.success("導入 " + users.size() + " 條");
}

效能優化關鍵點

優化點說明
SXSSF 窗口大小根據行大小調整,建議 100-1000,默認 100
臨時文件目錄-Djava.io.tmpdir=/data/tmp 指定大磁盤分區
避免重複創建 Style預創建樣式 Map 復用,每行不 new CellStyle
流式寫入 Response直接 wb.write(response.getOutputStream()),不落地
導入並發處理大文件分 Sheet 多線程解析,入庫用批量 INSERT
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved