freemarker导出docx文档(纯文本,使用浏览器输出)
制作模板及代码参考:https://blog.csdn.net/u014231523/article/details/88933319
https://blog.csdn.net/action5362603/article/details/84546012
新建符合需要的docx文档,后缀名改为zip,解压之后使用占位符更改word文件夹下的document.xml文件中对应内容,参考如下:
<#list titleList as title>
</#list>
为集合循环取值
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <w:document xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" xmlns:wpsCustomData="http://www.wps.cn/officeDocument/2013/wpsCustomData" mc:Ignorable="w14 w15 wp14"> <w:body> <w:p> <w:pPr><w:keepLines w:val="0"/><w:spacing w:after="400"/><w:ind w:firstLine="160"/><w:jc w:val="center"/></w:pPr><w:r><w:rPr><w:b/><w:sz w:val="32"/></w:rPr><w:t>${theme}</w:t></w:r> </w:p> <w:p><w:pPr><w:rPr><w:b w:val="0"/><w:color w:val="0066FF"/><w:sz w:val="24"/></w:rPr></w:pPr></w:p> <#list titleList as title> <w:p><w:pPr><w:rPr><w:b/><w:sz w:val="32"/></w:rPr></w:pPr> <w:r><w:rPr><w:rFonts w:hint="eastAsia" w:eastAsia="宋体"/><w:b w:val="0"/><w:color w:val="000000"/><w:sz w:val="24"/><w:lang w:val="en-US" w:eastAsia="zh-CN"/></w:rPr><w:t>${title.content}</w:t></w:r><w:r><w:rPr><w:b w:val="0"/><w:color w:val="000000"/><w:sz w:val="24"/></w:rPr><w:t xml:space="preserve"> </w:t></w:r><w:r><w:rPr><w:b w:val="0"/><w:color w:val="0066FF"/><w:sz w:val="24"/></w:rPr><w:t>[单选题]</w:t></w:r></w:p><w:p><w:pPr><w:rPr><w:b w:val="0"/><w:color w:val="0066FF"/><w:sz w:val="24"/></w:rPr></w:pPr></w:p> <w:tbl> <w:tblPr><w:tblStyle w:val="2"/><w:tblW w:w="3868" w:type="pct"/><w:tblInd w:w="0" w:type="dxa"/><w:tblBorders><w:top w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/><w:left w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/><w:bottom w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/><w:right w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/><w:insideH w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/><w:insideV w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/></w:tblBorders><w:tblLayout w:type="autofit"/><w:tblCellMar><w:top w:w="0" w:type="dxa"/><w:left w:w="108" w:type="dxa"/><w:bottom w:w="0" w:type="dxa"/><w:right w:w="108" w:type="dxa"/></w:tblCellMar></w:tblPr><w:tblGrid><w:gridCol w:w="3507"/><w:gridCol w:w="3086"/></w:tblGrid> <w:tr> <w:tblPrEx><w:tblBorders><w:top w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/><w:left w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/><w:bottom w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/><w:right w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/><w:insideH w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/><w:insideV w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/></w:tblBorders><w:tblCellMar><w:top w:w="0" w:type="dxa"/><w:left w:w="108" w:type="dxa"/><w:bottom w:w="0" w:type="dxa"/><w:right w:w="108" w:type="dxa"/></w:tblCellMar></w:tblPrEx><w:trPr><w:trHeight w:val="500" w:hRule="atLeast"/></w:trPr><w:tc><w:tcPr><w:shd w:val="clear" w:color="auto" w:fill="E0E0E0"/><w:vAlign w:val="center"/></w:tcPr><w:p><w:pPr><w:jc w:val="center"/></w:pPr><w:r><w:t>选项</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:shd w:val="clear" w:color="auto" w:fill="E0E0E0"/><w:vAlign w:val="center"/></w:tcPr><w:p><w:pPr><w:jc w:val="center"/></w:pPr><w:r><w:t>比例</w:t></w:r></w:p></w:tc> </w:tr> <w:tr> <w:tblPrEx><w:tblBorders><w:top w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/><w:left w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/><w:bottom w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/><w:right w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/><w:insideH w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/><w:insideV w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/></w:tblBorders><w:tblCellMar><w:top w:w="0" w:type="dxa"/><w:left w:w="108" w:type="dxa"/><w:bottom w:w="0" w:type="dxa"/><w:right w:w="108" w:type="dxa"/></w:tblCellMar></w:tblPrEx><w:trPr><w:trHeight w:val="500" w:hRule="atLeast"/></w:trPr> <w:tc><w:tcPr><w:shd w:val="clear" w:color="auto" w:fill="FFFFFF"/><w:vAlign w:val="center"/></w:tcPr><w:p><w:pPr><w:jc w:val="left"/><w:rPr><w:rFonts w:hint="default" w:eastAsia="宋体"/><w:lang w:val="en-US" w:eastAsia="zh-CN"/></w:rPr></w:pPr><w:r><w:rPr><w:rFonts w:hint="eastAsia" w:eastAsia="宋体"/><w:lang w:val="en-US" w:eastAsia="zh-CN"/></w:rPr><w:t>${title.optionsA}</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:shd w:val="clear" w:color="auto" w:fill="FFFFFF"/><w:vAlign w:val="center"/></w:tcPr><w:p><w:pPr><w:jc w:val="center"/><w:rPr><w:rFonts w:hint="default" w:eastAsia="宋体"/><w:lang w:val="en-US" w:eastAsia="zh-CN"/></w:rPr></w:pPr><w:r><w:rPr><w:rFonts w:hint="eastAsia" w:eastAsia="宋体"/><w:lang w:val="en-US" w:eastAsia="zh-CN"/></w:rPr><w:t>${title.countA}</w:t></w:r></w:p></w:tc> </w:tr> <w:tr> <w:tblPrEx><w:tblBorders><w:top w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/><w:left w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/><w:bottom w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/><w:right w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/><w:insideH w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/><w:insideV w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/></w:tblBorders><w:tblCellMar><w:top w:w="0" w:type="dxa"/><w:left w:w="108" w:type="dxa"/><w:bottom w:w="0" w:type="dxa"/><w:right w:w="108" w:type="dxa"/></w:tblCellMar></w:tblPrEx><w:trPr><w:trHeight w:val="500" w:hRule="atLeast"/></w:trPr><w:tc><w:tcPr><w:shd w:val="clear" w:color="auto" w:fill="F9F9F9"/><w:vAlign w:val="center"/></w:tcPr><w:p><w:pPr><w:jc w:val="left"/></w:pPr><w:r><w:rPr><w:rFonts w:hint="eastAsia" w:eastAsia="宋体"/><w:lang w:val="en-US" w:eastAsia="zh-CN"/></w:rPr><w:t>${title.optionsB}</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:shd w:val="clear" w:color="auto" w:fill="F9F9F9"/><w:vAlign w:val="center"/></w:tcPr><w:p><w:pPr><w:jc w:val="center"/><w:rPr><w:rFonts w:hint="default" w:eastAsia="宋体"/><w:lang w:val="en-US" w:eastAsia="zh-CN"/></w:rPr></w:pPr><w:r><w:rPr><w:rFonts w:hint="eastAsia" w:eastAsia="宋体"/><w:lang w:val="en-US" w:eastAsia="zh-CN"/></w:rPr><w:t>${title.countB}</w:t></w:r></w:p></w:tc> </w:tr> <w:tr> <w:tblPrEx><w:tblBorders><w:top w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/><w:left w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/><w:bottom w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/><w:right w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/><w:insideH w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/><w:insideV w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/></w:tblBorders><w:tblCellMar><w:top w:w="0" w:type="dxa"/><w:left w:w="108" w:type="dxa"/><w:bottom w:w="0" w:type="dxa"/><w:right w:w="108" w:type="dxa"/></w:tblCellMar></w:tblPrEx><w:trPr><w:trHeight w:val="500" w:hRule="atLeast"/></w:trPr><w:tc><w:tcPr><w:shd w:val="clear" w:color="auto" w:fill="FFFFFF"/><w:vAlign w:val="center"/></w:tcPr><w:p><w:pPr><w:jc w:val="left"/></w:pPr><w:r><w:rPr><w:rFonts w:hint="eastAsia" w:eastAsia="宋体"/><w:lang w:val="en-US" w:eastAsia="zh-CN"/></w:rPr><w:t>${title.optionsC}</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:shd w:val="clear" w:color="auto" w:fill="FFFFFF"/><w:vAlign w:val="center"/></w:tcPr><w:p><w:pPr><w:jc w:val="center"/></w:pPr><w:r><w:rPr><w:rFonts w:hint="eastAsia" w:eastAsia="宋体"/><w:lang w:val="en-US" w:eastAsia="zh-CN"/></w:rPr><w:t>${title.countC}</w:t></w:r></w:p></w:tc> </w:tr> <w:tr> <w:tblPrEx><w:tblBorders><w:top w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/><w:left w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/><w:bottom w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/><w:right w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/><w:insideH w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/><w:insideV w:val="single" w:color="D7D7D7" w:sz="4" w:space="0"/></w:tblBorders><w:tblCellMar><w:top w:w="0" w:type="dxa"/><w:left w:w="108" w:type="dxa"/><w:bottom w:w="0" w:type="dxa"/><w:right w:w="108" w:type="dxa"/></w:tblCellMar></w:tblPrEx><w:trPr><w:trHeight w:val="500" w:hRule="atLeast"/></w:trPr><w:tc><w:tcPr><w:shd w:val="clear" w:color="auto" w:fill="E0E0E0"/><w:vAlign w:val="center"/></w:tcPr><w:p><w:pPr><w:jc w:val="left"/></w:pPr><w:r><w:rPr><w:rFonts w:hint="eastAsia" w:eastAsia="宋体"/><w:lang w:val="en-US" w:eastAsia="zh-CN"/></w:rPr><w:t>${title.optionsD}</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:shd w:val="clear" w:color="auto" w:fill="E0E0E0"/><w:vAlign w:val="center"/></w:tcPr><w:p><w:pPr><w:jc w:val="center"/></w:pPr><w:r><w:rPr><w:rFonts w:hint="eastAsia" w:eastAsia="宋体"/><w:lang w:val="en-US" w:eastAsia="zh-CN"/></w:rPr><w:t>${title.countD}</w:t></w:r></w:p></w:tc> </w:tr> </w:tbl> <w:p><w:pPr><w:rPr><w:b w:val="0"/><w:color w:val="0066FF"/><w:sz w:val="24"/></w:rPr></w:pPr></w:p> </#list> <w:p><w:bookmarkStart w:id="0" w:name="_GoBack"/><w:bookmarkEnd w:id="0"/></w:p><w:sectPr><w:pgSz w:w="11906" w:h="16838"/><w:pgMar w:top="1440" w:right="1800" w:bottom="1440" w:left="1800" w:header="708" w:footer="708" w:gutter="0"/><w:cols w:space="708" w:num="1"/><w:docGrid w:linePitch="360" w:charSpace="0"/></w:sectPr> </w:body></w:document>
更改完成后将document.xml拷贝至项目resource源下的templates目录下
package com.stylefeng.guns.core.util; import java.io.*; import java.util.Enumeration; import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; import freemarker.template.Configuration; import freemarker.template.Template; /** * Word文档工具类 * @Author xWang **/ public class WordUtil { public static Configuration getConfiguration(){ //创建配置实例 Configuration configuration = new Configuration(Configuration.VERSION_2_3_28); //设置编码 configuration.setDefaultEncoding("utf-8"); configuration.setClassForTemplateLoading(WordUtil.class, "/templates");//换成自己对应的目录 return configuration; } /** * 获取模板字符串输入流 * @param dataMap 参数 * @param templateName 模板名称 * @return */ public static ByteArrayInputStream getFreemarkerContentInputStream(Map dataMap, String templateName) { ByteArrayInputStream in = null; try { //获取模板 Template template = getConfiguration().getTemplate(templateName); StringWriter writer = new StringWriter(); //生成文件 template.process(dataMap, writer); in = new ByteArrayInputStream(writer.toString().getBytes("utf-8"));//这里一定要设置utf-8编码 否则导出的word中中文会是乱码 } catch (Exception e) { System.err.println("模板生成错误"); } return in; } /** * 生成docx文档 * @param dataMap 数据参数 * @param outputStream 输出流 * @param document 模板xml文件名称 * @param templatesZipPath docx后缀名改为zip文档的路径地址(路径加文件名全路径地址) * @return * @author xWang */ public static void createDocx(Map dataMap, OutputStream outputStream,String document,String templatesZipPath) { ZipOutputStream zipout = null; try { //内容模板 ByteArrayInputStream documentInput = WordUtil.getFreemarkerContentInputStream(dataMap, document); File docxFile = new File(templatesZipPath); if (!docxFile.exists()) { docxFile.createNewFile(); } ZipFile zipFile = new ZipFile(docxFile); Enumeration<? extends ZipEntry> zipEntrys = zipFile.entries(); zipout = new ZipOutputStream(outputStream); //开始覆盖文档 int len = -1; byte[] buffer = new byte[1024]; while (zipEntrys.hasMoreElements()) { ZipEntry next = zipEntrys.nextElement(); InputStream is = zipFile.getInputStream(next); if (next.toString().indexOf("media") < 0) { zipout.putNextEntry(new ZipEntry(next.getName())); if ("word/document.xml".equals(next.getName())) {//如果是word/document.xml由我们输入 if (documentInput != null) { while ((len = documentInput.read(buffer)) != -1) { zipout.write(buffer, 0, len); } documentInput.close(); } } else { while ((len = is.read(buffer)) != -1) { zipout.write(buffer, 0, len); } is.close(); } } } } catch (Exception e) { System.err.println("导出失败:"+e.getStackTrace()); }finally { if(zipout!=null){ try { zipout.close(); } catch (IOException e) { System.err.println("io异常"); } } if(outputStream!=null){ try { outputStream.close(); } catch (IOException e) { System.err.println("io异常"); } } } } }
测试
List<Integer> list = new ArrayList(); list.add(1); list.add(2); list.add(3); Map<String,Object> map = new HashMap<>();
map.put("theme","测试");
map.put("titleList",list);
String output_file_name = "test.docx";
String templatesZipPath = "D/templates/templates.zip";
// 清空response
response.reset();
//设置ContentType字段值
response.setContentType("application/octet-stream");
response.setCharacterEncoding("UTF-8");
try {
//解决文件名为中文时的乱码问题
String downloadFileName = URLEncoder.encode(output_file_name,"UTF-8");
// 设置response的Header
response.addHeader("Content-Disposition", "attachment;filename=" + downloadFileName);
OutputStream outputStream = response.getOutputStream();
WordUtil.createDocx(map,outputStream,"document.xml",templatesZipPath);
}catch (FileNotFoundException e){
}catch (IOException e){
}
finally {
}
需要的依赖(maven坐标)
<!--生成word文档所需--> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.28</version> </dependency> <dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.6.1</version> </dependency>