欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

java如何在項(xiàng)目中實(shí)現(xiàn)excel導(dǎo)入導(dǎo)出功能

 更新時(shí)間:2024年10月08日 11:23:19   作者:光明_吖吼  
這篇文章主要介紹了java如何在項(xiàng)目中實(shí)現(xiàn)excel導(dǎo)入導(dǎo)出功能的相關(guān)資料,EasyExcel是一個(gè)基于Apache?POI開發(fā)的開源Java庫(kù),用于簡(jiǎn)化Excel文件的讀寫操作,文中將用法介紹的非常詳細(xì),需要的朋友可以參考下

一、初識(shí)EasyExcel*

1. Apache POI

先說(shuō)POI,有過(guò)報(bào)表導(dǎo)入導(dǎo)出經(jīng)驗(yàn)的同學(xué),應(yīng)該聽(tīng)過(guò)或者使用。

Apache POI是Apache軟件基金會(huì)的開源函式庫(kù),提供跨平臺(tái)的Java API實(shí)現(xiàn)Microsoft Office格式檔案讀寫。但是存在如下一些問(wèn)題:

1.1 學(xué)習(xí)使用成本較高

對(duì)POI有過(guò)深入了解的才知道原來(lái)POI還有SAX模式(Dom解析模式)。但SAX模式相對(duì)比較復(fù)雜,excel有03和07兩種版本,兩個(gè)版本數(shù)據(jù)存儲(chǔ)方式截然不同,sax解析方式也各不一樣。

想要了解清楚這兩種解析方式,才去寫代碼測(cè)試,估計(jì)兩天時(shí)間是需要的。再加上即使解析完,要轉(zhuǎn)換到自己業(yè)務(wù)模型還要很多繁瑣的代碼??傮w下來(lái)感覺(jué)至少需要三天,由于代碼復(fù)雜,后續(xù)維護(hù)成本巨大。

POI的SAX模式的API可以一定程度的解決一些內(nèi)存溢出的問(wèn)題,但是POI還是有一些缺陷,比如07版Excel解壓縮以及解壓后存儲(chǔ)都是在內(nèi)存中完成的,內(nèi)存消耗依然很大,一個(gè)3M的Excel用POI的SAX解析,依然需要100M左右內(nèi)存。

1.2 POI的內(nèi)存消耗較大

大部分使用POI都是使用他的userModel模式。userModel的好處是上手容易使用簡(jiǎn)單,隨便拷貝個(gè)代碼跑一下,剩下就是寫業(yè)務(wù)轉(zhuǎn)換了,雖然轉(zhuǎn)換也要寫上百行代碼,相對(duì)比較好理解。然而userModel模式最大的問(wèn)題是在于非常大的內(nèi)存消耗,一個(gè)幾兆的文件解析要用掉上百兆的內(nèi)存。現(xiàn)在很多應(yīng)用采用這種模式,之所以還正常在跑一定是并發(fā)不大,并發(fā)上來(lái)后一定會(huì)OOM或者頻繁的full gc。

總體上來(lái)說(shuō),簡(jiǎn)單寫法重度依賴內(nèi)存,復(fù)雜寫法學(xué)習(xí)成本高。

特點(diǎn)

  • 功能強(qiáng)大

  • 代碼書寫冗余繁雜

  • 讀寫大文件耗費(fèi)內(nèi)存較大,容易OOM

2. EasyExcel

2.1 重寫了POI對(duì)07版Excel的解析

  • EasyExcel重寫了POI對(duì)07版Excel的解析,可以把內(nèi)存消耗從100M左右降低到10M以內(nèi),并且再大的Excel不會(huì)出現(xiàn)內(nèi)存溢出,03版仍依賴POI的SAX模式。

  • 下圖為64M內(nèi)存1分鐘內(nèi)讀取75M(46W行25列)的Excel(當(dāng)然還有急速模式能更快,但是內(nèi)存占用會(huì)在100M多一點(diǎn))

  • 在上層做了模型轉(zhuǎn)換的封裝,讓使用者更加簡(jiǎn)單方便

特點(diǎn)

  • 在數(shù)據(jù)模型層面進(jìn)行了封裝,使用簡(jiǎn)單
  • 重寫了07版本的Excel的解析代碼,降低內(nèi)存消耗,能有效避免OOM
  • 只能操作Excel
  • 不能讀取圖片

二、快速入門–QuickStart

0、導(dǎo)入依賴坐標(biāo)

<!-- EasyExcel -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>2.1.6</version>
</dependency>
<!-- lombok 優(yōu)雅編程 -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.20</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>

導(dǎo)入easyexcel-2.1.6坐標(biāo)的時(shí)候,已依賴傳遞導(dǎo)入poi-3.17的POI。

1、最簡(jiǎn)單的讀

1.1、需求、準(zhǔn)備工作

/**
 * 需求:?jiǎn)螌?shí)體導(dǎo)入(從磁盤將文件導(dǎo)入到應(yīng)用程序)
 * 導(dǎo)入Excel學(xué)員信息到系統(tǒng)。
 * 包含如下列:姓名、性別、出生日期
 * 模板詳見(jiàn):學(xué)員信息.xlsx
 */

學(xué)員信息.xlsx

1.2、編寫導(dǎo)出數(shù)據(jù)的實(shí)體類

package com.taotie.test;

import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc
 */
// 基于lombok
@Data
@NoArgsConstructor
@AllArgsConstructor
@HeadRowHeight(20) // 指定列頭行高
@ColumnWidth(20) // 指定列寬
public class Student {
    /**
     * 學(xué)生姓名
     */
    @ExcelProperty(value = "學(xué)生姓名", index = 0)
    private String name;
    /**
     * 學(xué)生性別
     */
    @ExcelProperty(value = "學(xué)生性別", index = 2)
    private String gender;

    /**
     * 學(xué)生出生日期
     */
    @ExcelProperty(value = "學(xué)生出生日期", index = 1)
    private Date birthday;
    /**
     * id
     */
    // @ExcelProperty(value = "編號(hào)",index = 3)
    @ExcelIgnore // 忽略,不讀取
    private String id;
}

注解: 文章后面有詳解

1.3、 讀取Excel文件(上傳)

調(diào)用EasyExcelAPI讀取的Excel文件的測(cè)試類StudentReadDemo

package com.taotie.test;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
import com.alibaba.excel.read.builder.ExcelReaderSheetBuilder;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc
 */
@SpringBootTest 
public class TestEasyExcel {

    /**
     * 測(cè)試讀取數(shù)據(jù)
     */
    @Test
    public void testRead() {
        // 讀取文件,讀取完之后會(huì)自動(dòng)關(guān)閉
        /**
         * 參數(shù)1:pathName  文件路徑;"d:\\學(xué)員信息.xls"
         * 參數(shù)2:head		 每行數(shù)據(jù)對(duì)應(yīng)的實(shí)體;Student.class
         * 參數(shù)3:readListener	讀監(jiān)聽(tīng)器,每讀一樣就會(huì)調(diào)用一次該監(jiān)聽(tīng)器的invoke方法
         * 參數(shù)4:sheet方法參數(shù): 工作表的順序號(hào)(從0開始)或者工作表的名字,不傳默認(rèn)為0
         */
        // // 封裝工作簿對(duì)象
        // ExcelReaderBuilder workBook = EasyExcel.read
        //         ("E:\\學(xué)員信息.xlsx",
        //                 Student.class,
        //                 new StudentReadListener( ));
        // // 封裝工作表
        // ExcelReaderSheetBuilder sheet1 = workBook.sheet( );
        // // 讀取
        // sheet1.doRead( );
        
        // 最簡(jiǎn)單的寫法
        EasyExcel.read("E:\\學(xué)員信息.xlsx",Student.class,new StudentReadListener()).sheet().doRead();
    }
}

讀取Excel的監(jiān)聽(tīng)器,用于處理讀取產(chǎn)生的數(shù)據(jù)

package com.taotie.listener;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.taotie.domain.Student;

/**
 * @Author Vsunks.v
 * @Description:
 */
public class StudentReadListener extends AnalysisEventListener<Student> {
    // 每讀一行,會(huì)調(diào)用該invoke方法一次
    @Override
    public void invoke(Student data, AnalysisContext context) {
        System.out.println("data = " + data);
    }

    // 全部讀完之后,會(huì)調(diào)用該方法
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // TODO......
    }
}

2、最簡(jiǎn)單的寫(導(dǎo)出)

2.1 需求、準(zhǔn)備工作

/**
 * 需求:?jiǎn)螌?shí)體導(dǎo)出(從應(yīng)用程序?qū)⑽募?dǎo)入到磁盤)
 * 導(dǎo)出多個(gè)學(xué)生對(duì)象到Excel表格
 * 包含如下列:姓名、性別、出生日期
 * 模板詳見(jiàn):學(xué)員信息.xlsx
 */

2.2、編寫導(dǎo)出數(shù)據(jù)的實(shí)體

// 還是上個(gè)實(shí)體類...

2.3、 準(zhǔn)備數(shù)據(jù)并寫入到文件

    /**
     * 測(cè)試寫出數(shù)據(jù)
     */
    @Test
    public void simpleWrite() {
        // 創(chuàng)造數(shù)據(jù)
        ArrayList<Student> list = new ArrayList<>( );
        list.add(new Student("張三","男",new Date(),"1001"));
        list.add(new Student("李四","女",new Date(),"1002"));
        list.add(new Student("王五","男",new Date(),"1003"));
        list.add(new Student("趙六","女",new Date(),"1004"));
        list.add(new Student("周期","男",new Date(),"1005"));
        list.add(new Student("茅十八","女",new Date(),"1006"));

        // 寫出的文件路徑,當(dāng)前項(xiàng)目下
        String fileName = "student.xlsx";

        // 這里 需要指定寫用哪個(gè)class去寫,然后寫到第一個(gè)sheet,名字為模板 然后文件流會(huì)自動(dòng)關(guān)閉
        // 如果這里想使用03 則 傳入excelType參數(shù)即可
        EasyExcel.write(fileName, Student.class).sheet("學(xué)生信息").doWrite(list);
        System.out.println("導(dǎo)出OK" );
    }

三、vue文件上傳和下載[重點(diǎn)]

基于springboot的文件上傳和下載

0. 導(dǎo)入依賴

<!-- EasyExcel -->

<!-- lombok -->

<!-- junit -->

3.1 文件上傳

注意: 本地Excel表格,列要和數(shù)據(jù)庫(kù)一致

需求: 批量插入計(jì)量單位(導(dǎo)入excel數(shù)據(jù)到項(xiàng)目中)

思路:

  • 前端設(shè)計(jì)文件上傳組件 ,點(diǎn)擊開始文件上傳
  • 后端接收文件,使用工具解析數(shù)據(jù)
  • 插入數(shù)據(jù)庫(kù)

3.1.1 前端

在頁(yè)面設(shè)計(jì)上傳的組件

1.設(shè)置上傳按鈕,顯示上傳的對(duì)話框

2.設(shè)置對(duì)話框+上傳組件

  <!-- 上傳excel的對(duì)話框 -->
  <el-dialog title="上傳計(jì)量單位Excel" :visible.sync="dialogExcelVisible" width="40%">
    <el-upload
      class="upload-demo"
      drag
      action="http://localhost:8888/md/unit/upload/excel"
      accept=".xlsx,.xls"
      :on-success="uploadExcelSuccess"
      :on-error="uploadExcelError"
      multiple>
      <i class="el-icon-upload"></i>
      <div class="el-upload__text">將文件拖到此處,或<em>點(diǎn)擊上傳</em></div>
      <div class="el-upload__tip" slot="tip">只能上傳.xlsx,.xls文件,且不超過(guò)500kb</div>
    </el-upload>
  </el-dialog>
uploadExcelSuccess(){
  this.$message({
    type:"success",
    message:"上傳成功"
  })
  this.dialogExcelVisible = false;
  this.fetchData();
},
uploadExcelError(err){
  this.$message({
    type:"error",
    message:err
  })
}

3.1.2 后端-實(shí)體類注解

3.1.3 后端-監(jiān)聽(tīng)器

package com.qf.config;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.qf.entity.SysUser;
import com.qf.entity.UnitMeasure;
import com.qf.service.SysUserService;
import com.qf.service.UnitMeasureService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import java.util.ArrayList;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc
 */
@Component
@Scope("prototype")    // 作者要求每次讀取都要使用新的Listener
public class MdUnitMeasureReadListener extends AnalysisEventListener<UnitMeasure> {
    // 有個(gè)很重要的點(diǎn) DemoDataListener 不能被spring管理,
    // 要每次讀取excel都要new,然后里面用到spring可以構(gòu)造方法傳進(jìn)去
    private UnitMeasureService service;
    public MdUnitMeasureReadListener(){} // 空參構(gòu)造

    // 有參構(gòu)造
    public MdUnitMeasureReadListener(UnitMeasureService service){
        this.service = service;
    }

    // 每隔5條存儲(chǔ)數(shù)據(jù)庫(kù),實(shí)際項(xiàng)目中使用時(shí)可以100條,然后清理list ,方便內(nèi)存回收
    private final int BATCH_COUNT = 5;
    private ArrayList<UnitMeasure> list = new ArrayList<>( );

    // 每讀一行,會(huì)調(diào)用該invoke方法一次
    @Override
    public void invoke(UnitMeasure data, AnalysisContext context) {
        list.add(data);
        // 達(dá)到BATCH_COUNT了,需要去存儲(chǔ)一次數(shù)據(jù)庫(kù),防止數(shù)據(jù)幾萬(wàn)條數(shù)據(jù)在內(nèi)存,容易OOM
        if (list.size( ) >= BATCH_COUNT) {
            // 調(diào)用方法,執(zhí)行插入
            saveData( );
            // 存儲(chǔ)完成清理 list
            list.clear();
        }
    }

    // 全部讀完之后,會(huì)調(diào)用該方法
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 這里也要保存數(shù)據(jù),確保最后遺留的數(shù)據(jù)也存儲(chǔ)到數(shù)據(jù)庫(kù)
        if(list.size() > 0) {
            saveData( );
        }
        System.out.println("所有數(shù)據(jù)解析完成!");
    }


    // 向數(shù)據(jù)庫(kù)插入數(shù)據(jù)
    private void saveData() {
        System.out.println("開始存儲(chǔ)數(shù)據(jù)庫(kù)!");

        // 調(diào)用業(yè)務(wù)層存數(shù)據(jù)庫(kù)
        service.saveBatch(list);
        System.out.println("存儲(chǔ)數(shù)據(jù)庫(kù)成功!");
    }
}

3.1.4 后端-Controller接收

 /**
     * 上傳Excel文件
     */
    @PostMapping("/upload/excel")
    public R uploadExcel(MultipartFile file) {
        try {
            // 重點(diǎn),此處第三個(gè)參數(shù)需要傳入Service對(duì)象
            EasyExcel.read(file.getInputStream( ),
                            UnitMeasure.class,
                            new MdUnitMeasureReadListener(service))
                    .sheet( ).doRead( );
        }catch (Exception e){
            e.printStackTrace();
            return R.fail(e.getMessage());
        }
        return R.ok( );
    }

3.1.5 后端-Service

// 需要添加批量插入的方法

3.1.6 后端-Mapper

       <!-- 批量插入 -->
    <insert id="saveBatch">
        insert into
            md_unit_measure       (measure_code,measure_name,primary_flag,primary_id,change_rate,enable_flag)
        values
        <foreach collection="list" item="unit" separator=",">
            (#{unit.measureCode},
            #{unit.measureName},
            #{unit.primaryFlag},
            #{unit.primaryId},
            #{unit.changeRate},
            #{unit.enableFlag})
        </foreach>

3.1.7 測(cè)試

本地創(chuàng)建一個(gè)excel表格,按照實(shí)體類中定義的列名填充數(shù)據(jù)

點(diǎn)擊上傳

3.2 文件導(dǎo)出

需求: 將項(xiàng)目中的數(shù)據(jù)導(dǎo)出到本地excel表格

思路:

  • 前端設(shè)計(jì)按鈕,點(diǎn)擊開始導(dǎo)出
  • 后端請(qǐng)求,查詢出數(shù)據(jù),
  • 使用工具導(dǎo)出

實(shí)體類于之前一樣

// 略

Controller層

/**
 * 下載Excel文件
 * 注意,返回值是void
 */
@GetMapping("/download/excel")
public void downloadExcel(HttpServletResponse response) throws IOException {

    //  查詢數(shù)據(jù)庫(kù)全部數(shù)據(jù)
    List<UnitMeasure> list = service.findAll(null);

    // 下面這個(gè)注釋是前端使用方式1,即a標(biāo)簽發(fā)請(qǐng)求時(shí)采用
    response.setContentType("application/vnd.ms-excel");
    response.setCharacterEncoding("utf-8");
    // 這里URLEncoder.encode可以防止中文亂碼
    String fileName = URLEncoder.encode("計(jì)量單位信息", "UTF-8");
    response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");

    // easyexcel導(dǎo)出工具
    EasyExcel.write(response.getOutputStream(), UnitMeasure.class).autoCloseStream(Boolean.FALSE).sheet("計(jì)量單位信息")
        .doWrite(list);
}

// todo servicce+mapper實(shí)現(xiàn)查詢?nèi)?/p>

前端

1.導(dǎo)出按鈕觸發(fā)函數(shù)

2.函數(shù)內(nèi)確認(rèn)導(dǎo)出,發(fā)出請(qǐng)求到后端

3.3、自定義單元格樣式

EasyExcel支持調(diào)整行高、列寬、背景色、字體大小等內(nèi)容,但是控制方式與使用原生POI無(wú)異,比較繁瑣,不建議使用。

但是可以使用模板填充的方式,向預(yù)設(shè)樣式的表格中直接寫入數(shù)據(jù),寫入數(shù)據(jù)的時(shí)候會(huì)保持原有樣式。

總結(jié)

到此這篇關(guān)于java如何在項(xiàng)目中實(shí)現(xiàn)excel導(dǎo)入導(dǎo)出功能的文章就介紹到這了,更多相關(guān)java實(shí)現(xiàn)excel導(dǎo)入導(dǎo)出內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JAVA常用API總結(jié)與說(shuō)明

    JAVA常用API總結(jié)與說(shuō)明

    這篇文章主要介紹了JAVA常用API總結(jié)與說(shuō)明,包括JAVA線程常用API,JAVA隊(duì)列常用API,JAVA泛型集合算法常用API,JAVA并發(fā)常用API需要的朋友可以參考下
    2022-12-12
  • Mybatis Interceptor 攔截器的實(shí)現(xiàn)

    Mybatis Interceptor 攔截器的實(shí)現(xiàn)

    這篇文章主要介紹了Mybatis Interceptor 攔截器的實(shí)現(xiàn),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-12-12
  • 大數(shù)據(jù) java hive udf函數(shù)的示例代碼(手機(jī)號(hào)碼脫敏)

    大數(shù)據(jù) java hive udf函數(shù)的示例代碼(手機(jī)號(hào)碼脫敏)

    這篇文章主要介紹了大數(shù)據(jù) java hive udf函數(shù)(手機(jī)號(hào)碼脫敏),的相關(guān)知識(shí),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-06-06
  • 基于spring中的aop簡(jiǎn)單實(shí)例講解

    基于spring中的aop簡(jiǎn)單實(shí)例講解

    下面小編就為大家?guī)?lái)一篇基于spring中的aop簡(jiǎn)單實(shí)例講解。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-07-07
  • Java設(shè)計(jì)模式之享元模式實(shí)例詳解

    Java設(shè)計(jì)模式之享元模式實(shí)例詳解

    這篇文章主要介紹了Java設(shè)計(jì)模式之享元模式,結(jié)合實(shí)例形式詳細(xì)分析了享元模式的概念、功能、定義及使用方法,需要的朋友可以參考下
    2018-04-04
  • java?poi?讀取單元格null或者空字符串方式

    java?poi?讀取單元格null或者空字符串方式

    這篇文章主要介紹了java?poi?讀取單元格null或者空字符串方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • SpringMVC實(shí)現(xiàn)賬號(hào)只能在一處登陸

    SpringMVC實(shí)現(xiàn)賬號(hào)只能在一處登陸

    這篇文章主要為大家詳細(xì)介紹了SpringMVC如何實(shí)現(xiàn)賬號(hào)只能在一處登陸,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • 詳解SpringBoot初始教程之Tomcat、Https配置以及Jetty優(yōu)化

    詳解SpringBoot初始教程之Tomcat、Https配置以及Jetty優(yōu)化

    本篇文章主要介紹了詳解SpringBoot初始教程之Tomcat、Https配置以及Jetty優(yōu)化,具有一定的參考價(jià)值,有興趣的可以了解一下
    2017-09-09
  • springboot實(shí)現(xiàn)過(guò)濾器的示例代碼

    springboot實(shí)現(xiàn)過(guò)濾器的示例代碼

    JavaWeb開發(fā)中,過(guò)濾器Filter是三大組件之一,主要用于請(qǐng)求攔截和響應(yīng)處理,如權(quán)限校驗(yàn)、日志記錄、請(qǐng)求過(guò)濾等,本文就來(lái)介紹一下springboot實(shí)現(xiàn)過(guò)濾器的示例代碼,感興趣的可以了解一下
    2024-10-10
  • SpringBoot整合Redis的哨兵模式的實(shí)現(xiàn)

    SpringBoot整合Redis的哨兵模式的實(shí)現(xiàn)

    Redis提供了哨兵模式來(lái)處理主從切換和故障轉(zhuǎn)移,本文主要介紹了SpringBoot整合Redis的哨兵模式的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-08-08

最新評(píng)論