国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

目錄
Excel模板的設(shè)計(jì)" >Excel模板的設(shè)計(jì)
一個(gè)簡(jiǎn)單的Excel報(bào)表範(fàn)本 " >一個(gè)簡(jiǎn)單的Excel報(bào)表範(fàn)本
一個(gè)複雜的Excel報(bào)表範(fàn)本 " >一個(gè)複雜的Excel報(bào)表範(fàn)本
複雜範(fàn)本設(shè)計(jì)剖析 " >複雜範(fàn)本設(shè)計(jì)剖析
準(zhǔn)備模板數(shù)據(jù) " >準(zhǔn)備模板數(shù)據(jù)
圖片數(shù)據(jù)導(dǎo)出 " >圖片數(shù)據(jù)導(dǎo)出
將數(shù)據(jù)導(dǎo)出至模板 " >將數(shù)據(jù)導(dǎo)出至模板
首頁(yè) 專(zhuān)題 excel 使用 EasyPOI 優(yōu)雅匯出Excel模板資料(含圖片)

使用 EasyPOI 優(yōu)雅匯出Excel模板資料(含圖片)

Jul 26, 2023 pm 04:32 PM
easypoi

前言

最近有讀者在問(wèn)easypoi的問(wèn)題,抽空整理了一篇文章。

正文

EasyPOI功能如同名字Easy,主打的功能就是容易,讓一個(gè)沒(méi)接觸過(guò)POI的人員可以方便的寫(xiě)出Excel導(dǎo)出,Excel模板導(dǎo)出,Excel導(dǎo)入,Word範(fàn)本匯出。透過(guò)簡(jiǎn)單的註解和模板語(yǔ)言(熟悉的表達(dá)式語(yǔ)法),完成先前複雜的寫(xiě)法。

本文主要透過(guò)簡(jiǎn)單的分析讓讀者知道Excel模板該如何編寫(xiě),EasyPOI要如何使用才能導(dǎo)出滿(mǎn)足自己需要的Excel數(shù)據(jù),從而簡(jiǎn)化編碼。同時(shí)本文也會(huì)對(duì)一些不常見(jiàn)的功能如圖片匯出功能進(jìn)行說(shuō)明,讓讀者少踩坑。

版本及相依說(shuō)明

EasyPOI4.0.0及以後的版本依賴(lài)Apache POI的4.0.0及以後版本。所以在maven的配置中,兩者的版本號(hào)碼一定要匹配。

要注意的是,Apache POI的4.0.0相對(duì)之前的版本有很大的變更,如果之前程式碼中Excel操作部分依賴(lài)舊的版本,那麼不建議使用4.0.0及之後的版本。當(dāng)然,如果之前程式碼不涉及或很少涉及WorkBook的創(chuàng)建細(xì)節(jié),使用新版也沒(méi)有問(wèn)題。

筆者需要改寫(xiě)的項(xiàng)目是基於JEECG 3.7版本,依賴(lài)的是3.9版本的Apache POI,而JEECG維護(hù)的jeasypoi版本最高只有2.2.0,而該版本並不支援模板匯出圖片功能。說(shuō)到這裡又要吐槽以下JEECG團(tuán)隊(duì),既然自己不打算維護(hù)jeasypoi,那專(zhuān)案中直接使用官方的EasyPOI不就好了,2.2.0版本的jeasypoi給開(kāi)發(fā)者挖了多少坑??!

為了和舊版相容,又想使用EasyPOI帶來(lái)的圖片匯出功能,所以筆者最終採(cǎi)用的EasyPOI版本是3.3.0,對(duì)應(yīng)的Apache POI依賴(lài)是3.15。

Maven配置如下所示:

<properties>
    <poi.version>3.15</poi.version>
    <easypoi.version>3.3.0</easypoi.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>${poi.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>${poi.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml-schemas</artifactId>
        <version>${poi.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-scratchpad</artifactId>
        <version>${poi.version}</version>
    </dependency>
    <dependency>
        <groupId>cn.afterturn</groupId>
        <artifactId>easypoi-web</artifactId>
        <version>${easypoi.version}</version>
    </dependency>
</dependencies>

Excel模板的設(shè)計(jì)

我們使用EasyPOI的模板匯出功能就是不想透過(guò)編碼的方式來(lái)設(shè)計(jì)Excel報(bào)表的樣式,所以工作的第一步就是設(shè)計(jì)Excel模板,分清楚哪些部分是固定的,哪些是需要循環(huán)填入的。 EasyPOI有自己的表達(dá)式語(yǔ)言,每種表達(dá)式的詳細(xì)介紹請(qǐng)參考後文的參考連結(jié)。

一個(gè)簡(jiǎn)單的Excel報(bào)表範(fàn)本

#一些簡(jiǎn)單的範(fàn)本就不在這裡詳細(xì)解釋了,只放一下效果圖和模板配置內(nèi)容。等讀者明白了複雜的模板如何製作並如何填值的時(shí)候,簡(jiǎn)單的很快就能明白了。

先看看報(bào)表效果圖:

使用 EasyPOI 優(yōu)雅匯出Excel模板資料(含圖片)

再看看實(shí)際的範(fàn)本:

使用 EasyPOI 優(yōu)雅匯出Excel模板資料(含圖片)

看了上述兩張圖,是不是已經(jīng)感受到模板導(dǎo)出功能的強(qiáng)大了呢?

一個(gè)複雜的Excel報(bào)表範(fàn)本

下面要介紹的這個(gè)範(fàn)本比較複雜,不像是常見(jiàn)的那種一行是一筆記錄的情況,所以將詳細(xì)介紹該範(fàn)本的配置,順帶對(duì)EasyPOI的部分錶達(dá)式進(jìn)行簡(jiǎn)單介紹。

還是先看效果圖:

使用 EasyPOI 優(yōu)雅匯出Excel模板資料(含圖片)

再看看範(fàn)本:

使用 EasyPOI 優(yōu)雅匯出Excel模板資料(含圖片)

##這兩張圖一對(duì)比,是不是有種知識(shí)改變命運(yùn)的感覺(jué)?

複雜範(fàn)本設(shè)計(jì)剖析

#從貨品資訊的範(fàn)本圖及效果圖中我們發(fā)現(xiàn),整個(gè)範(fàn)本實(shí)際上分為上下兩部分。其中上部分為不變的抬頭訊息,下部分為循環(huán)插入的貨品明細(xì)訊息。所以我們關(guān)注的重點(diǎn)是下半部的文法。

下半部的第一列圖中沒(méi)有顯示完整,實(shí)際上是{{!fe: list t.id。

注意,這裡 沒(méi)有 }}符號(hào)!根據(jù)EasyPOI的官方文檔,{{}}代表的是表達(dá)式,根據(jù)表達(dá)式取裡邊的值。仔細(xì)看圖可以發(fā)現(xiàn),表達(dá)式的閉合符號(hào){{}}出現(xiàn)在圖中的右下角。也就是說(shuō),從第一列{{開(kāi)始到右下角}}結(jié)束,這中間的所有內(nèi)容都是表達(dá)式的一部分。

因?yàn)檎麄€(gè)範(fàn)本資訊都是表達(dá)式的一部分,所以即使是普通字串也需要專(zhuān)門(mén)標(biāo)明。下面將表達(dá)式中的子表達(dá)式逐一說(shuō)明。

!fe: 遍歷資料不建立row。

官方文件中的這句話(huà)大家理解起來(lái)可能有點(diǎn)費(fèi)解,什麼叫不創(chuàng)建row?實(shí)際上,不建立row是相對(duì)於建立row而言的,建立row的表達(dá)式是fe:。

就像是資料庫(kù)中每筆記錄對(duì)應(yīng)著一個(gè)實(shí)體對(duì)象,創(chuàng)建row表示每行就是一個(gè)實(shí)體對(duì)象Entity,這個(gè)實(shí)體對(duì)象的屬性用{{}}表達(dá)式包裹起來(lái)。

不建立row表示整個(gè)表達(dá)式中只有一個(gè)實(shí)體物件Object,只不過(guò)這個(gè)Object比較特別,它是由list中N個(gè)Entity拼接起來(lái)的。每一個(gè)Entity不只是指模型本身,也包含了Excel的樣式,例如佔(zhàn)用了幾個(gè)單元格,單元格的座標(biāo)、排布順序等。

list 自訂的名稱(chēng),表示表達(dá)式中的資料集合,由程式碼以list為鍵,從Map中取得值的集合。

list這個(gè)名字很容易理解,就是一個(gè)佔(zhàn)位符,可以隨便取。 EasyPOI解析到list就知道Map中存在該鍵的值的集合,後邊解析到資料就從該集合取即可。

搜尋Java知音公眾號(hào),回覆“後端面試”,送你一份Java面試題寶典.pdf

t 預(yù)定義值,表示集合中的任意物件。

從模板中我們大致可以感覺(jué)到,list中每個(gè)物件叫做t,t.name就代表t的name屬性,所以t這個(gè)名字就可以隨便叫,反正它和list一樣,作用是佔(zhàn)位符。

但其實(shí)這是一個(gè)大坑!如果你把t換成了其他值例如g,模板中其他地方寫(xiě)g.name g.code等等,最後是解析不到的!官方文件對(duì)這一點(diǎn)並沒(méi)有強(qiáng)調(diào),而是作者實(shí)際踩了坑之後才發(fā)現(xiàn)的!

]] 換行符號(hào) 多行遍歷匯出。

對(duì)於這個(gè)符號(hào)的官方解釋也是莫名其妙,什麼叫換行符,多行遍歷導(dǎo)出?實(shí)際上它的意思就是,當(dāng)解析到表達(dá)式中含有這個(gè)符號(hào),該行後邊的內(nèi)容就不解析了,管你後邊有沒(méi)有其他內(nèi)容或樣式。

該符號(hào)一定要寫(xiě)在每行的最後一列,不然會(huì)出現(xiàn)每行列數(shù)不一樣的情況,EasyPOI內(nèi)部做賦值的時(shí)候就會(huì)報(bào)空指標(biāo)異常了。

‘’ 單引號(hào)表示常數(shù)值 ‘’ 例如’1’ 那麼輸出的就是 1

##官方文件中這裡的介紹也有坑。 ''是表示常數(shù)值,但實(shí)際上Excel中只是這麼些是不對(duì)的,因?yàn)镋xcel的單元格中遇到'後會(huì)認(rèn)為後面都是字符串,所以得在單元格中寫(xiě)''庫(kù)別:' ,這樣顯示出來(lái)的才是'庫(kù)別:',而不是字串庫(kù)別:'。

經(jīng)過(guò)上述分析,圖中的範(fàn)本其實(shí)就類(lèi)似以下內(nèi)容:

{{!fe: list t.id ‘庫(kù)別:’ t.bin 換行 ‘商品名稱(chēng):’ t.name 換行 ‘商品編號(hào):’ t.code t.barcode 換行 ‘生產(chǎn)日期:’ t.proDate 換行 ‘進(jìn)貨日期:’ t.recvDate}}

如果list中有多條記錄,上述字符串就再循環(huán)拼接一些內(nèi)容,最終都在一個(gè){{}}表達(dá)式中。

至此,模板的設(shè)計(jì)已剖析完畢,讀者可根據(jù)自己的需求結(jié)合官方文檔自行設(shè)計(jì)模板。下面將對(duì)模板賦值進(jìn)行介紹。

準(zhǔn)備模板數(shù)據(jù)

從上節(jié)的描述中可知,只需要準(zhǔn)備一個(gè)Map的對(duì)象即可,其中鍵為list,值為一個(gè)List數(shù)組,數(shù)組中元素類(lèi)型為Map。代碼如下:

Map<String, Object> total = new HashMap<>();
List<Map<String, Object>> mapList = new ArrayList<>();
for (int i = 1; i <= 5; i++) {
    Map<String, Object> map = new HashMap<>();
    map.put("id", i + "");
    map.put("bin", "001 1000千克");
    map.put("name", "商品" + i);
    map.put("code", "goods" + i);
    map.put("proDate", "2019-05-30");
    map.put("recvDate", "2019-07-07");

    // 插入圖片
    ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
    BufferedImage bufferImg = ImageIO.read(BarcodeUtil.generateToStream("001"));
    ImageIO.write(bufferImg, "jpg", byteArrayOut);
    ImageEntity imageEntity = new ImageEntity(byteArrayOut.toByteArray(), 200, 1000);
    map.put("barcode", imageEntity);

    mapList.add(map);
}
total.put("list", mapList);

圖片數(shù)據(jù)導(dǎo)出

上述代碼中需要特殊關(guān)注的是圖片導(dǎo)出部分。EasyPOI導(dǎo)出圖片有兩種方式,一種是通過(guò)圖片的Url,還有一種是獲取圖片的byte[],畢竟圖片的本質(zhì)就是byte[]。因?yàn)楣P者的項(xiàng)目中圖片不是存放在數(shù)據(jù)庫(kù)之中,而是需要根據(jù)查詢(xún)結(jié)果動(dòng)態(tài)生成條碼,所以通過(guò)byte[]導(dǎo)出圖片。

ImageEntity是EasyPOI內(nèi)置的一個(gè)JavaBean,用于設(shè)定圖片的寬度和高度、導(dǎo)出方式、RowSpan和ColumnSpan等。調(diào)試EasyPOI的源碼可知,當(dāng)設(shè)置了RowSpan或者ColumnSpan之后,圖片的高度設(shè)置就失效了,圖片大小會(huì)自動(dòng)填充圖片所在的單元格。

圖片導(dǎo)出的坑點(diǎn)在于導(dǎo)出圖片的大小。假設(shè)我們將四個(gè)單元格合成為一個(gè),希望導(dǎo)出的圖片能填充合并之后的單元格,但是對(duì)不起,EasyPOI暫時(shí)做不到,它只會(huì)填充合并之前左上角的單元格,具體原因如下源碼所示:

//BaseExportService.java
ClientAnchor anchor;
if (type.equals(ExcelType.HSSF)) {
    anchor = new HSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1),
            cell.getRow().getRowNum() + 1);
} else {
    anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1),
            cell.getRow().getRowNum() + 1);
}

可以看到,在創(chuàng)建圖片插入位置的時(shí)候已經(jīng)指定了圖片的跨度為1行1列,即左上角的單元格。如果之前又設(shè)置了RowSpan或者ColumnSpan,那么圖片高度的設(shè)置也會(huì)失效,最終導(dǎo)致導(dǎo)出的圖片非常小。

搜索Java知音公眾號(hào),回復(fù)“后端面試”,送你一份Java面試題寶典.pdf

個(gè)人認(rèn)為ImageEntity提供的RowSpan或者ColumnSpan的set方法并沒(méi)有什么用,因?yàn)槲覀儎?dòng)態(tài)創(chuàng)建的合并單元格并不能被賦值。所以,導(dǎo)出圖片的最好方式就是直接指定它的高度,因?yàn)閷挾葧?huì)自動(dòng)填充單元格,模板中單元格的寬度要合適。

//ExcelExportOfTemplateUtil.java
if (img.getRowspan()>1 || img.getColspan() > 1){
    img.setHeight(0);
    PoiMergeCellUtil.addMergedRegion(cell.getSheet(),cell.getRowIndex(),
            cell.getRowIndex() + img.getRowspan() - 1, cell.getColumnIndex(), cell.getColumnIndex() + img.getColspan() -1);
}

將數(shù)據(jù)導(dǎo)出至模板

以上準(zhǔn)備工作全部完成后就可以將模板和數(shù)據(jù)進(jìn)行組裝了,或者說(shuō)是渲染,代碼如下所示:

public static void exportByTemplate(String templateName, Map<String, Object> data, OutputStream fileOut) {
    TemplateExportParams params = new TemplateExportParams("export/template/" + templateName, true);
    try {
        Workbook workbook = ExcelExportUtil.exportExcel(params, data);
        workbook.write(fileOut);
    } catch (Exception e) {
        LogUtil.error("", e);
    }
}

總結(jié)

網(wǎng)上針對(duì)EasyPOI的介紹多限于最基本的行插入功能,但實(shí)際上Excel模板的需求可能各式各樣。本文只是拋磚引玉,對(duì)EasyPOI中的部分概念做了詳細(xì)介紹,希望幫助大家少踩坑。

如果想詳細(xì)了解EasyPOI的各種功能,參考鏈接中的文檔說(shuō)明及測(cè)試項(xiàng)目源碼就是最好的學(xué)習(xí)資料。希望大家都能得心應(yīng)手地使用EasyPOI,大大提升開(kāi)發(fā)效率!

參考鏈接

EasyPOI官方文檔

  • https://opensource.afterturn.cn/doc/easypoi.html

EasyPOI測(cè)試項(xiàng)目

  • https://gitee.com/lemur/easypoi-test

一些坑

近日有網(wǎng)友求助我解決EasyPOI的復(fù)雜模板配置問(wèn)題,通過(guò)解決該網(wǎng)友的問(wèn)題發(fā)現(xiàn)了EasyPOI中的幾個(gè)坑點(diǎn),補(bǔ)充說(shuō)明幾個(gè)問(wèn)題。

在複雜模板設(shè)計(jì)剖析一節(jié)中已經(jīng)描述了EasyPOI支援的複雜的模板該如何配置。此模板的配置絕對(duì)是正確的,但有3個(gè)點(diǎn)沒(méi)有說(shuō)清楚,大家在照葫蘆畫(huà)瓢時(shí)容易出錯(cuò):

  1. {!fe: list需要在一個(gè)單獨(dú)的列中。 EasyPOI原始碼中是根據(jù)該儲(chǔ)存格的行、列跨距來(lái)決定list中的每個(gè)元素需要多少行的。例如上述圖片中,該儲(chǔ)存格的跨距是5行1列,也就是說(shuō),以後list中的每個(gè)元素都會(huì)佔(zhàn)用5行。如果覺(jué)得該列不符合自訂模板的風(fēng)格,可以把該列的列寬設(shè)為0,但一定需要有{{!fe: list。
  2. 在物件的起始和結(jié)束符號(hào){{}}之間不能有任何空的單元格!程式碼中在解析到該單元格為空時(shí)會(huì)直接拋異常,如果就希望該單元格為空,則得顯示寫(xiě)入空字串:’’’。
  3. 換行符]]必須佔(zhàn)用每行的最後一個(gè)儲(chǔ)存格!比如說(shuō)第一行有10個(gè)單元格,第二行只用了前5個(gè),那麼不能直接在第5個(gè)結(jié)束直接寫(xiě)換行符]],而是需要把6-10個(gè)單元格合併,然後寫(xiě)入]]。參考上述圖片中生產(chǎn)日期所在行的最後一列。這麼設(shè)定的原因是EasyPOI要求每行的單元格數(shù)目完全一致,因?yàn)樵创a中判斷了每個(gè)單元格的列跨度,如果提前使用了]]換行符,那麼該列的數(shù)目就和其他行不同,那麼賦值的時(shí)候就亂掉了,會(huì)出現(xiàn)索引異常。

以上是使用 EasyPOI 優(yōu)雅匯出Excel模板資料(含圖片)的詳細(xì)內(nèi)容。更多資訊請(qǐng)關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

本網(wǎng)站聲明
本文內(nèi)容由網(wǎng)友自願(yuàn)投稿,版權(quán)歸原作者所有。本站不承擔(dān)相應(yīng)的法律責(zé)任。如發(fā)現(xiàn)涉嫌抄襲或侵權(quán)的內(nèi)容,請(qǐng)聯(lián)絡(luò)admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費(fèi)脫衣圖片

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅(qū)動(dòng)的應(yīng)用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線(xiàn)上人工智慧工具。

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費(fèi)的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費(fèi)的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強(qiáng)大的PHP整合開(kāi)發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺(jué)化網(wǎng)頁(yè)開(kāi)發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級(jí)程式碼編輯軟體(SublimeText3)

熱門(mén)話(huà)題

Laravel 教程
1601
29
PHP教程
1502
276