最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

springboot之excel工具類(lèi)使用及說(shuō)明

 更新時(shí)間:2026年04月07日 09:10:28   作者:enjoy囂士  
本文介紹了一個(gè)批量處理Excel數(shù)據(jù)的小工具,提供導(dǎo)入導(dǎo)出功能,通過(guò)定義數(shù)據(jù)類(lèi)和處理函數(shù)即可實(shí)現(xiàn)數(shù)據(jù)處理,最后進(jìn)行模擬請(qǐng)求和文件數(shù)據(jù)生成,以測(cè)試工具的正確性

背景

后臺(tái)需要批量處理excel數(shù)據(jù),常見(jiàn)的就是導(dǎo)入導(dǎo)出了。故自己寫(xiě)了一個(gè)小工具。

依賴(lài)

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

工具類(lèi)

package org.test.exceldemo.excel;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.CellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.read.listener.PageReadListener;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;

/**
 * Excel 導(dǎo)入導(dǎo)出工具類(lèi)
 * 包含只讀寫(xiě)、只寫(xiě)、流式讀、流式寫(xiě)
 */
public class EasyExcelPipelineUtil {
    /**
     * ??? 同步讀取(小文件用)
     */
    public static <T> List<T> readSync(InputStream inputStream, Class<T> clazz) {
        return EasyExcel.read(inputStream)
                .head(clazz)
                .sheet()
                .doReadSync();
    }

    /**
     * ??? 分頁(yè)讀?。ㄍ扑])
     */
    public static <T> void readByPage(InputStream inputStream,
                                      Class<T> clazz,
                                      Consumer<List<T>> consumer,
                                      int pageSize) {

        EasyExcel.read(inputStream, clazz,
                        new PageReadListener<T>(consumer, pageSize))
                .sheet()
                .doRead();
    }

    /**
     * ??? MultipartFile 分頁(yè)讀取
     */
    public static <T> void readByMultipart(MultipartFile file,
                                           Class<T> clazz,
                                           Consumer<List<T>> consumer,
                                           int pageSize) throws IOException {

        readByPage(file.getInputStream(), clazz, consumer, pageSize);
    }

    /**
     * ??? URL 分頁(yè)讀取
     */
    public static <T> void readByUrl(String url,
                                     Class<T> clazz,
                                     Consumer<List<T>> consumer,
                                     int pageSize) throws Exception {

        try (InputStream in = new URL(url).openStream()) {
            readByPage(in, clazz, consumer, pageSize);
        }
    }

    /**
     * ====================================
     * ????? 直接寫(xiě) Excel(最常用導(dǎo)出)
     * ====================================
     */
    public static <T> void write(String filePath,
                                 Class<T> clazz,
                                 List<T> data, String sheetName) {

        EasyExcel.write(filePath, clazz)
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                .registerWriteHandler(new ExcelCellWriteWidthConfig())
                .sheet(sheetName)
                .doWrite(data);
    }

    /**
     * ? 寫(xiě)到 OutputStream(瀏覽器下載用)
     */
    public static <T> void write(OutputStream outputStream,
                                 Class<T> clazz,
                                 List<T> data, String sheetName) {

        EasyExcel.write(outputStream, clazz)
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                .registerWriteHandler(new ExcelCellWriteWidthConfig())
                .sheet(sheetName)
                .doWrite(data);
    }

    /**
     * ???? 超大數(shù)據(jù)流式寫(xiě)(百萬(wàn)行推薦)
     */
    public static <T> void writeStream(String filePath,
                                       Class<T> clazz,
                                       Consumer<ExcelWriter> writerConsumer) {

        ExcelWriter writer = EasyExcel.write(filePath, clazz)
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                .registerWriteHandler(new ExcelCellWriteWidthConfig())
                .build();

        try {
            writerConsumer.accept(writer);
        } finally {
            writer.finish();
        }
    }
// 調(diào)用樣例
//    EasyExcelUtil.writeStream(
//            "D:/big.xlsx",
//    UserExportVO.class,
//    writer -> {
//
//        for (int i = 0; i < 100; i++) {
//
//            List<UserExportVO> page =
//                    userService.queryPage(i);
//
//            EasyExcelUtil.writeBatchSheet(
//                    writer,
//                    page,
//                    0,
//                    "用戶(hù)表"
//            );
//        }
//    }
//);

    /**
     * ? 分批寫(xiě) sheet
     */
    public static <T> void writeBatchSheet(ExcelWriter writer,
                                           List<T> data,
                                           int sheetNo,
                                           String sheetName) {

        WriteSheet sheet = EasyExcel.writerSheet(sheetNo, sheetName)
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                .registerWriteHandler(new ExcelCellWriteWidthConfig())
                .build();
        writer.write(data, sheet);
    }

    /**
     * ??? 核心流式分頁(yè)處理(真正生產(chǎn)級(jí))
     * ??? 不關(guān)心讀寫(xiě),只需要處理數(shù)據(jù)即可,包含excel文件的讀寫(xiě)
     */
    private static <IN, OUT> void processStream(
            InputStream inputStream,
            OutputStream outputStream,
            Class<IN> inClass,
            Class<OUT> outClass,
            Function<List<IN>, List<OUT>> mapper,
            int pageSize) {

        ExcelWriter writer = EasyExcel.write(outputStream, outClass)
                        .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                        .registerWriteHandler(new ExcelCellWriteWidthConfig())
                        .build();
        WriteSheet sheet = EasyExcel.writerSheet("result").build();

        EasyExcel.read(inputStream, inClass,
                        new PageReadListener<IN>(pageData -> {
                            List<OUT> result = mapper.apply(pageData);
                            writer.write(result, sheet);
                        }, pageSize))
                .sheet()
                .doRead();

        writer.finish();
    }

    /**
     * =========================
     * ? 本地文件路徑
     * =========================
     */
    public static <IN, OUT> void processByFilePath(
            String inputFile,
            String outputFile,
            Class<IN> inClass,
            Class<OUT> outClass,
            Function<List<IN>, List<OUT>> mapper,
            int pageSize) throws Exception {

        try (InputStream in = new FileInputStream(inputFile);
             OutputStream out = new FileOutputStream(outputFile)) {

            processStream(in, out, inClass, outClass, mapper, pageSize);
        }
    }

    /**
     * =========================
     * ? URL 網(wǎng)絡(luò)文件
     * =========================
     */
    public static <IN, OUT> void processByUrl(
            String fileUrl,
            String outputFile,
            Class<IN> inClass,
            Class<OUT> outClass,
            Function<List<IN>, List<OUT>> mapper,
            int pageSize) throws Exception {

        try (InputStream in = new URL(fileUrl).openStream();
             OutputStream out = new FileOutputStream(outputFile)) {

            processStream(in, out, inClass, outClass, mapper, pageSize);
        }
    }

    /**
     * =========================
     * ? MultipartFile(Web上傳)
     * =========================
     */
    public static <IN, OUT> void processByMultipart(
            MultipartFile file,
            String outputFile,
            Class<IN> inClass,
            Class<OUT> outClass,
            Function<List<IN>, List<OUT>> mapper,
            int pageSize) throws Exception {
        try (InputStream in = file.getInputStream();
             OutputStream out = new FileOutputStream(outputFile)) {

            processStream(in, out, inClass, outClass, mapper, pageSize);
        }
    }

    /**
     * =========================
     * ? InputStream 通用入口
     * =========================
     */
    public static <IN, OUT> void processByStream(
            InputStream inputStream,
            OutputStream outputStream,
            Class<IN> inClass,
            Class<OUT> outClass,
            Function<List<IN>, List<OUT>> mapper,
            int pageSize) {

        processStream(inputStream, outputStream, inClass, outClass, mapper, pageSize);
    }

    /**
     * 自動(dòng)計(jì)算列寬
     *
     */
    private static class ExcelCellWriteWidthConfig extends AbstractColumnWidthStyleStrategy {
        private final Map<Integer, Map<Integer, Integer>> CACHE = new HashMap<>();

        @Override
        protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer integer, Boolean isHead) {
            boolean needSetWidth = isHead || !CollectionUtils.isEmpty(cellDataList);
            if (needSetWidth) {
                Map<Integer, Integer> maxColumnWidthMap = CACHE.computeIfAbsent(writeSheetHolder.getSheetNo(), k -> new HashMap<>());

                Integer columnWidth = this.dataLength(cellDataList, cell, isHead);
                // 單元格文本長(zhǎng)度大于60換行
                if (columnWidth >= 0) {
                    if (columnWidth > 60) {
                        columnWidth = 60;
                    }
                    Integer maxColumnWidth = maxColumnWidthMap.get(cell.getColumnIndex());
                    if (maxColumnWidth == null || columnWidth > maxColumnWidth) {
                        maxColumnWidthMap.put(cell.getColumnIndex(), columnWidth);
                        Sheet sheet = writeSheetHolder.getSheet();
                        sheet.setColumnWidth(cell.getColumnIndex(), columnWidth * 2 * 256);
                    }
                }
            }
        }

        /**
         * 計(jì)算長(zhǎng)度
         */
        private Integer dataLength(List<WriteCellData<?>> cellDataList, Cell cell, Boolean isHead) {
            if (isHead) {
                return cell.getStringCellValue().getBytes().length;
            } else {
                CellData<?> cellData = cellDataList.get(0);
                CellDataTypeEnum type = cellData.getType();
                if (type == null) {
                    return -1;
                } else {
                    switch (type) {
                        case STRING:
                            // 換行符(數(shù)據(jù)需要提前解析好)
                            int index = cellData.getStringValue().indexOf("\n");
                            return index != -1 ?
                                    cellData.getStringValue().substring(0, index).getBytes().length + 1 : cellData.getStringValue().getBytes().length + 1;
                        case BOOLEAN:
                            return cellData.getBooleanValue().toString().getBytes().length;
                        case NUMBER:
                            return cellData.getNumberValue().toString().getBytes().length;
                        default:
                            return -1;
                    }
                }
            }
        }
    }
}

舉例

定義exel文件數(shù)據(jù)類(lèi),定義數(shù)據(jù)處理函數(shù)即可。

導(dǎo)入類(lèi)

package org.test.exceldemo.excel;

import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;

/**
 *  導(dǎo)入數(shù)據(jù)類(lèi),對(duì)應(yīng)excel表格字段
 */
@Data
public class UserImportVO {

    @ExcelProperty("User Name")
    private String name;

    @ExcelProperty("User Age")
    private Integer age;
}

導(dǎo)出類(lèi)

package org.test.exceldemo.excel;

import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;

/**
 * 導(dǎo)入結(jié)果類(lèi)
 */
@Data
public class UserImportResultVO {

    @ExcelProperty("User Name")
    private String name;

    @ExcelProperty("User Age")
    private Integer age;

    @ExcelProperty("Import Result")
    private String result;
}

數(shù)據(jù)處理函數(shù)類(lèi)

package org.test.exceldemo.excel;

import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 *  
 */
@Service
public class TestExcelDemoService {
    /**
     * excel數(shù)據(jù)處理類(lèi)
     * @param list excel數(shù)據(jù)
     * @param globalUnique 全局唯一
     * @return 處理結(jié)果
     */
    public List<UserImportResultVO> convertPage(List<UserImportVO> list, Set<String> globalUnique) {

        List<UserImportResultVO> result = new ArrayList<>();

        for (UserImportVO in : list) {
            UserImportResultVO out = new UserImportResultVO();
            BeanUtils.copyProperties(in, out);
            // 判斷數(shù)據(jù)重復(fù)
            if (!globalUnique.add(in.getName())){
                out.setResult("重復(fù)數(shù)據(jù)");
                result.add(out);
                continue;
            }
            // 數(shù)據(jù)處理邏輯

            // 處理結(jié)果
            out.setResult("success");
            result.add(out);
        }
        return result;
    }
}

模擬請(qǐng)求處理類(lèi)

@RestController
@RequestMapping("/")
public class TestExcelController {
    @Resource
    private TestExcelDemoService testExcelDemoService;

    @PostMapping(path = "upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public String uploadFile(@RequestParam("file") MultipartFile file) throws Exception {
        //通過(guò)文件后綴名或文件魔數(shù)進(jìn)行更可靠的校驗(yàn)
        String originalFilename = file.getOriginalFilename();
        // 只處理excel文件
        if (originalFilename != null && !originalFilename.toLowerCase().endsWith(".xlsx")) {
            return "僅支持 EXCEL 文件";
        }

        Set<String> globalUnique = new HashSet<>();
        EasyExcelPipelineUtil.processByMultipart(file,
                "D:/output.xlsx",
                UserImportVO.class,
                UserImportResultVO.class,  list -> testExcelDemoService.convertPage(list, globalUnique), 1000);
        return "上傳成功";
    }
}

測(cè)試數(shù)據(jù)

模擬請(qǐng)求

請(qǐng)求文件數(shù)據(jù)

生成導(dǎo)出結(jié)果文件數(shù)據(jù)

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • java的多線(xiàn)程用法編程總結(jié)

    java的多線(xiàn)程用法編程總結(jié)

    本文主要講了java中多線(xiàn)程的使用方法、線(xiàn)程同步、線(xiàn)程數(shù)據(jù)傳遞、線(xiàn)程狀態(tài)及相應(yīng)的一些線(xiàn)程函數(shù)用法、概述等。
    2016-10-10
  • Java使用dom4j實(shí)現(xiàn)對(duì)xml簡(jiǎn)單的增刪改查操作示例

    Java使用dom4j實(shí)現(xiàn)對(duì)xml簡(jiǎn)單的增刪改查操作示例

    這篇文章主要介紹了Java使用dom4j實(shí)現(xiàn)對(duì)xml簡(jiǎn)單的增刪改查操作,結(jié)合實(shí)例形式詳細(xì)分析了Java使用dom4j實(shí)現(xiàn)對(duì)xml簡(jiǎn)單的增刪改查基本操作技巧與相關(guān)注意事項(xiàng),需要的朋友可以參考下
    2020-05-05
  • java?百度手寫(xiě)文字識(shí)別接口配置代碼

    java?百度手寫(xiě)文字識(shí)別接口配置代碼

    本文通過(guò)實(shí)例代碼給大家介紹了java?百度手寫(xiě)文字識(shí)別接口配置方法,代碼簡(jiǎn)單易懂,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2022-01-01
  • java實(shí)現(xiàn)微信掃碼支付功能

    java實(shí)現(xiàn)微信掃碼支付功能

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)微信掃碼支付功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • mybatis插入數(shù)據(jù)后返回自增主鍵ID的兩種實(shí)現(xiàn)方式

    mybatis插入數(shù)據(jù)后返回自增主鍵ID的兩種實(shí)現(xiàn)方式

    這篇文章主要介紹了mybatis插入數(shù)據(jù)后返回自增主鍵ID的兩種實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • SpringBoot+MyBatis-Plus實(shí)現(xiàn)數(shù)據(jù)庫(kù)讀寫(xiě)分離的代碼示例

    SpringBoot+MyBatis-Plus實(shí)現(xiàn)數(shù)據(jù)庫(kù)讀寫(xiě)分離的代碼示例

    在當(dāng)今互聯(lián)網(wǎng)應(yīng)用中,數(shù)據(jù)庫(kù)讀寫(xiě)分離是提高系統(tǒng)性能和穩(wěn)定性的重要手段之一,通過(guò)將讀操作和寫(xiě)操作分別路由到不同的數(shù)據(jù)庫(kù)節(jié)點(diǎn),可以有效減輕數(shù)據(jù)庫(kù)服務(wù)器的負(fù)擔(dān),本文將介紹如何利用SpringBoot和MyBatis-Plus框架實(shí)現(xiàn)數(shù)據(jù)庫(kù)讀寫(xiě)分離,需要的朋友可以參考下
    2023-11-11
  • MyBatis-Plus之select、delete用法及說(shuō)明

    MyBatis-Plus之select、delete用法及說(shuō)明

    文章主要講解了Mybatis-Plus中的查詢(xún)和刪除操作,查詢(xún)操作包括根據(jù)ID、批量和使用map進(jìn)行條件查詢(xún),以及內(nèi)置分頁(yè)插件的使用,刪除操作則包括物理刪除和邏輯刪除,其中邏輯刪除需要在數(shù)據(jù)庫(kù)和實(shí)體類(lèi)中進(jìn)行相關(guān)配置
    2026-04-04
  • Spring Boot Actuator監(jiān)控端點(diǎn)小結(jié)

    Spring Boot Actuator監(jiān)控端點(diǎn)小結(jié)

    這篇文章主要介紹了Spring Boot Actuator監(jiān)控端點(diǎn)小結(jié),需要的朋友可以參考下
    2017-06-06
  • 關(guān)于Spring注解@Async引發(fā)其他注解失效的解決

    關(guān)于Spring注解@Async引發(fā)其他注解失效的解決

    這篇文章主要介紹了關(guān)于Spring注解@Async引發(fā)其他注解失效的解決,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-03-03
  • += 和 ++ 操作符區(qū)別簡(jiǎn)單介紹

    += 和 ++ 操作符區(qū)別簡(jiǎn)單介紹

    這篇文章主要介紹了+= 和 ++ 操作符區(qū)別簡(jiǎn)單介紹的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2016-09-09

最新評(píng)論

宕昌县| 天祝| 泽库县| 蒙山县| 萨嘎县| 阜阳市| 连城县| 长海县| 南开区| 合江县| 盐城市| 九龙城区| 澄城县| 秦安县| 株洲县| 牙克石市| 个旧市| 丘北县| 常州市| 石渠县| 福州市| 长宁县| 延吉市| 溆浦县| 河东区| 崇义县| 金沙县| 曲阳县| 平和县| 巴南区| 北京市| 连江县| 江油市| 旬邑县| 紫云| 辽宁省| 文山县| 报价| 四平市| 潍坊市| 赣州市|