本文是通过一步步的还原事件的发生并解决的一个过程记录,如果想知道如何解决的可以直接跳转文章末尾结论部分
提示一下,关注一下
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
属性
text
<?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
,这就是后文要探讨的关键所在
text
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文件内容
text
<?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
属性值。而我们要做的就是修改该值到能容纳我们要导出的数据即可。甚至是可以改为变量读取数据长度是否可行 。
如果感觉有用的话欢迎点赞、收藏、转发