使用EasyExcel導(dǎo)入導(dǎo)出Excel

在管理一個系統(tǒng)時,總會有許多的數(shù)據(jù),為了方便瀏覽查看數(shù)據(jù),系統(tǒng)總會提供「導(dǎo)出Excel」的功能;有導(dǎo)出就有導(dǎo)入,在要向數(shù)據(jù)庫中插入大量的數(shù)據(jù)時,我們向程序提供準備好的 Excel,然后程序讀取表格內(nèi)容,并將數(shù)據(jù)添加到數(shù)據(jù)庫中。

實現(xiàn)這個「導(dǎo)入/導(dǎo)出 Excel」的功能也不復(fù)雜,我們使用第三方的類庫即可實現(xiàn)。

技術(shù)選型

能夠?qū)崿F(xiàn)「導(dǎo)入/導(dǎo)出 Excel」的第三方常用類庫有 Apache poi、Java Excel(JXL)和阿里巴巴開源的 Easyexcel 等。這么多類庫該怎么選呢?在這里我給大家推薦阿里巴巴開源的「Easyexcel」。

  • 性能對比
    poi 和 jxl 對內(nèi)存的消耗很大,在處理大批量的數(shù)據(jù)時,容易造成內(nèi)存溢出。比如處理一個 3M 的 Excel,poi 和 jxl 可能需要上百兆的內(nèi)存,但 easyexcel 可能只需要幾百或幾千 KB(內(nèi)存消耗對比有些夸張)。在性能這一塊,Excel 完全是吊打 poi 和 jxl。

  • 學習復(fù)雜度對比
    我最開始使用的是 poi。在學習它的時候,理解起來不難,就是操作的時候太特么的難了。因為 poi 需要自己處理數(shù)據(jù),還有復(fù)雜的表格樣式,就光是處理數(shù)據(jù)這一款就很頭疼了。等你寫好所有的代碼,沒有幾百行,你是實現(xiàn)不了的。反觀 easyexcel。它能自己處理數(shù)據(jù),表格格式也簡單,即使是小白也很容易上手。在學習復(fù)雜的這塊也吊打 poi,而 jxl 我沒了解,但多半也是被吊打。

項目結(jié)構(gòu)

項目結(jié)構(gòu)

pom.xml

在項目中需要額外添加 EasyExcel 和文件上傳的依賴(需要上傳 Excel)。需要注意的時,EasyExcel 和 Apache poi 存在沖突,所以需要在項目中去除 poi 的依賴,然而我們并沒有在項目引入 poi 的依賴,又怎么會又 poi 呢?這是因為在我們的項目中,有其它包依賴于 poi,而我們就需要將其找出來,并去除其中的 poi 依賴。最簡單的方法就是一個個試。

.........
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <!-- 去除 poi -->
  <exclusions>
    <exclusion>
      <groupId>org.apache.poi</groupId>
      <artifactId>poi</artifactId>
    </exclusion>
  </exclusions>
  <version>${org.slf4j-version}</version>
</dependency>
<!-- 文件上傳依賴 -->
<dependency>
  <groupId>commons-io</groupId>
  <artifactId>commons-io</artifactId>
  <version>1.3.2</version>
</dependency>
<dependency>
  <groupId>commons-fileupload</groupId>
  <artifactId>commons-fileupload</artifactId>
  <version>1.2.1</version>
</dependency>
<!--Alibaba-Excel-->
<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>easyexcel</artifactId>
  <version>1.1.2-beat1</version>
</dependency>

ExcelListener

使用 EasyExcel,我們需要繼承 AnalysisEventListener

public class ExcelListener extends AnalysisEventListener {
    //可以通過實例獲取該值
    private List<Object> datas = new ArrayList<Object>();
    public void invoke(Object o, AnalysisContext analysisContext) {
        datas.add(o);//數(shù)據(jù)存儲到list,供批量處理,或后續(xù)自己業(yè)務(wù)邏輯處理。
        doSomething(o);//根據(jù)自己業(yè)務(wù)做處理
    }

    private void doSomething(Object object) {
        //1、入庫調(diào)用接口
    }

    public List<Object> getDatas() {
        return datas;
    }

    public void setDatas(List<Object> datas) {
        this.datas = datas;
    }

    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        // datas.clear();//解析結(jié)束銷毀不用的資源
    }
}

其中, invoke()doAfterAllAnalysed() 是必須實現(xiàn)的方法。

invoke() 中,我們將數(shù)據(jù)封裝到 list 中,再在控制器中,通過 getter() 方法獲取數(shù)據(jù),這樣我們就可以獲取到 easyexcel 幫我們解析好的數(shù)據(jù),再將數(shù)據(jù)進行類型轉(zhuǎn)化,這樣,我們就可以對數(shù)據(jù)進行寫入操作。

Category

這是一個實體類。我們導(dǎo)出 Excel 時,有時需要表頭,如果需要表頭,我們就可以在相應(yīng)的實體類中加入 @ExcelProperty(value = "id", index = 0) 注解,并且繼承 BaseRowModel。其中 value 代表在導(dǎo)出 Excel 時,該字段對應(yīng)的表頭名稱;index 代表該字段對應(yīng)的表頭位置。

public class Catagory extends BaseRowModel {
    @ExcelProperty(value = "id", index = 0)
    private Integer id;

    @ExcelProperty(value = "name", index = 1)
    private String name;
      .........
}

ExcleController

作為程序的控制器,其中包含 導(dǎo)入/導(dǎo)出 Excel 的 @RequestMapping 。

/expor

這是導(dǎo)出 Excel 的控制器,導(dǎo)出的思路也很簡單。

  1. 添加響應(yīng)頭信息;

  2. 添加 ExcelWriter;

  3. 添加 Sheet(表單);

  4. 添加數(shù)據(jù);

  5. 輸出。

@RequestMapping("/expor")
public String exporExcel(HttpServletResponse response) throws IOException {
        ExcelWriter writer = null;
        OutputStream outputStream = response.getOutputStream();
     try {
        //添加響應(yīng)頭信息
        response.setHeader("Content-disposition", "attachment; filename=" + "catagory.xls");
        response.setContentType("application/msexcel;charset=UTF-8");//設(shè)置類型
        response.setHeader("Pragma", "No-cache");//設(shè)置頭
        response.setHeader("Cache-Control", "no-cache");//設(shè)置頭
        response.setDateHeader("Expires", 0);//設(shè)置日期頭

        //實例化 ExcelWriter
        writer = new ExcelWriter(outputStream, ExcelTypeEnum.XLS, true);

        //實例化表單
        Sheet sheet = new Sheet(1, 0, Catagory.class);
        sheet.setSheetName("目錄");

        //獲取數(shù)據(jù)
        List<Catagory> catagoryList = excleService.findAll();
                
        //輸出
        writer.write(catagoryList, sheet);
        writer.finish();
        outputStream.flush();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            response.getOutputStream().close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return "index";
}

/import

這是導(dǎo)入 Excel 的控制器,實現(xiàn)思路與導(dǎo)入的思路類似,不過這個不需添加響應(yīng)頭信息。

  1. 實例化 ExcelListener;

  2. 實例化 ExcelReader;

  3. 讀取表格信息;

  4. 向數(shù)據(jù)庫插入數(shù)據(jù)。

@RequestMapping("/import")
public String importExcel(@RequestParam("file") MultipartFile file) throws IOException {
    InputStream inputStream = file.getInputStream();

    //實例化實現(xiàn)了AnalysisEventListener接口的類
    ExcelListener listener = new ExcelListener();
    //傳入?yún)?shù)
    ExcelReader excelReader = new ExcelReader(inputStream, ExcelTypeEnum.XLS, null, listener);
    //讀取信息
    excelReader.read(new Sheet(1, 1, Catagory.class));

    //獲取數(shù)據(jù)
    List<Object> list = listener.getDatas();

    List<Catagory> catagoryList = new ArrayList<Catagory>();
    Catagory catagory = new Catagory();

    //轉(zhuǎn)換數(shù)據(jù)類型,并插入到數(shù)據(jù)庫
    for (int i = 0; i < list.size(); i++) {
        catagory = (Catagory) list.get(i);
        catagoryMapper.insertCategory(catagory);
    }
    return "index";
}

JSP

涉及到文件的上傳,所以在 JSP 中,需要注意 formenctype 類型。不然,你在上傳文件時會一直報錯。

<form action="${pageContext.request.contextPath}/import", method="post", enctype="multipart/form-data">
    <input type="file" name="file"/>
    <input type="submit">
</form>

寫到這里,程序的主要代碼也看的差不多了,其它的代碼請查看項目源碼。

導(dǎo)出 Excel 效果

導(dǎo)出效果

JSP 效果

jsp頁面

點擊獲取項目源碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容