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
  • 1.部署歷史 猿友們好,作為初來實習的我,已經遭受社會的“毒打”,所以請容許我在下麵環節適當吐槽,3Q! 傳統部署 ​ 回顧以往在伺服器部署webapi項目(非獨立發佈),dotnet環境、守護進程兩個逃都逃不掉,正常情況下還得來個nginx代理。不僅僅這仨,可能牽扯到yum或npm。node等都要 ...
  • 隨著技術的進步,跨平臺開發已經成為了標配,在此大背景下,ASP.NET Core也應運而生。本文主要基於ASP.NET Core+Element+Sql Server開發一個校園圖書管理系統為例,簡述基於MVC三層架構開發的常見知識點,前一篇文章,已經簡單介紹瞭如何搭建開發框架,和登錄功能實現,本篇... ...
  • 這道題只要會自定義cmp恰當地進行排序,其他部分沒有什麼大問題。 上代碼: 1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,s,h1,h2,cnt; 4 struct apple{ 5 int height,ns;//height為蘋 ...
  • 這篇文章主要描述RPC的路由策略,包括為什麼需要請求隔離,為什麼不在註冊中心中實現請求隔離以及不同粒度的路由策略。 ...
  • 簡介: 中介者模式,屬於行為型的設計模式。用一個中介對象來封裝一系列的對象交互。中介者是各對象不需要顯式地相互引用,從而使其耦合鬆散,而且可以獨立地改變他們之間的交互。 適用場景: 如果平行對象間的依賴複雜,可以使用中介者解耦。 優點: 符合迪米特法則,減少成員間的依賴。 缺點: 不適用於系統出現對 ...
  • 【前置內容】Spring 學習筆記全系列傳送門: Spring學習筆記 - 第一章 - IoC(控制反轉)、IoC容器、Bean的實例化與生命周期、DI(依賴註入) Spring學習筆記 - 第二章 - 註解開發、配置管理第三方Bean、註解管理第三方Bean、Spring 整合 MyBatis 和 ...
  • 簡介: 享元模式,屬於結構型的設計模式。運用共用技術有效地支持大量細粒度的對象。 適用場景: 具有相同抽象但是細節不同的場景中。 優點: 把公共的部分分離為抽象,細節依賴於抽象,符合依賴倒轉原則。 缺點: 增加複雜性。 代碼: //用戶類 class User { private $name; fu ...
  • 這次設計一個通用的多位元組SPI介面模塊,特點如下: 可以設置為1-128位元組的SPI通信模塊 可以修改CPOL、CPHA來進行不同的通信模式 可以設置輸出的時鐘 狀態轉移圖和思路與多位元組串口發送模塊一樣,這裡就不給出了,具體可看該隨筆。 一、模塊代碼 1、需要的模塊 通用8位SPI介面模塊 `tim ...
  • AOP-03 7.AOP-切入表達式 7.1切入表達式的具體使用 1.切入表達式的作用: 通過表達式的方式定義一個或多個具體的連接點。 2.語法細節: (1)切入表達式的語法格式: execution([許可權修飾符] [返回值類型] [簡單類名/全類名] [方法名]([參數列表]) 若目標類、介面與 ...
  • 測試一、虛繼承與繼承的區別 1.1 單個繼承,不帶虛函數 1>class B size(8): 1> + 1> 0 | + (base class A) 1> 0 | | _ia //4B 1> | + 1> 4 | _ib //4B 有兩個int類型數據成員,占8B,基類邏輯存在前面 1.2、單個 ...