使用Freemarker模版導(dǎo)出xls文件使用excel打開提示文件損壞

本文是通過一步步的還原事件的發(fā)生并解決的一個(gè)過程記錄驻呐,如果想知道如何解決的可以直接跳轉(zhuǎn)文章末尾結(jié)論部分

提示一下打洼,關(guān)注一下 Table 標(biāo)簽中的 ss:ExpandedRowCount 屬性

解決的問題

在項(xiàng)目中使用freemarker的xml模板導(dǎo)出xls格式的Excel文件時(shí),使用國產(chǎn)Office工具可以打開查看蛉威,使用Excel打開提示文件已損壞

關(guān)鍵詞

國產(chǎn)office,Excel,freemarker

環(huán)境信息

  • Windows 11
  • office 2019
  • 永中office2022體驗(yàn)版
  • JDK8
  • springboot 2.6.13
  • freemarker 2.6.13

事件還原

1妻怎、首先使用Excel創(chuàng)建一個(gè)空白excel文件,輸入我們要導(dǎo)出的表格模板泞歉,如下圖所示逼侦,我們創(chuàng)建一個(gè)表格,表格中導(dǎo)出姓名腰耙、年齡榛丢、電話、住址等信息的這樣一個(gè)表格挺庞,并且添加了一行示例數(shù)據(jù)

2晰赞、點(diǎn)擊另存為,選中xml格式導(dǎo)出

3选侨、打開xml文件掖鱼,修改添加數(shù)據(jù)的地方,使用freemarker語法遍歷輸出數(shù)據(jù)

修改前如下圖所示

修改后如下圖所示

其中的#list為固定語法援制,resultList為獲取輸入模板數(shù)據(jù)的key戏挡,該值是一個(gè)Listas itemList*中的每一個(gè)對象以item來遍歷

item.name為獲取姓名隘谣,item.age為獲取年齡增拥,item.phont為獲取電話啄巧,item.address為獲取住址

${item.name!''}的完整意思就是輸出用戶名,為空時(shí)輸出為空

4掌栅、創(chuàng)建springboot程序秩仆,并在resources下創(chuàng)建freemarker目錄,繼續(xù)創(chuàng)建test.xml模板文件猾封,test.xml文件內(nèi)容就是上一步我們修改完成之后的xml文件澄耍,結(jié)構(gòu)如下

文件內(nèi)容如下(本內(nèi)容為Excel打開異常的,如需正常的晌缘,需跳轉(zhuǎn)文章末尾

提示一下齐莲,關(guān)注一下 Table 標(biāo)簽中的 ss:ExpandedRowCount 屬性

<?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
          xmlns:o="urn:schemas-microsoft-com:office:office"
          xmlns:x="urn:schemas-microsoft-com:office:excel"
          xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
          xmlns:html="http://www.w3.org/TR/REC-html40">
    <DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">
        <Author>zuiyu</Author>
        <LastAuthor>zuiyu</LastAuthor>
        <Created>2023-07-26T02:16:31Z</Created>
        <LastSaved>2023-07-26T02:18:00Z</LastSaved>
        <Version>16.00</Version>
    </DocumentProperties>
    <OfficeDocumentSettings xmlns="urn:schemas-microsoft-com:office:office">
        <AllowPNG/>
    </OfficeDocumentSettings>
    <ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
        <WindowHeight>5880</WindowHeight>
        <WindowWidth>14400</WindowWidth>
        <WindowTopX>32767</WindowTopX>
        <WindowTopY>32767</WindowTopY>
        <ProtectStructure>False</ProtectStructure>
        <ProtectWindows>False</ProtectWindows>
    </ExcelWorkbook>
    <Styles>
        <Style ss:ID="Default" ss:Name="Normal">
            <Alignment ss:Vertical="Center"/>
            <Borders/>
            <Font ss:FontName="等線" x:CharSet="134" ss:Size="11" ss:Color="#000000"/>
            <Interior/>
            <NumberFormat/>
            <Protection/>
        </Style>
    </Styles>
    <Worksheet ss:Name="Sheet1">
        <Table ss:ExpandedColumnCount="4" ss:ExpandedRowCount="2" x:FullColumns="1"
               x:FullRows="1" ss:DefaultColumnWidth="51" ss:DefaultRowHeight="13.875">
            <Row>
                <Cell><Data ss:Type="String">姓名</Data></Cell>
                <Cell><Data ss:Type="String">年齡</Data></Cell>
                <Cell><Data ss:Type="String">電話</Data></Cell>
                <Cell><Data ss:Type="String">住址</Data></Cell>
            </Row>
            <#list resultList as item>
            <Row>
                <Cell><Data ss:Type="String">${item.name!''}</Data></Cell>
                <Cell><Data ss:Type="Number">${item.age!''}</Data></Cell>
                <Cell><Data ss:Type="Number">${item.phone!''}</Data></Cell>
                <Cell><Data ss:Type="String">${item.address!''}</Data></Cell>
            </Row>
        </#list>
    </Table>
    <WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
        <PageSetup>
            <Header x:Margin="0.3"/>
            <Footer x:Margin="0.3"/>
            <PageMargins x:Bottom="0.75" x:Left="0.7" x:Right="0.7" x:Top="0.75"/>
        </PageSetup>
        <Selected/>
        <Panes>
            <Pane>
                <Number>3</Number>
                <ActiveRow>4</ActiveRow>
                <ActiveCol>5</ActiveCol>
            </Pane>
        </Panes>
        <ProtectObjects>False</ProtectObjects>
        <ProtectScenarios>False</ProtectScenarios>
    </WorksheetOptions>
</Worksheet>
        </Workbook>

5、編寫導(dǎo)出excel文件的代碼磷箕,都是測試數(shù)據(jù)选酗,看看就好,只是舉個(gè)例子

需要關(guān)注的點(diǎn)是岳枷,我們此處導(dǎo)出的用戶數(shù)據(jù)為100芒填,而上文中提示需要關(guān)注的參數(shù)ss:ExpandedRowCount參數(shù)值為2,這就是后文要探討的關(guān)鍵所在

package com.example.exceldemo.demos.excel;

import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.URLEncoder;
import java.util.*;

/**
 * @Author zuiyu
 * @Date 2023/7/26 10:26
 */
@RestController
@RequestMapping("/excel")
public class ExcelController {
    @GetMapping("/export")
    public void export(HttpServletResponse response) throws IOException, TemplateException {
        Configuration configuration = new Configuration(Configuration.VERSION_2_3_26);
        configuration.setDefaultEncoding("utf-8");
        configuration.setClassForTemplateLoading(getClass(),"/freemarker");
        Template template = configuration.getTemplate("test.xml");
        List<Person> list = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            Person person1 = new Person();
            person1.setName("測試用戶名:"+i);
            person1.setAge((i+1)*2);
            person1.setPhone(new Random().nextInt(100));
            person1.setAddress("地址:"+i);
            list.add(person1);
        }

        Map<String,Object> map = new HashMap<>();
        map.put("resultList",list);
        ServletOutputStream outputStream = response.getOutputStream();
        response.setContentType("application/octet-stream");
        response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("測試xml導(dǎo)出excel.xls", "UTF-8"));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream));
        template.process(map,bw);
        bw.flush();
        bw.close();
        System.out.println("導(dǎo)出成功");

    }
}

6空繁、下面執(zhí)行接口http://localhost:8080/excel/export導(dǎo)出xls文件進(jìn)行查看文件內(nèi)容殿衰,我們的預(yù)期就是國產(chǎn)Office可以打開觀看,而Excel打開時(shí)提示文件已損壞盛泡。打開結(jié)果就不進(jìn)行展示了闷祥,感興趣的可以使用上面的代碼進(jìn)行一下測試

7、下面我們修改ss:ExpandedRowCount="2"ss:ExpandedRowCount="9999"傲诵,這樣就可以容納我們的100條記錄凯砍。此時(shí)重啟程序進(jìn)行導(dǎo)出我們就可以發(fā)現(xiàn)不管是使用Excel查看還是國產(chǎn)Office查看都可以進(jìn)行正常的顯示了

8、下面是修改之后的完整的xml文件內(nèi)容

<?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
          xmlns:o="urn:schemas-microsoft-com:office:office"
          xmlns:x="urn:schemas-microsoft-com:office:excel"
          xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
          xmlns:html="http://www.w3.org/TR/REC-html40">
    <DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">
        <Author>zuiyu</Author>
        <LastAuthor>zuiyu</LastAuthor>
        <Created>2023-07-26T02:16:31Z</Created>
        <LastSaved>2023-07-26T02:18:00Z</LastSaved>
        <Version>16.00</Version>
    </DocumentProperties>
    <OfficeDocumentSettings xmlns="urn:schemas-microsoft-com:office:office">
        <AllowPNG/>
    </OfficeDocumentSettings>
    <ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
        <WindowHeight>5880</WindowHeight>
        <WindowWidth>14400</WindowWidth>
        <WindowTopX>32767</WindowTopX>
        <WindowTopY>32767</WindowTopY>
        <ProtectStructure>False</ProtectStructure>
        <ProtectWindows>False</ProtectWindows>
    </ExcelWorkbook>
    <Styles>
        <Style ss:ID="Default" ss:Name="Normal">
            <Alignment ss:Vertical="Center"/>
            <Borders/>
            <Font ss:FontName="等線" x:CharSet="134" ss:Size="11" ss:Color="#000000"/>
            <Interior/>
            <NumberFormat/>
            <Protection/>
        </Style>
    </Styles>
    <Worksheet ss:Name="Sheet1">
        <Table ss:ExpandedColumnCount="4" ss:ExpandedRowCount="9999" x:FullColumns="1"
               x:FullRows="1" ss:DefaultColumnWidth="51" ss:DefaultRowHeight="13.875">
            <Row>
                <Cell><Data ss:Type="String">姓名</Data></Cell>
                <Cell><Data ss:Type="String">年齡</Data></Cell>
                <Cell><Data ss:Type="String">電話</Data></Cell>
                <Cell><Data ss:Type="String">住址</Data></Cell>
            </Row>
            <#list resultList as item>
            <Row>
                <Cell><Data ss:Type="String">${item.name!''}</Data></Cell>
                <Cell><Data ss:Type="Number">${item.age!''}</Data></Cell>
                <Cell><Data ss:Type="Number">${item.phone!''}</Data></Cell>
                <Cell><Data ss:Type="String">${item.address!''}</Data></Cell>
            </Row>
        </#list>
    </Table>
    <WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
        <PageSetup>
            <Header x:Margin="0.3"/>
            <Footer x:Margin="0.3"/>
            <PageMargins x:Bottom="0.75" x:Left="0.7" x:Right="0.7" x:Top="0.75"/>
        </PageSetup>
        <Selected/>
        <Panes>
            <Pane>
                <Number>3</Number>
                <ActiveRow>4</ActiveRow>
                <ActiveCol>5</ActiveCol>
            </Pane>
        </Panes>
        <ProtectObjects>False</ProtectObjects>
        <ProtectScenarios>False</ProtectScenarios>
    </WorksheetOptions>
</Worksheet>
        </Workbook>

總結(jié)

通過這次實(shí)驗(yàn)可以得知掰吕,文件的打開失敗的根本原因就是數(shù)據(jù)行超過了設(shè)置的ExpandedRowCount屬性值果覆。而我們要做的就是修改該值到能容納我們要導(dǎo)出的數(shù)據(jù)即可。甚至是可以改為變量讀取數(shù)據(jù)長度是否可行 殖熟。

如果感覺有用的話歡迎點(diǎn)贊局待、收藏、轉(zhuǎn)發(fā)菱属,號(hào)《醉魚Java》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末钳榨,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子纽门,更是在濱河造成了極大的恐慌薛耻,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,589評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赏陵,死亡現(xiàn)場離奇詭異饼齿,居然都是意外死亡饲漾,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門缕溉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來考传,“玉大人,你說我怎么就攤上這事证鸥×爬悖” “怎么了?”我有些...
    開封第一講書人閱讀 165,933評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵枉层,是天一觀的道長泉褐。 經(jīng)常有香客問我,道長鸟蜡,這世上最難降的妖魔是什么膜赃? 我笑而不...
    開封第一講書人閱讀 58,976評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮矩欠,結(jié)果婚禮上财剖,老公的妹妹穿的比我還像新娘悠夯。我一直安慰自己癌淮,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評(píng)論 6 393
  • 文/花漫 我一把揭開白布沦补。 她就那樣靜靜地躺著乳蓄,像睡著了一般。 火紅的嫁衣襯著肌膚如雪夕膀。 梳的紋絲不亂的頭發(fā)上虚倒,一...
    開封第一講書人閱讀 51,775評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音产舞,去河邊找鬼魂奥。 笑死,一個(gè)胖子當(dāng)著我的面吹牛易猫,可吹牛的內(nèi)容都是我干的耻煤。 我是一名探鬼主播,決...
    沈念sama閱讀 40,474評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼准颓,長吁一口氣:“原來是場噩夢啊……” “哼哈蝇!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起攘已,我...
    開封第一講書人閱讀 39,359評(píng)論 0 276
  • 序言:老撾萬榮一對情侶失蹤炮赦,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后样勃,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體吠勘,經(jīng)...
    沈念sama閱讀 45,854評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡性芬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了剧防。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片雹嗦。...
    茶點(diǎn)故事閱讀 40,146評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖浩习,靈堂內(nèi)的尸體忽然破棺而出冻记,到底是詐尸還是另有隱情,我是刑警寧澤棚唆,帶...
    沈念sama閱讀 35,826評(píng)論 5 346
  • 正文 年R本政府宣布暇赤,位于F島的核電站,受9級(jí)特大地震影響宵凌,放射性物質(zhì)發(fā)生泄漏鞋囊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評(píng)論 3 331
  • 文/蒙蒙 一瞎惫、第九天 我趴在偏房一處隱蔽的房頂上張望溜腐。 院中可真熱鬧,春花似錦瓜喇、人聲如沸挺益。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽望众。三九已至,卻和暖如春伞辛,著一層夾襖步出監(jiān)牢的瞬間烂翰,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評(píng)論 1 272
  • 我被黑心中介騙來泰國打工蚤氏, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留甘耿,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,420評(píng)論 3 373
  • 正文 我出身青樓竿滨,卻偏偏與公主長得像佳恬,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子姐呐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評(píng)論 2 356

推薦閱讀更多精彩內(nèi)容