国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

Spring Boot 3.4 一鍵搞定!接口實現(xiàn)任意表的 Excel 導(dǎo)入導(dǎo)出

開發(fā) 前端
本文展示了一種高效且內(nèi)存友好的 Excel 文件處理方案。無論是單一表格的導(dǎo)入導(dǎo)出,還是動態(tài)適配不同數(shù)據(jù)表的需求,我們都可以通過泛型和反射機制靈活實現(xiàn)。

在 Java Web 開發(fā)中,處理 Excel 文件的導(dǎo)入導(dǎo)出是常見且重要的需求,尤其是在大數(shù)據(jù)量的場景下,如何高效、安全地進行 Excel 文件的讀寫,直接影響到系統(tǒng)的性能與穩(wěn)定性。傳統(tǒng)的工具如 EasyPoi 或 Hutool 提供了強大的功能,但在大規(guī)模數(shù)據(jù)處理時,這些工具常常面臨內(nèi)存溢出(OOM)等性能瓶頸。為了解決這些問題,我們可以轉(zhuǎn)而使用 EasyExcel,它采用了低內(nèi)存消耗的設(shè)計,能夠高效地處理海量數(shù)據(jù)的導(dǎo)入導(dǎo)出。

本文將介紹如何通過結(jié)合 Spring Boot 3.4 與 EasyExcel,實現(xiàn)一鍵搞定任意表的 Excel 導(dǎo)入導(dǎo)出。我們將通過使用 Java 8 的函數(shù)式編程特性、反射機制、以及多線程優(yōu)化技術(shù),進一步提升開發(fā)效率并確保系統(tǒng)的穩(wěn)定性。特別地,在處理大數(shù)據(jù)量時,我們會通過批量存儲和線程池的方式,避免內(nèi)存溢出問題,并進一步優(yōu)化導(dǎo)入導(dǎo)出的性能。

優(yōu)化策略

  1. 使用 Java 8 的函數(shù)式編程簡化數(shù)據(jù)導(dǎo)入
  2. 利用反射實現(xiàn)通用接口導(dǎo)入任意 Excel
  3. 通過線程池優(yōu)化大數(shù)據(jù)量 Excel 導(dǎo)入性能
  4. 通過泛型支持多種數(shù)據(jù)導(dǎo)出格式

Maven 依賴

首先,需要在 pom.xml 文件中添加 EasyExcel 的依賴:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>3.0.5</version>
</dependency>

使用泛型實現(xiàn)對象的單個 Sheet 導(dǎo)入

首先,我們創(chuàng)建一個用于表示導(dǎo)入數(shù)據(jù)的類,假設(shè)是一個學生信息類:

package com.icoderoad.entity;


import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;


@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("stu_info")
@ApiModel("學生信息")
public class StuInfo {


    private static final long serialVersionUID = 1L;


    @ApiModelProperty("姓名")
    @ExcelProperty(value = "姓名", order = 0)
    private String name;


    @ApiModelProperty("年齡")
    @ExcelProperty(value = "年齡", order = 1)
    private Integer age;


    @ApiModelProperty("身高")
    @ExcelProperty(value = "身高", order = 2)
    private Double tall;


    @ApiModelProperty("自我介紹")
    @ExcelProperty(value = "自我介紹", order = 3)
    private String selfIntroduce;


    @ApiModelProperty("性別")
    @ExcelProperty(value = "性別", order = 4)
    private Integer gender;


    @ApiModelProperty("入學時間")
    @ExcelProperty(value = "入學時間", order = 5)
    private String intake;


    @ApiModelProperty("出生日期")
    @ExcelProperty(value = "出生日期", order = 6)
    private String birthday;
}

重寫 ReadListener 接口

為了處理數(shù)據(jù)導(dǎo)入過程中可能出現(xiàn)的內(nèi)存溢出問題,我們重寫 ReadListener 接口,并將數(shù)據(jù)按批次進行存儲:

package com.icoderoad.listener;


import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.read.listener.ReadListener;
import com.icoderoad.exception.BizException;
import lombok.extern.slf4j.Slf4j;


import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;


@Slf4j
public class UploadDataListener<T> implements ReadListener<T> {


    private static final int BATCH_COUNT = 100;
    private List<T> cachedDataList = new ArrayList<>(BATCH_COUNT);
    private Predicate<T> predicate;
    private Consumer<Collection<T>> consumer;


    public UploadDataListener(Predicate<T> predicate, Consumer<Collection<T>> consumer) {
        this.predicate = predicate;
        this.consumer = consumer;
    }


    public UploadDataListener(Consumer<Collection<T>> consumer) {
        this.consumer = consumer;
    }


    @Override
    public void invoke(T data, AnalysisContext context) {
        if (predicate != null && !predicate.test(data)) {
            return;
        }
        cachedDataList.add(data);


        // When the batch size reaches BATCH_COUNT, trigger data storage
        if (cachedDataList.size() >= BATCH_COUNT) {
            try {
                consumer.accept(cachedDataList);
            } catch (Exception e) {
                log.error("Data upload failed! Data={}", cachedDataList);
                throw new BizException("Import failed");
            }
            cachedDataList.clear();
        }
    }


    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        if (!cachedDataList.isEmpty()) {
            try {
                consumer.accept(cachedDataList);
                log.info("All data parsing completed!");
            } catch (Exception e) {
                log.error("Data upload failed! Data={}", cachedDataList);
                if (e instanceof BizException) {
                    throw e;
                }
                throw new BizException("Import failed");
            }
        }
    }
}

Controller 層實現(xiàn)

在 Controller 層,我們使用 EasyExcel.read() 方法讀取上傳的文件,并通過 UploadDataListener 實現(xiàn)數(shù)據(jù)批量存儲:

package com.icoderoad.controller;


import com.alibaba.excel.EasyExcel;
import com.icoderoad.entity.StuInfo;
import com.icoderoad.listener.UploadDataListener;
import com.icoderoad.service.StuInfoService;
import com.icoderoad.util.ValidationUtils;
import com.icoderoad.exception.BizException;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;


import java.io.IOException;


@Slf4j
@RestController
@RequestMapping("/excel")
public class ExcelController {


    @Autowired
    private StuInfoService service;


    @ApiOperation("一鍵導(dǎo)入數(shù)據(jù)到 Excel")
    @PostMapping("/update")
    @ResponseBody
    public R<String> importExcel(MultipartFile file) throws IOException {
        try {
            EasyExcel.read(file.getInputStream(), StuInfo.class, new UploadDataListener<StuInfo>(
                list -> {
                    // 驗證數(shù)據(jù)
                    ValidationUtils.validate(list);
                    // 批量保存數(shù)據(jù)
                    service.saveBatch(list);
                    log.info("Imported {} rows of data from Excel", list.size());
                }
            )).sheet().doRead();
        } catch (IOException e) {
            log.error("Import failed", e);
            throw new BizException("Import failed");
        }
        return R.success("Success");
    }
}

處理任意數(shù)據(jù)表的導(dǎo)入

對于需要導(dǎo)入不同數(shù)據(jù)表的情況,我們可以通過傳遞表編碼以及文件來動態(tài)讀取數(shù)據(jù),并進行適配:

@ApiOperation("通用數(shù)據(jù)表導(dǎo)入")
@PostMapping("/listenMapData")
@ResponseBody
public R<String> listenMapData(@RequestParam("tableCode") String tableCode, MultipartFile file) throws IOException {
    try {
        EasyExcel.read(file.getInputStream(), new NonClazzOrientedListener(
            list -> {
                log.info("Imported {} rows of data", list.size());
            }
        )).sheet().doRead();
    } catch (IOException e) {
        log.error("Import failed", e);
        throw new BizException("Import failed");
    }
    return R.success("Success");
}

重寫 ReadListener 接口處理非類型化數(shù)據(jù)

當我們需要處理不同類型的表時,可以通過 Map 來處理數(shù)據(jù),具體實現(xiàn)如下:

package com.icoderoad.listener;


import com.alibaba.excel.context.AnalysisContext;
import com.icoderoad.exception.BizException;
import lombok.extern.slf4j.Slf4j;


import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Predicate;


@Slf4j
public class NonClazzOrientedListener implements ReadListener<Map<Integer, String>> {


    // 定義批次處理的大小
    private static final int BATCH_COUNT = 100;


    // 用于緩存行數(shù)據(jù)
    private List<List<Object>> rowsList = new ArrayList<>(BATCH_COUNT);


    // 臨時存儲每一行數(shù)據(jù)
    private List<Object> rowList = new ArrayList<>();


    // 條件判斷的 Predicate,決定是否處理當前行
    private Predicate<Map<Integer, String>> predicate;


    // 數(shù)據(jù)處理的消費者
    private Consumer<List> consumer;


    // 構(gòu)造函數(shù),傳入條件判斷和數(shù)據(jù)處理邏輯
    public NonClazzOrientedListener(Predicate<Map<Integer, String>> predicate, Consumer<List> consumer) {
        this.predicate = predicate;
        this.consumer = consumer;
    }


    // 構(gòu)造函數(shù),只傳入數(shù)據(jù)處理邏輯
    public NonClazzOrientedListener(Consumer<List> consumer) {
        this.consumer = consumer;
    }


    @Override
    public void invoke(Map<Integer, String> row, AnalysisContext analysisContext) {
        // 判斷是否符合處理條件,如果有定義 Predicate,進行過濾
        if (predicate != null && !predicate.test(row)) {
            return;
        }


        // 清理 rowList,為下一行做準備
        rowList.clear();


        // 處理每一行的數(shù)據(jù),將行數(shù)據(jù)添加到 rowList
        row.forEach((k, v) -> {
            log.debug("處理數(shù)據(jù)行,鍵:{},值:{}", k, v);  // 中文日志輸出
            rowList.add(v == null ? "" : v);
        });


        // 將處理過的 rowList 添加到 rowsList
        rowsList.add(rowList);


        // 當達到批次大小時,執(zhí)行存儲操作
        if (rowsList.size() >= BATCH_COUNT) {
            processBatch();
        }
    }


    // 批量處理數(shù)據(jù),并清理緩存
    private void processBatch() {
        try {
            log.debug("執(zhí)行存儲邏輯,當前批次包含 {} 行數(shù)據(jù)", rowsList.size());  // 中文日志輸出
            log.info("當前數(shù)據(jù):{}", rowsList);
            consumer.accept(rowsList);
        } catch (Exception e) {
            log.error("數(shù)據(jù)上傳失敗!數(shù)據(jù):{}", rowsList, e);  // 中文日志輸出
            if (e instanceof BizException) {
                throw e;
            }
            throw new BizException("導(dǎo)入失敗");
        } finally {
            // 批次處理后清空緩存
            rowsList.clear();
        }
    }


    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        // 如果還有剩余數(shù)據(jù)沒有處理,執(zhí)行最后一次存儲操作
        if (!rowsList.isEmpty()) {
            processBatch();
        }
        log.debug("所有數(shù)據(jù)處理并上傳完成。");  // 中文日志輸出
    }
}

結(jié)論

通過 EasyExcel 和 Spring Boot 3.4 的完美結(jié)合,本文展示了一種高效且內(nèi)存友好的 Excel 文件處理方案。無論是單一表格的導(dǎo)入導(dǎo)出,還是動態(tài)適配不同數(shù)據(jù)表的需求,我們都可以通過泛型和反射機制靈活實現(xiàn)。同時,利用線程池的方式優(yōu)化大數(shù)據(jù)量處理,顯著提高了性能,避免了內(nèi)存溢出(OOM)問題。通過本文的方法,你可以輕松實現(xiàn)任意表的數(shù)據(jù)導(dǎo)入導(dǎo)出,滿足各種業(yè)務(wù)需求,并為未來的大規(guī)模數(shù)據(jù)處理奠定堅實的基礎(chǔ)。

優(yōu)化后的這兩部分旨在加強對文章主題的深入闡述,同時突出技術(shù)的實際應(yīng)用價值和解決方案的優(yōu)勢,增強文章的專業(yè)性和實踐性。如果你覺得還有其他可以進一步擴展或調(diào)整的地方,隨時告訴我!

責任編輯:武曉燕 來源: 路條編程
相關(guān)推薦

2025-03-26 00:35:00

Javaweb開發(fā)

2025-04-08 01:00:00

Spring開發(fā)系統(tǒng)

2025-10-31 07:42:31

SpringExcel工具

2021-04-23 10:38:52

Spring BootSpringMVC源碼

2025-09-11 08:07:24

2025-03-28 07:56:39

Spring服務(wù)配置

2020-03-31 15:03:56

Spring Boot代碼Java

2025-02-17 00:00:45

接口支付寶沙箱

2025-04-17 04:00:00

2025-09-26 02:00:00

Spring接口開發(fā)

2024-10-17 11:09:46

2025-04-08 08:01:31

2022-06-06 08:42:04

spring-boo開發(fā)接口防盜刷

2025-07-07 07:33:31

2025-04-27 03:00:00

Spring集成測試

2025-03-03 08:00:00

SpringBootEasyExcel數(shù)據(jù)導(dǎo)出

2021-05-14 06:15:48

SpringAware接口

2025-11-04 07:58:20

SpringBoot多語言18n

2022-08-01 07:02:06

SpringEasyExcel場景

2024-08-05 09:51:00

點贊
收藏

51CTO技術(shù)棧公眾號

欧美 国产 精品| 欧美新色视频| 黄色片网站在线观看| 精品成人在线视频| 尤物网在线观看| 欧洲成人免费aa| 欧美理论在线| 男人天堂网站在线| 欧美日韩美女在线| 亚洲黄页在线观看| 亚洲精品永久www嫩草| 亚洲乱码中文字幕| 国产视频一区二| 99电影在线观看| 亚洲国产乱码最新视频| 日本电影久久久| 中文字幕一区二区中文字幕| 香蕉成人伊视频在线观看| av中文在线资源库| 国产成+人+综合+亚洲欧美丁香花| 国产尤物一区二区在线| 在线观看av每日更新免费| 亚洲成在人线在线播放| 国产igao激情在线入口| 丁香婷婷综合激情五月色| 国产高清在线一区| 顶级嫩模精品视频在线看| 视频福利一区| 制服丝袜专区在线| 国产高清在线观看| 日日噜噜噜夜夜爽爽狠狠视频| 日本一区高清在线视频| 高清一区二区三区视频| 欧美亚洲国产视频| 中文字幕在线看视频国产欧美| 在线播放中文字幕一区| 国产一区二区0| 国产一区二区在线网站| 久久国产三级| 色婷婷综合久久| 污污网址在线观看| 国产午夜久久久久| 欧美极品欧美精品欧美图片| 国产一区二区精品久| 亚洲精品国产精品乱码不99按摩| 欧美图片激情小说| 视频国产一区| 国产亚洲美女精品久久久| 中国字幕a在线看韩国电影| 国产精品久线在线观看| 神马一区二区影院| 先锋影音久久| 欧美精品一区二区三区国产精品| 美女av免费在线观看| 最新国产一区| 女女同性女同一区二区三区91| 国产毛片久久久| 91在线视频九色| 琪琪一区二区三区| 久在线观看视频| 国产精品色一区二区三区| 女人被爽到呻吟gif动态图下载| 欧美激情一区不卡| 都市激情一区| 久久婷婷国产麻豆91天堂| 精品国产123区| 国产成人精品免费视频| 国产亚洲亚洲国产一二区| 国产精品一国产精品最新章节| 国产精品国产三级国产aⅴ原创| 国产精品xx| 亚洲精品欧洲精品| 久久夜色精品国产噜噜av| 欧美成人午夜激情| 电影亚洲精品噜噜在线观看| 国产一区二区三区视频免费| 国产真实生活伦对白| 中文精品久久| 中文在线不卡视频| 大胆人体一区| 91精品中文字幕一区二区三区| 久久天天狠狠| 中文字幕精品影院| 亚洲国产日韩精品在线| 国产精品日本一区二区不卡视频 | 一级视频在线免费观看| 国产欧美日本在线| 亚洲一区二区视频| 日韩极品一区| 在线激情免费视频| 日韩三级视频在线看| 高清av在线| 亚洲成人综合网站| 成黄免费在线| 亚洲欧美日韩不卡一区二区三区| 欧美日韩在线播放三区| 国产精品一区二区不卡| 欧美三级理论片| 91丨九色丨蝌蚪丨老版| 午夜影院在线观看视频| 亚洲国产精品久久不卡毛片| 触手亚洲一区二区三区| 精品国产依人香蕉在线精品| 蜜乳av综合| 欧美中文字幕在线| 亚洲一区二区视频在线| 美女精品网站| 99精品国产一区二区三区2021 | 久久99精品久久久久婷婷| 国产精品欧美风情| 国产一区二区三区四区三区四| 久久精品人成| 欧美亚洲综合一区| 亚洲三级精品| 好吊色这里只有精品| 亚洲欧美日韩国产成人| 亚洲精品ww久久久久久p站| 久久一区二区三区电影| 亚洲三级欧美| 亚洲色图图片网| 免费在线观看亚洲视频| 毛片av在线播放| 国产成人亚洲综合91精品| 国产福利一区在线| 一色桃子在线| 亚洲精品短视频| 久久爱另类一区二区小说| 99热免费在线观看| 91精品国产91久久久久久一区二区| 久久福利在线| 性欧美精品一区二区三区在线播放 | 亚洲人成在线观| 日韩精品一区二区久久| 五月婷婷六月合| 日本特级黄色大片| 欧美精品123| 国产99视频在线观看| 在线不卡a资源高清| 久久精品国内一区二区三区| 日本动漫同人动漫在线观看| 国产在线精品一区二区中文| 亚洲欧美国产精品专区久久| 麻豆精品久久精品色综合| 日韩最新在线| av在线播放av| 国产精品一区二区三区不卡 | 黄页网站大全在线免费观看| 国产精品久久久av| 欧美日韩精品二区| 性xx色xx综合久久久xx| 免费高清在线| 一级特黄录像免费播放全99| 91香蕉嫩草影院入口| 亚洲香蕉伊综合在人在线视看| 亚洲国产激情av| 亚洲精品国产偷自在线观看| 综合久久2019| 成人免费看黄网址| 国产精品高潮粉嫩av| 精品电影在线观看| 精品一区二区三区在线视频| 欧美18免费视频| 在线天堂av| 18禁网站免费无遮挡无码中文| 成人动漫在线视频| 91精品婷婷国产综合久久 | 日本成人网址| 日韩肉感妇bbwbbwbbw| 国产精品免费一区二区三区在线观看| 最近2019好看的中文字幕免费| 国产精品不卡一区| 蜜臀va亚洲va欧美va天堂 | 成人综合av| 亚洲一区二区精品在线观看| 国产免费成人av| 日韩精品在线免费观看| 精品视频在线免费| 亚洲美女偷拍久久| 激情久久五月天| 免费欧美一区| 极品美女一区| 国产成人黄色网址| 中文字幕免费在线不卡| 快播日韩欧美| 国产精品10p综合二区| 国产精品中文字幕在线| 91麻豆精品国产91久久久更新时间| 91在线高清观看| 99热这里只有精品8| 欧美午夜精品一区二区三区电影| 亚洲欧洲国产精品一区| 在线免费看黄色| 不卡的av中文字幕| www国产无套内射com| 六月婷婷在线视频| 亚洲精品乱码久久久久久蜜桃91| 日韩免费三级| 丁香婷婷久久久综合精品国产 | 国产精品99免视看9| 日韩中文字幕网站|