使用freemarker 模板生成Excel和Word文件

使用freemarker 模板生成文件Excel和Word文件
freemarker的常用语法
1. 引入依赖的包

pom.xml文件


<dependency><groupId>org.freemarkergroupId><artifactId>freemarkerartifactId><version>2.3.30version>
dependency>
2. Freemarker配置

FreemarkerUtil.java

package com.jeesite.modules.jss.Utils;import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Map;public class FreemarkerUtil {public Template getTemplate(String name) {try {这里是对应的你使用jar包的版本号:2.3.30Configuration configuration = new Configuration(Configuration.VERSION_2_3_30);// 空值时不显示configuration.setClassicCompatible(true);//第二个参数 为你对应存放.ftl文件的包名  (template在resource文件夹下)configuration.setClassForTemplateLoading(this.getClass(), "/template");Template template = configuration.getTemplate(name);return template;} catch (IOException e) {e.printStackTrace();}return null;}
}
3. ftl模板文件的生成

在excel/word文件里画好模板,将excel/word文件另存为.xml文件。在template文件夹下新建模板文件,后缀为.ftl,然后将.xml文件的内容复制到模板文件中。
在这里插入图片描述
在这里插入图片描述

循环数据集行的部分,在ftl文件里使用<#list>实现:

excel循环行:

在这里插入图片描述

word循环行:

<#list priceInfo.jssProductList as product><w:tr w:rsidR="003F3BC7" w:rsidRPr="00F12F15" w14:paraId="3C7E34E4" w14:textId="77777777" w:rsidTr="00E74DC5"><w:tc><w:tcPr><w:tcW w:w="1134" w:type="dxa"/>w:tcPr><w:p w14:paraId="0E684322" w14:textId="6CB43827" w:rsidR="003F3BC7" w:rsidRPr="00F12F15" w:rsidRDefault="00FA3CA0" w:rsidP="003F3BC7"><w:pPr><w:jc w:val="left"/><w:rPr><w:sz w:val="18"/><w:lang w:eastAsia="zh-CN"/>w:rPr>w:pPr><w:r><w:rPr><w:rFonts w:ascii="等线" w:eastAsia="等线" w:hAnsi="等线" w:hint="eastAsia"/><w:sz w:val="18"/><w:lang w:eastAsia="zh-CN"/>w:rPr><w:t>${product.itemDesc}w:t>w:r>w:p>w:tc>w:tr>
#list>
金额格式化: ${(product.price?string('0.00'))!'0.00'}
日期格式化: ${contract.wantedDeliveryDate?string('yyyy-MM-dd')}

值为NULL时格式转化会出错,加上 “!", !"后的内容表示数据为null时显示的值

<#list jssOrders.jssProductList as product>
<#list product.jssDeviceList as device>
<#if (device_index == 0)>
<Row ss:AutoFitHeight="0"><Cell ss:MergeDown="${product.jssDeviceList?size-1}" ss:StyleID="m3012774613960"><Data ss:Type="String">${product.itemDesc}Data>Cell><Cell ss:MergeDown="${product.jssDeviceList?size-1}" ss:StyleID="m3012774613980"><Data ss:Type="String">${product.model}Data>Cell><Cell ss:MergeDown="${product.jssDeviceList?size-1}" ss:StyleID="m3012774614020"><Data ss:Type="String">${product.qty}Data>Cell><Cell ss:StyleID="s75"><Data ss:Type="String">${device.deviceNo}Data>Cell><Cell ss:StyleID="s76"><Data ss:Type="String">${device.remark2}Data>Cell>
Row>
#if>
<#if (device_index > 0)>
<Row ss:AutoFitHeight="0"><Cell ss:Index="4" ss:StyleID="s75"><Data ss:Type="String">${device.deviceNo}Data>Cell><Cell ss:StyleID="s76"><Data ss:Type="String">${device.remark2}Data>Cell>
Row>
#if>
#list>
#list>

语法:

<#list itemList as item>

集合长度:${itemList?size}

循环时的下标:item_index

合并单元格:ss:MergeDown="${product.jssDeviceList?size-1}"

4.页面 .html

连续发送多个文件下载请求时,先发起的请求会被自动取消掉,只能成功下载最后一个请求的文件。所以创建多个临时iframe进行请求。

// 打印按钮按下事件
$("#btnPrint").click(function(){$("#dataGrid input:checkbox:checked").each(function(){var id = $(this).attr("id").substr(13);var iframe = document.createElement("iframe");iframe.style.display = "none";iframe.style.height = 0;iframe.src = "${ctx}/jss/jssContract/exportData?id=" + id;document.body.appendChild(iframe);// 5分钟之后删除setTimeout(()=>{iframe.remove();}, 5 * 60 * 1000);});
});
5.Controller
/*** 导出数据到Excel/Word文件* @param request* @param response* @return* @throws IOException*/@RequestMapping(value = "exportData")public void exportData(String id , HttpServletRequest request, HttpServletResponse response) throws IOException, TemplateException{//获取数据JssContract jssContract = jssContractService.getExportData(id);Map<String,Object> root = new HashMap<String,Object>();root.put("contract", jssContract);// Excelresponse.setHeader("content-Type", "application/msexcel");// word// response.setHeader("content-Type", "application/msword");// 下载文件的默认名称 (word时后缀名改为.doc)response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("合同_" + jssContract.getContractNo() + ".xls", "UTF-8"));FreemarkerUtil freemarkerUtil = new FreemarkerUtil();// 配置的template文件夹下Template template = freemarkerUtil.getTemplate("jssContractTemplate.ftl");template.process(root,new OutputStreamWriter(response.getOutputStream()));}
关于freemarker的语法
1.空值处理的方法

默认情况下,freemarker的变量必须有值,如果没有被赋值的变量在页面上使用就会抛出异常,出错的信息都会显示在页面上。
解决办法:

方法一、我们可以在页面上使用freemarker变量时 以 ${xxx?if_exists} 来处理空值的情况,或采用默认值的方法避免此类问题。但每个freemarker变量都这样处理确实比较让人心烦,请看以下方法。

方法二、在类路径下 加入 freemarker.properties 文件,里面配置 classic_compatible=true。

方法三、通过freemarker.template.Configuration的 config.setClassicCompatible(true);

(通过源码我们看到,其实)方法二、方法三是思想是一致的,只是实现方法不同而已。如果应用中已经存在了 freemarker.properties 并配置了其他的属性,可以在这里配置,否则推荐使用方法三.)

方法四、在ftl文件内引入 。

总结:方法四是需要在每个需要这样处理的页面都要引入的,比较麻烦,、还是选择使用 方法二、方法三好了。但是方法二、方法三也不是万能的。例如我在action中定义一个MyBean类的对象为 myBean,MyBean中有Comp属性。在页面上就要 用如下语句使用: m y B e a n . c o m p , 这 里 m y B e a n 可 能 为 n u l l , c o m p 也 可 能 为 n u l l 。 这 时 候 就 要 使 用 方 法 一 了 , {myBean.comp},这里myBean可能为null,comp也可能为null。这时候 就要使用方法一了, myBean.compmyBeannullcompnull使{(myBean.comp)!} 或 ${(myBean.comp)?if_exists}。

2.部分语法
${book.name?if_exists } //用于判断如果存在,就输出这个值 
${book.name?default(‘xxx’)}//默认值xxx 
${book.name!"xxx"}//默认值xxx 
${book.date?string('yyyy-MM-dd')} //日期格式 
${book?string.number} 20 //三种不同的数字格式 
${book?string.currency}--<#-- $20.00 --> 
${book?string.percent}—<#-- 20% --><#assign foo=ture /> //声明变量,插入布尔值进行显示 
${foo?string("yes","no")} <#-- yes -->

大小比较符号使用需要注意:(xml的原因),可以用于比较数字和日期
使用lt、lte、gt和gte来替代<、<=、>和>= 也可以使用括号<#if (x>y)>

1.逻辑判断: if else
<#if condition>... 
<#elseif condition2>... 
<#elseif condition3>...... 
<#else>... 

空值判断:<#if book.name?? >

  1. switch
<#switch value> 
<#case refValue1> 
... 
<#break> 
<#case refValue2> 
... 
<#break> 
<#default> 
... 
#switch>
3:循环读取集合: 注意/的使用
<#list student as stu> 
${stu}<br/>
#list> 

item_index:当前变量的索引值
item_has_next:是否存在下一个对象 其中item名称为as后的变量名,如stu

集合长度判断
<#if student?size != 0> 判断=的时候,注意只要一个=符号,而不是==

4.比较运算符
  1. =或者==:判断两个值是否相等.
  2. !=:判断两个值是否不等.
  3. >或者gt:判断左边值是否大于右边值
  4. >=或者gte:判断左边值是否大于等于右边值
  5. <或者lt:判断左边值是否小于右边值
  6. <=或者lte:判断左边值是否小于等于右边值

5.ftl文本中的空格会被忽略掉,且使用 不能解析,可使用阿斯克码表示空格  

6.多条件关联 且:&& 或:||


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部