5、基於EasyExcel的導入導出

来源:https://www.cnblogs.com/Iven-L/archive/2022/08/07/16560278.html
-Advertisement-
Play Games

一、Apach POI處理Excel的方式: 傳統Excel操作或者解析都是利用Apach POI進行操作,POI中處理Excel有以下幾種方式: 1、HSSFWorkbook: HSSFWorkbook用來處理.xls尾碼的Excel,即適用於Excel2003以前(包括2003)的版本。因為其最 ...


一、Apach POI處理Excel的方式:

傳統Excel操作或者解析都是利用Apach POI進行操作,POI中處理Excel有以下幾種方式:

1、HSSFWorkbook:

HSSFWorkbook用來處理.xls尾碼的Excel,即適用於Excel2003以前(包括2003)的版本。因為其最大隻能處理65535行的數據,所以現在已經很少使用了

2、XSSFWorkbook:

XSSFWorkbook是現在處理Excel比較常見的方式。其適用於.xlsx尾碼的Excel,即Excel2007後的版本。能夠最多處理104萬行數據。但是其在讀取/處理Excel時會一口氣將Excel內容寫入到記憶體,因此在處理的Excel文件較大時可能打爆記憶體,造成OOM異常(記憶體溢出)

3、SXSSFWorkbook:

SXSSFWorkbook相當於是XSSFWorkbook的改良版本,在初始化SXSSFWorkbook實例時,需要填寫一個緩衝行數參數(預設100行),當讀入到記憶體中的數據超過該數值後,會像隊列一樣將最前面的數據保存到硬碟中,從而避免出現OOM。這麼一看該方式簡直完美啊,不過因為超過緩存行的數據都寫到硬碟中了,所以如果你想要獲取這塊的內容(比如複製這塊內容到另一個Excel中)就會發現取不到了,因為不在記憶體中,所以無法通過SXSSFWorkbook實例獲取該部分內容。

 

二、Apach POI框架的不足:

1、使用步驟繁瑣;

2、動態寫出Excel操作非常麻煩;

3、對於新手來說,很難在短時間內上手;

4、讀寫時需要占用較大的內容,當數據量大時容器發生OOM;

基於上述原因,阿裡開源出一款易上手,且比較節省記憶體的Excel操作框架:EasyExcel

 

三、Apach POI、EasyPoi與EasyExcel的區別:

1、POI 優點在於自由,但是迎來的就是複雜度,和大數據量時候性能的缺點

2、EasyPoi基於POI 的二次封裝,解決了大部分的常用場景,簡化了代碼,但是特別複雜表格處理還是不行,而且性能的話和poi差不多,簡單來說就是簡化了Poi的操作,少些點代碼,總體來說,easypoi和easyexcel都是基於apache poi進行二次開發的。

3、easypoi和easyexcel的不同點在於:

(1)、easypoi 在讀寫數據的時候,優先是先將數據寫入記憶體,優點是讀寫性能非常高,但是當數據量很大的時候,會出現oom,當然它也提供了 sax 模式的讀寫方式,需要調用特定的方法實現。

(2)、easyexcel 基於sax模式進行讀寫數據,不會出現oom情況,程式有過高併發場景的驗證,因此程式運行比較穩定,相對於 easypoi 來說,讀寫性能稍慢!

(3)、easypoi 與 easyexcel 還有一點區別在於,easypoi 對定製化的導出支持非常的豐富,如果當前的項目需求,併發量不大、數據量也不大,但是需要導出 excel 的文件樣式千差萬別,那麼我推薦你用 easypoi;反之,使用 easyexcel !

 

四、EasyExcel的使用:

4.1、操作流程:

建工程——》改POM——》寫YML——》業務類

4.1.1、添加依賴:

        <!-- easyexcel 依賴 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>2.2.7</version>
        </dependency>    

4.1.2、寫YML:

server:
  port: 8081

spring:
  application:
    name: demo    #項目名
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource    #當前數據源操作類型
    driver-class-name: org.gjt.mm.mysql.Driver    #mysql驅動包
    url: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: 123456
    druid:
      test-while-idle: false  #關閉空閑檢測

mybatis:
  mapperLocations: classpath:mapper/*.xml    #resource目錄下建mapper包,存放xml文件

 

4.2、EasyExcel的導出操作(單個與批量導出):

4.2.1、通用導出工具類ExportUtil:

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;

import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.util.List;

@Slf4j
public class ExportUtil {
    /**
     * 導出 Excel
     *
     * @param response  :響應
     * @param data      :導出的list集合
     * @param fileName  :Excel名(最好英文,無需尾碼)
     * @param sheetName :sheet頁名
     * @param clazz     :導出Excel實體類
     * @throws Exception
     */
    public static void writeExcel(HttpServletResponse response, List<? extends Object> data, String fileName, String sheetName, Class clazz) throws Exception {
        //表頭樣式
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        //設置表頭居中對齊
        headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        //內容樣式
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        //設置內容靠左對齊
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);
        HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);

        EasyExcel.write(getOutputStream(fileName, response), clazz)
                .excelType(ExcelTypeEnum.XLSX)//讀取的文件類型
                .sheet(sheetName)//讀取的sheet,可以是行號也可以是sheet名
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())//設置自動適應寬度
                .registerWriteHandler(horizontalCellStyleStrategy)//設置樣式(或:registerWriteHandler(createStyleStrategy))
                .doWrite(data);
    }

    /**
     * 格式處理
     */
    private static OutputStream getOutputStream(String fileName, HttpServletResponse response) throws Exception {
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        response.setCharacterEncoding("utf8");
        response.addHeader("Content-disposition", "attachment;filename=" + fileName + ExcelTypeEnum.XLSX.getValue());
        return response.getOutputStream();
    }

    /**
     * 自定義樣式
     */
    private static HorizontalCellStyleStrategy createStyleStrategy() {
        // 頭的策略
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        // 背景設置為紅色
        headWriteCellStyle.setFillForegroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE.getIndex());
        WriteFont headWriteFont = new WriteFont();
        headWriteFont.setFontHeightInPoints((short) 10);
        headWriteCellStyle.setWriteFont(headWriteFont);
        // 內容的策略
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);  //底邊框
        contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);  //左邊框
        contentWriteCellStyle.setBorderRight(BorderStyle.THIN);  //右邊框
        contentWriteCellStyle.setBorderTop(BorderStyle.THIN);  //頂邊框
        WriteFont contentWriteFont = new WriteFont();
        // 字體大小
        contentWriteFont.setFontHeightInPoints((short) 10);
        contentWriteCellStyle.setWriteFont(contentWriteFont);
        // 執行策略
        HorizontalCellStyleStrategy horizontalCellStyleStrategy =
                new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);

        return horizontalCellStyleStrategy;
    }
}

4.2.2、業務流程:

1、請求體:

import lombok.Data;

import java.util.List;

@Data
public class RequestVO {
    private String id;
    private List<String> ids;
    private Boolean way;
}

2、控制類:

    /**
     * 導出
     * 1、單個導出
     * 2、批量導出
     *
     * http://localhost:8081/v1/export-data
     * {
     *     "id":"xxx",
     *     "ids":["xxx","xxx"],
     *     "way":false
     * }
     * */
    @PostMapping("/export-data")
    public void exportList(
            @RequestBody RequestVO requestVO,
            HttpServletResponse response) {
        //導出方式:單個/批量
        if(true == requestVO.getWay()){
            requestVO.setId(null);
        }
        operateService.exportData(requestVO,response);
    }

3、業務類:

    @Autowired
    private OperateMapper operateMapper;

    /**
     * 導出操作
     */
    @Override
    public void exportData(RequestVO requestVO, HttpServletResponse response) {
        //mysql查詢
        List<BasicDemo> list = operateMapper.selectAllDemo(requestVO);
        //轉換
        List<ExportExcelVO> exportList = new ArrayList<>();
        Optional.ofNullable(list).ifPresent(po -> {
            po.stream().forEach(p -> {
                ExportExcelVO exportExcelVO = ExportExcelVO.builder()
                        .uuid(p.getUuid())
                        .name(p.getName())
                        .status(p.getStatus())
                        .startTime(p.getStartTime())
                        .build();
                exportList.add(exportExcelVO);
            });
        });

        //導出
        try {
            writeExcel(response, exportList, "result", "表名", ExportExcelVO.class);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("錯誤信息Exception:", e);
        }
        log.info("執行完畢,導出成功");
    }

4、導出實體類:

import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import lombok.Builder;
import lombok.Data;

import java.io.Serializable;

@HeadRowHeight(value = 35) // 設置表頭行高
@ContentRowHeight(value = 25) // 設置內容行高
//@ColumnWidth(value = 50) // 設置列寬
@Data
@Builder
public class ExportExcelVO implements Serializable {

    @ExcelProperty(value = {"編號"},order = 1)
    private String uuid;

    @ExcelProperty(value = {"基本信息","詳情","名字"},order = 2)
    private String name;

    @ExcelProperty(value = {"基本信息","詳情","狀態"},order = 3)
    private String status;

    @ExcelProperty(value = {"基本信息","操作時間","時間"},order = 4)
    @DateTimeFormat("yyyy-MM-dd")   //時間格式
    private String startTime;


}

5、SQL語句:

    <select id="selectAllDemo" resultMap="BaseResultMap" parameterType="java.lang.String">
        select
        <include refid="Base_Column_List"/>
        from page_demo
        where 1=1
        <if test="id neq null and id != ''">
            AND uuid = #{id}
        </if>
        <if test="ids != null and ids.size()!=0">
            AND uuid in
            <foreach collection="ids" item="item" index="index" open="(" separator=","
                     close=")">
                #{item}
            </foreach>
        </if>
    </select>

6、導出樣本:

 

4.3、EasyExcel的導入操作(模板下載與數據導入):

4.3.1、通用導入工具類ImportUtil:

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;


@Slf4j
public class ImportUtil {
    /**
     * 導入 Excel
     *
     * @param multipartFile excel文件
     * @param clazz         數據類型的class對象
     * @param <T>
     * @return
     */
    public static <T> List<T> importExcel(MultipartFile multipartFile, Class<T> clazz) throws Exception {
        List<T> list = new ArrayList<>();
        InputStream inputStream = multipartFile.getInputStream();

        EasyExcel.read(inputStream, clazz, new AnalysisEventListener<T>() {
            //每解析一行就會調用一次,data數據表示解析出來一行的數據
            @Override
            public void invoke(T data, AnalysisContext context) {
                list.add(data);
            }

            //當全部數據讀取完成後調用該方法
            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {
                log.info("解析完成");
            }
        }).sheet().doRead();
        return list;
    }
}

4.3.2、業務流程:

1、控制類:

    @Autowired
    private OperateService operateService;

    /**
     * 導入模板下載
     * http://localhost:8081/v1/download
     * */
    @GetMapping("/download")
    public void downloadTemplate(HttpServletResponse response) {
        operateService.importTemplate(response);
    }

    /**
     * 導入
     * http://localhost:8081/v1/import-data
     */
    @PostMapping(value="/import-data")
    public Response<List<ImportExcelVO>> importExcel(@RequestParam(value = "file") MultipartFile file)  {
        List<ImportExcelVO> list = operateService.importData(file);
        return Response.success(list);
    }

2、業務類:

    /**
     * 導入模板下載
     */
    @Override
    public void importTemplate(HttpServletResponse response) {
        List<ImportExcelVO> importExcelVO = new ArrayList<>();
        try {
            //相當導出 Excel操作
            writeExcel(response, importExcelVO, "importTemplate", "表名", ImportExcelVO.class);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("錯誤信息Exception:", e);
        }
        log.info("執行完畢,導出成功");
    }

    /**
     * 導入操作
     */
    @Override
    public List<ImportExcelVO> importData(MultipartFile file) {
        List<ImportExcelVO> list = new ArrayList<>();
        try {
            //獲取數據
            list = importExcel(file, ImportExcelVO.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //數據操作:
        for (ImportExcelVO importExcelVO :
                list) {
            log.info("輸出:" + importExcelVO);
        }
        return list;
    }

4、導入實體類:

@HeadRowHeight(value = 35) // 設置表頭行高
@ContentRowHeight(value = 25) // 設置內容行高
//@ColumnWidth(value = 50) // 設置列寬
@Data
public class ImportExcelVO implements Serializable {

    @ExcelProperty(value = {"編號"},order = 1)
    private String uuid;

    @ExcelProperty(value = {"基本信息","詳情","名字"},order = 2)
    private String name;

    @ExcelProperty(value = {"基本信息","詳情","狀態"},order = 3)
    private String status;

    @ExcelProperty(value = {"基本信息","操作時間","時間"},order = 4)
    @DateTimeFormat("yyyy-MM-dd")   //時間格式
    private String startTime;


}

 

五、參考:

參考

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 面試官:我看你的簡歷上寫著精通MySQL,問你個簡單的問題,MySQL聯合索引有什麼特性? 我:MySQL聯合索引遵循最左首碼匹配原則,即最左優先,查詢的時候會優先匹配最左邊的索引。 例如當我們在(a,b,c)三個欄位上創建聯合索引時,實際上是創建了三個索引,分別是(a)、(a,b)、(a,b,c)... ...
  • 有趣的特性:CHECK約束 功能說明 在MySQL 8.0.16以前, CREATE TABLE允許從語法層面輸入下列CHECK約束,但實際沒有效果: CHECK (expr) 在 MySQL 8.0.16,CREATE TABLE添加了針對所有存儲引擎的表和列的CHECK約束的核心特性。CREAT ...
  • 在B/S系統開發中,前後端分離開發設計已成為一種標準,而VUE作為前端三大主流框架之一,越來越受到大家的青睞,Antdv是Antd在Vue中的實現。本系列文章主要通過Antdv和Asp.net WebApi開發學生信息管理系統,簡述前後端分離開發的主要相關內容,僅供學習分享使用,如有不足之處,還請指... ...
  • vue3-admin-template 項目地址:vue3-admin-template 能拿來直接開發項目,不需要考慮格式化配置、打包編譯優化等等,難道它不香嗎?~~ 此項目是集成vue3 + vite + Element-Plus + Pinia + vue-router的後臺管理系統的模板工程 ...
  • 1 配置全局組件 當一個組件使用頻率非常高的時候,可以考慮設置其為全局組件,方便其他地方調用。 案例 我這兒封裝一個Card組件想在任何地方去使用: <template> <div class="card"> <div class="card-header"> <div>主標題</div> <div ...
  • 前言 由於業務需求,需要有一個圖片標記功能,其實就是對圖片畫框畫線做標記,類似微信的圖片編輯 但是需要存下標記圖及其標記的具體數據,。功能其實很簡單,但剛開始的時候也是費了一些功夫的。我將原項目中該功能抽離出來單獨寫了一個demo,作為記錄,同時你們在開發過程中有類似需求的話也可以參考一下該思路,其 ...
  • 原文鏈接:20 多個好用的 Vue 組件庫 在本文中,將分享一些常見的 vue.js 組件。 Tables / Data Grids Vue Tables-2 地址:https://github.com/matfish2/vue-tables-2 Vue Tables 2 旨在為開發者提供一個功能齊 ...
  • HashMap概要 代碼如果沒有特定說明,為JDK 1.8 HashMap用來存放鍵值對,是Map介面的實現,是非線程安全的 可以存儲key和value為null的值,但key為null的節點只能有一個 哈希值的計算:在hashCode的基礎上添加擾動函數,使元素分佈更加隨機 哈希衝突:通過鏈表存儲 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 在我們開發過程中基本上不可或缺的用到一些敏感機密數據,比如SQL伺服器的連接串或者是OAuth2的Secret等,這些敏感數據在代碼中是不太安全的,我們不應該在源代碼中存儲密碼和其他的敏感數據,一種推薦的方式是通過Asp.Net Core的機密管理器。 機密管理器 在 ASP.NET Core ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 順序棧的介面程式 目錄順序棧的介面程式頭文件創建順序棧入棧出棧利用棧將10進位轉16進位數驗證 頭文件 #include <stdio.h> #include <stdbool.h> #include <stdlib.h> 創建順序棧 // 指的是順序棧中的元素的數據類型,用戶可以根據需要進行修改 ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • C總結與剖析:關鍵字篇 -- <<C語言深度解剖>> 目錄C總結與剖析:關鍵字篇 -- <<C語言深度解剖>>程式的本質:二進位文件變數1.變數:記憶體上的某個位置開闢的空間2.變數的初始化3.為什麼要有變數4.局部變數與全局變數5.變數的大小由類型決定6.任何一個變數,記憶體賦值都是從低地址開始往高地 ...
  • 如果讓你來做一個有狀態流式應用的故障恢復,你會如何來做呢? 單機和多機會遇到什麼不同的問題? Flink Checkpoint 是做什麼用的?原理是什麼? ...
  • C++ 多級繼承 多級繼承是一種面向對象編程(OOP)特性,允許一個類從多個基類繼承屬性和方法。它使代碼更易於組織和維護,並促進代碼重用。 多級繼承的語法 在 C++ 中,使用 : 符號來指定繼承關係。多級繼承的語法如下: class DerivedClass : public BaseClass1 ...
  • 前言 什麼是SpringCloud? Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的開發便利性簡化了分散式系統的開發,比如服務註冊、服務發現、網關、路由、鏈路追蹤等。Spring Cloud 並不是重覆造輪子,而是將市面上開發得比較好的模塊集成進去,進行封裝,從 ...
  • class_template 類模板和函數模板的定義和使用類似,我們已經進行了介紹。有時,有兩個或多個類,其功能是相同的,僅僅是數據類型不同。類模板用於實現類所需數據的類型參數化 template<class NameType, class AgeType> class Person { publi ...
  • 目錄system v IPC簡介共用記憶體需要用到的函數介面shmget函數--獲取對象IDshmat函數--獲得映射空間shmctl函數--釋放資源共用記憶體實現思路註意 system v IPC簡介 消息隊列、共用記憶體和信號量統稱為system v IPC(進程間通信機制),V是羅馬數字5,是UNI ...