美文网首页
使用Freemarker模版导出xls文件使用excel打开提示

使用Freemarker模版导出xls文件使用excel打开提示

作者: 醉鱼java | 来源:发表于2023-07-31 21:10 被阅读0次

    本文是通过一步步的还原事件的发生并解决的一个过程记录,如果想知道如何解决的可以直接跳转文章末尾结论部分

    提示一下,关注一下 Table 标签中的 ss:ExpandedRowCount 属性

    解决的问题

    在项目中使用freemarker的xml模板导出xls格式的Excel文件时,使用国产Office工具可以打开查看,使用Excel打开提示文件已损坏

    关键词

    国产office,Excel,freemarker

    环境信息

    • Windows 11
    • office 2019
    • 永中office2022体验版
    • JDK8
    • springboot 2.6.13
    • freemarker 2.6.13

    事件还原

    1、首先使用Excel创建一个空白excel文件,输入我们要导出的表格模板,如下图所示,我们创建一个表格,表格中导出姓名、年龄、电话、住址等信息的这样一个表格,并且添加了一行示例数据

    2、点击另存为,选中xml格式导出

    3、打开xml文件,修改添加数据的地方,使用freemarker语法遍历输出数据

    修改前如下图所示

    修改后如下图所示

    其中的#list为固定语法,resultList为获取输入模板数据的key,该值是一个Listas itemList*中的每一个对象以item来遍历

    item.name为获取姓名,item.age为获取年龄,item.phont为获取电话,item.address为获取住址

    ${item.name!''}的完整意思就是输出用户名,为空时输出为空

    4、创建springboot程序,并在resources下创建freemarker目录,继续创建test.xml模板文件,test.xml文件内容就是上一步我们修改完成之后的xml文件,结构如下

    文件内容如下(本内容为Excel打开异常的,如需正常的,需跳转文章末尾

    提示一下,关注一下 Table 标签中的 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、编写导出excel文件的代码,都是测试数据,看看就好,只是举个例子

    需要关注的点是,我们此处导出的用户数据为100,而上文中提示需要关注的参数ss:ExpandedRowCount参数值为2,这就是后文要探讨的关键所在

    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导出excel.xls", "UTF-8"));
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream));
            template.process(map,bw);
            bw.flush();
            bw.close();
            System.out.println("导出成功");
    
        }
    }
    
    

    6、下面执行接口http://localhost:8080/excel/export导出xls文件进行查看文件内容,我们的预期就是国产Office可以打开观看,而Excel打开时提示文件已损坏。打开结果就不进行展示了,感兴趣的可以使用上面的代码进行一下测试

    7、下面我们修改ss:ExpandedRowCount="2"ss:ExpandedRowCount="9999",这样就可以容纳我们的100条记录。此时重启程序进行导出我们就可以发现不管是使用Excel查看还是国产Office查看都可以进行正常的显示了

    8、下面是修改之后的完整的xml文件内容

    <?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>
    
    

    总结

    通过这次实验可以得知,文件的打开失败的根本原因就是数据行超过了设置的ExpandedRowCount属性值。而我们要做的就是修改该值到能容纳我们要导出的数据即可。甚至是可以改为变量读取数据长度是否可行 。

    如果感觉有用的话欢迎点赞、收藏、转发,号《醉鱼Java》

    相关文章

      网友评论

          本文标题:使用Freemarker模版导出xls文件使用excel打开提示

          本文链接:https://www.haomeiwen.com/subject/eqfypdtx.html