本文是通过一步步的还原事件的发生并解决的一个过程记录,如果想知道如何解决的可以直接跳转文章末尾结论部分
提示一下,关注一下
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,该值是一个List,as item
是*List**中的每一个对象以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》获取一手面试资料,一起学编程