基础准备
velocity模板语法简介
官方实例
版本环境
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.7</version>
</dependency>
标签介绍
<Workbook>
<DocumentProperties></DocumentProperties>
<CustomDocumentProperties></CustomDocumentProperties>
<ExcelWorkbook></ExcelWorkbook>
<Styles></Styles>
<Worksheet></Worksheet>
</Workbook>
workbook
一个workbook对应一个工作薄,下面是常见的约定命名空间。
<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"
xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882">
</Workbook>
DocumentProperties
约定属性配置
<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">
<LastAuthor>16056</LastAuthor>
<Created>2019-07-25T02:16:00Z</Created>
<LastSaved>2019-07-26T02:55:46Z</LastSaved>
</DocumentProperties>
CustomDocumentProperties
自定义属性配置
<CustomDocumentProperties xmlns="urn:schemas-microsoft-com:office:office">
<KSOProductBuildVer dt:dt="string">2052-11.1.0.8894</KSOProductBuildVer>
</CustomDocumentProperties>
ExcelWorkbook
excel相关的属性
<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
<WindowWidth>19200</WindowWidth>
<WindowHeight>7070</WindowHeight>
<ProtectStructure>False</ProtectStructure>
<ProtectWindows>False</ProtectWindows>
</ExcelWorkbook>
Style
<!--
ID:这个样式的唯一值
Name:这个样式的名称
-->
<Style ss:ID="s69" ss:Name="这个样式的名称">
<!-- Horizontal:水平居中 Vertical:垂直居中 WrapText:自动换行 -->
<Alignment ss:Horizontal="Center" ss:Vertical="Center" ss:WrapText="1"/>
<!-- 单元格边框 上下左右(可不全,写什么地方,画什么地方)-->
<Borders>
<!-- Weight:线宽-->
<Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1"/>
<Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1"/>
<Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1"/>
<Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1"/>
</Borders>
<!-- 字体样式
微软雅黑:字体名称
Size:大小
Bold:字体加粗
-->
<Font ss:FontName="微软雅黑" x:CharSet="134" ss:Size="10" ss:Bold="1"/>
<!-- 后续补充 -->
<Interior ss:Color="#FFFFFF" ss:Pattern="Solid"/>
<!-- 后续补充 -->
<NumberFormat ss:Format="[$-F800]dddd\,\ mmmm\ dd\,\ yyyy"/>
<!-- 后续补充 -->
<Protection/>
</Style >
Worksheet
<Worksheet ss:Name="sheetName">
<Table
ss:ExpandedColumnCount="21" ss:ExpandedRowCount="4"
x:FullColumns="1" x:FullRows="1"
ss:DefaultColumnWidth="默认列宽" ss:DefaultRowHeight="默认行高">
<!-- 第几列样式生效 -->
<Column ss:Index="第几列(从1开始)" ss:StyleID="样式id" ss:AutoFitWidth="0" ss:Width="宽度:如84"/>
<Row ss:Height="行高 如:33.75">
<Cell ss:StyleID="样式id" ss:MergeAcross="单元格合并数量(向右)不包括自己">
<Data ss:Type="值类型:如String">值</Data>
</Cell>
<Cell ss:StyleID="s73" ss:MergeDown="单元格合并数量(向下)不包括自己">
<Data ss:Type="值类型:如String">值</Data>
</Cell>
</Row>
</Table>
<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
<PageSetup>
<Header x:Margin="0.3"/>
<Footer x:Margin="0.3"/>
<PageMargins x:Left="0.7" x:Right="0.7" x:Top="0.75" x:Bottom="0.75"/>
</PageSetup>
<Selected/>
<TopRowVisible>0</TopRowVisible>
<LeftColumnVisible>0</LeftColumnVisible>
<PageBreakZoom>100</PageBreakZoom>
<Panes>
<Pane>
<Number>3</Number>
<ActiveRow>12</ActiveRow>
<ActiveCol>13</ActiveCol>
<RangeSelection>R13C14</RangeSelection>
</Pane>
</Panes>
<ProtectObjects>False</ProtectObjects>
<ProtectScenarios>False</ProtectScenarios>
</WorksheetOptions>
</Worksheet>
操作记录
样例模板
首先给出我们要实现的模板。其中啦啦
可以看作是我们常见的标题部分。本次我们的导出模板是向右的。
操作过程
为了能使样式效果生效,我们提前配置如下:
<Table
ss:ExpandedColumnCount="21" ss:ExpandedRowCount="4"
x:FullColumns="1" x:FullRows="1"
<!--暂不做配置-->
ss:DefaultColumnWidth="49.5" ss:DefaultRowHeight="14" >
<!--标题-->
<Column ss:Index="1" ss:Width="60"/>
<!--1级表头-->
<Column ss:Index="2" ss:Width="90"/>
<!--2级表头-->
<Column ss:Index="3" ss:Width="180"/>
</Table>
第一行
Row表示行,cell表示单元格,当前第一行我们处理两个cell(依次向右),其中第一个单元格向下合并四个单元格,所以ss:MergeDown="4"
,第二个单元格需要向右合并一个所以ss:MergeAcross="1"
。
<Row ss:Height="33.75">
<Cell ss:StyleID="s73" ss:MergeDown="4">
<Data ss:Type="String">啦啦</Data>
</Cell>
<Cell ss:StyleID="s72" ss:MergeAcross="1">
<Data ss:Type="String">啦啦啦1</Data>
</Cell>
</Row>
当前效果如下所示:
第二行
由第一行操作过程我们知道单元格默认从第一列开始处理,此时我们的表头哈哈
在第二列,因此我们要指定处理的列ss:Index="2"
,同时指定 ss:MergeDown="1"
向下拓展一个。同理哈哈1
指定ss:Index="3"
<Row ss:Height="33.75" >
<Cell ss:Index="2" ss:StyleID="s71" ss:MergeDown="1" >
<Data ss:Type="String">哈哈</Data>
</Cell>
<Cell ss:Index="3" ss:StyleID="s70" >
<Data ss:Type="String">哈哈1</Data>
</Cell>
</Row>
当前效果如下所示:
如何把哈哈2
放入里面呢?答案是再写一个Row。
<Row ss:Height="33.75">
<Cell ss:Index="3" ss:StyleID="s70">
<Data ss:Type="String">哈哈2</Data>
</Cell>
</Row">
哈哈2
在第3行,此时Row标签数量总数应该为3
。添加完成后效果如下:
同理喜喜也如同第二行操作一样。
常见问题
取值问题
<Cell ss:StyleID="s69">
<Data ss:Type="String">${smokeInfo.result}</Data>
</Cell>
当smokeInfo.result的值为null时,导出的excel值为${smokeInfo.result}
,此时需要在模板进行空值判断。$!{smokeInfo.result}
。
<Cell ss:StyleID="s69">
<Data ss:Type="String">$!{smokeInfo.result}</Data>
</Cell>
线框丢失
我们变量取值时,我们使用了!
进行空值判断后,会出现部分单元格线框丢失的问题,此时我们需要给一个默认值。
#if("$!{smokeInfo.result}" == "")
<Cell ss:StyleID="s69">
<Data ss:Type="String">${nullValue}</Data>
</Cell>
#else
<Cell ss:StyleID="s69">
<Data ss:Type="String">$!{smokeInfo.result}</Data>
</Cell>
#end
其中nullValue来自于我们设置的一个默认值。可以发现是一个空字符串。
paramMap.put("nullValue","");
循环填充
如下图所示,喜喜1
和喜喜2
存在多个值,对于实体属性来说则是一个list
。那么我们该如何填充这个值呢?
<Row ss:Height="33.75">
<Cell ss:Index="2" ss:StyleID="s71" ss:MergeDown="1" >
<Data ss:Type="String">喜喜</Data>
</Cell>
<Cell ss:Index="3" ss:StyleID="s70">
<Data ss:Type="String">喜喜1</Data>
</Cell>
#foreach($device in ${deviceList})
#if(${device.smokeInfos.size()} > 0)
#set($smokeInfoRowCount = (${device.smokeInfos.size()} - 1))
#else
#set($smokeInfoRowCount = 0)
#end
#foreach($smokeInfo in ${device.smokeInfos})
#if("$!{smokeInfo.result}" == "")
<Cell ss:StyleID="s69">
<Data ss:Type="String">${nullValue}</Data>
</Cell>
#else
<Cell ss:StyleID="s69">
<Data ss:Type="String">$!{smokeInfo.result}</Data>
</Cell>
#end
#end
#if($smokeInfoRowCount == 0)
<Cell ss:StyleID="s69">
<Data ss:Type="String">${nullValue}</Data>
</Cell>
#end
#end
</Row>
其中第一个foreach是数据源循环
,第二个foreach是每一条数据中的一个集合属性的遍历。
其他问题
excel无法打开,详见问题原因。
源代码
gitee仓库