最近一直在做导出功能,公司的页面太复杂,每个word页面的字段都有上百个,还要写近十个页面的导出,表示真心伤不起。技术也由刚开始的磕磕碰碰,到现在的熟练。
之前也曾做过导出功能(导出试卷),当时采用的是poi,直接输出试题,页面比较简单。这一次因为需要导出的word除了基本的文字信息外,还包含图片,复选框,表格循环显示等。选择了使用freemarker进行导出,百度到的都是先写好word,然后另存为xml,再将扩展名更改为ftl。然后通过Java代码填充数据,最终输出word。但遇到的问题是,我使用word-->xml-->ftl,得到的ftl模板在有的位置无法识别freemarker的一些标记,在无意之中发现通过word-->html--->ftl,也可以成功导出Word。
先写好所需要导出的word的模板,调整word的样式。将word另存为html页面,再更改扩展名为ftl。
编写后台的代码,部分代码如下。
public String createWord(){ Map<String, Object> dataMap = new HashMap<String, Object>(); // word中需要展示的动态数据,用map集合来保存 dataMap.put("test", test); WordUtil.createWord(dataMap, "test.ftl", filePath, fileOnlyName); return "createWordSuccess"; } public String dowloadWord() { /** 先判断文件是否已生成 */ try { //解决中文乱码 filePath = URLDecoder.decode(filePath, "UTF-8"); fileOnlyName = URLDecoder.decode(fileOnlyName, "UTF-8"); fileName = URLDecoder.decode(fileName, "UTF-8"); //如果文件不存在,则会跳入异常,然后可以进行异常处理 new FileInputStream(filePath + File.separator + fileOnlyName); } catch (Exception e) { e.printStackTrace(); return "error"; } return "dowloadWord"; } public InputStream getWordFile(){ try { //解决中文乱码 filePath = URLDecoder.decode(filePath, "UTF-8"); fileOnlyName = URLDecoder.decode(fileOnlyName, "UTF-8"); fileName = URLDecoder.decode(fileName, "UTF-8"); /** 返回最终生成的word文件流 */ return new FileInputStream(filePath + File.separator + fileOnlyName); } catch (Exception e) { e.printStackTrace(); return null; } }
WordUtil工具类代码实现如下:
import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.util.Map; import sun.misc.BASE64Encoder; import freemarker.template.Configuration; import freemarker.template.Template; public class WordUtil { public static String getImageStr(String imgFile) { //String imgFile = "d:/aa.jpg"; InputStream in = null; byte[] data = null; try { in = new FileInputStream(imgFile); data = new byte[in.available()]; in.read(data); in.close(); } catch (Exception e) { e.printStackTrace(); } BASE64Encoder encoder = new BASE64Encoder(); return encoder.encode(data); } @SuppressWarnings("unchecked") public static void createWord(Map dataMap,String templateName,String filePath,String fileName){ try { //创建配置实例 Configuration configuration = new Configuration(); //设置编码 configuration.setDefaultEncoding("UTF-8"); //ftl模板文件统一放至com.fbty.coast.template 包下面 configuration.setClassForTemplateLoading(WordUtil.class,"/com/template/"); //获取模板 Template template = configuration.getTemplate(templateName); //输出文件 File outFile = new File(filePath+File.separator+fileName); //如果输出目标文件夹不存在,则创建 if (!outFile.getParentFile().exists()){ outFile.getParentFile().mkdirs(); } //将模板和数据模型合并生成文件 Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile),"UTF-8")); //生成文件 template.process(dataMap, out); //关闭流 out.flush(); out.close(); } catch (Exception e) { e.printStackTrace(); } } }
对于填充的文本数据,在ftl模板中使用${text}获取,或者${text?default('')}。
实现复选框选中:
<#list ['强 ','中','弱'] as crack_dzpzx_list> <input type="checkbox" style="vertical-align:middle;" <#if crack_dzpzx?exists> <#list crack_dzpzx as crack_dzpzx_x> <#if crack_dzpzx_x==crack_dzpzx_list> checked="checked" </#if> </#list> </#if>> ${crack_dzpzx_list?default('')} </#list>