> 文章列表 > SpringBoot使用Freemarker导出word模板(OpenXML)

SpringBoot使用Freemarker导出word模板(OpenXML)

SpringBoot使用Freemarker导出word模板(OpenXML)

1、OpenXML

word.docx文档另存为xml之后会生成带有OpenXML标签的文档。

1.1、常用标签示意

标签 解释
<w:wordDocument> XML文档开头描述,包括各种命名空间的描述
<o:DocumentProperties>
<o:CustomDocumentProperties>
<w:fonts>
<w:styles>
<w:bgPict>
<w:docPr>
<w:body>
在<w:wordDocument>中,包含的所有文档主体标签
<w:body> 文档体
<w:sect> 在<w:body>中,描述具体文档体
<w:sectPr> 在<w:sect>中,描述文档样式,注:出现多个<w:sect>时可能会导致莫名其妙的分页
<w:t> 表示真正的文本内容<w:t xml:space="preserve">的意思是无内容时空格会被忽略
<w:p> 段落
<w:r>  样式串,指明它包括的文本的显示样式
<w:hdr> 页眉
<w:ftr>  页脚
<w:val > 一个值
<w:rPr> 在<w:r> 中的标签,是r标签内的样式
<w:pPr> 在<w:p>中的标签,是p标签内的样式
<w:b w:val=”on”> 在样式标签内,描述字体问粗体
<w:jc w:val="right"/> 在样式标签内,描述段落对齐方式为右对齐,可选值有右对齐rignt、左对齐left、居中对齐center、两端对齐both
<w:vAlign w:val="center"/> 在样式标签内,描述表格中的单元格上下对齐方式,可选值有:上top、中center、下bottom
<w:sz w:val="40"/> 在样式标签内,描述字号大小,sz表示Non-Complex Script Font Size,简单理解的话,就是单字节字符(如ASCII编码字符等)的大小
<w:szCs w:val="40"/> 字号,szCs表示Complex Script Font Size,可以简单理解为双字节字符(如中日韩文字、阿拉伯文等)的大小
<w:attr> 自定义XML属性
<w:bookmarkStart>
<w:bookmarkEnd>
书签开始、结束
<w:bCs> 复合字体加粗
<w:rFronts> 在样式标签内,描述字体
<w:hint> 在样式标签内的w:rFonts标签内使用:

<w:rFonts w:ascii="宋体" w:h-ansi="宋体" w:cs="宋体" w:hint="fareast"/>
<w:docPr> 描述文档整个的样式
<w:zoom w:percent="100"/> 在<w:docPr>样式标签下表示视图比例100%
<w:view w:val="print"/> 在<w:docPr>样式标签下表示文档视图是"print"
<w:tbl> 表格标签
<w:tblPr> 在<w:tbl>中,表示表格样式标签
<w:tblBorders> 在<w:tblPr>中,表示表格边框样式
<w:tblGrid> 在<w:tbl>中,定义表格列数以
<w:gridCol w:w="715"/> 在<w:tblGrid>中,定义表格每列的宽度
<w:tr> 在<w:tbl>中,表示表格的行
<w:trPr> 在<w:tr>中,表示表格行的样式
<w:tc> 在<w:tr>中,表示表格的某一行的某个单元格
<w:tcPr> 在<w:tc>中,描述单元格样式
<w:gridSpan w:val="2"/> 左右合并单元格
<w:vmerge w:val="restart"/>
<w:vmerge w:val="continue"/>
上下合并单元格,合并的第一个单元格w:val="restart",下面需要合并的单元格都使用continue
<w:br w:type="page"/> 分页符
<w:pict> 图片区域
<w:binData> 在<w:pict>中,图片源(注:base64图片数据不带【data:image/png;base64,】前缀)

<w:binData w:name="wordml://01.png" xml:space="preserve">base64图片数据</w:binData>
<v:shape>

图片引用占位符,引用的是<w:binData>图片(<v:imagedata src="wordml://01.png" 名称是已存在的图片源)

<v:shape id="图片 10" o:spid="_x0000_s1026" o:spt="75" alt="001.png"  style="xxx" filled="f" o:preferrelative="t" stroked="f" coordsize="21600,21600"><v:path/><v:fill on="f" focussize="0,0"/><v:stroke on="f"/><v:imagedata src="wordml://01.png" o:title="001.png"/><o:lock v:ext="edit" aspectratio="t"/>
</v:shape>

1.2、文档大略结构

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<?mso-application progid="Word.Document"?>
<w:wordDocumentxmlns:*="****"><o:DocumentProperties><!--作者--><o:Author>xxx</o:Author><!--修改者--><o:LastAuthor>xxx</o:LastAuthor><!--创建时间--><o:Created>xxx</o:Created><!--修改时间--><o:LastSaved>xxx</o:LastSaved><!--时长--><o:TotalTime>0</o:TotalTime><!--页数--><o:Pages>0</o:Pages><!--字数--><o:Words>0</o:Words><!--字节数--><o:Characters>0</o:Characters><!--行数--><o:Lines>0</o:Lines><!--段落数--><o:Paragraphs>0</o:Paragraphs><!--空格数--><o:CharactersWithSpaces>0</o:CharactersWithSpaces><!--版本--><o:Version>14</o:Version></o:DocumentProperties><o:CustomDocumentProperties><!--KSO产品构建版本--><o:KSOProductBuildVer dt:dt="string">xxxx</o:KSOProductBuildVer><o:ICV dt:dt="string">xxxx</o:ICV></o:CustomDocumentProperties><!--字体组--><w:fonts><w:defaultFonts w:ascii="Calibri" w:fareast="宋体" w:h-ansi="Calibri" w:cs="Times New Roman"/><w:font w:name="宋体"><w:panose-1 w:val="02010600030101010101"/><w:charset w:val="86"/><w:family w:val="Auto"/><w:pitch w:val="Default"/><w:sig w:usb-0="00000203" w:usb-1="288F0000" w:usb-2="00000006" w:usb-3="00000000" w:csb-0="00040001" w:csb-1="00000000"/></w:font></w:fonts><!--样式组--><w:styles><w:latentStyles w:defLockedState="off" w:latentStyleCount="260"><w:lsdException w:name="Normal"/></w:latentStyles><w:style w:type="paragraph" w:styleId="a1" w:default="on"><w:name w:val="Normal"/><w:pPr><w:widowControl w:val="off"/></w:pPr><w:rPr><w:rFonts w:ascii="Calibri" w:h-ansi="Calibri" w:fareast="宋体" w:cs="Times New Roman" w:hint="default"/><w:sz w:val="22"/><w:sz-cs w:val="22"/><w:lang w:val="EN-US" w:fareast="EN-US" w:bidi="AR-SA"/></w:rPr></w:style></w:styles><!--文档背景描述--><w:bgPict><w:background/><v:background id="_x0000_s1025"><v:fill on="f" focussize="0,0"/></v:background></w:bgPict><!--文档样式--><w:docPr><!--视图--><w:view w:val="print"/><!--缩放--><w:zoom w:percent="100"/><!--字符间距--><w:characterSpacingControl w:val="CompressPunctuation"/><!--文档保护--><w:documentProtection w:enforcement="off"/><!--标点符号相关--><w:punctuationKerning/><!--不嵌入系统字体--><w:doNotEmbedSystemFonts/><!--边界不围绕头部--><w:bordersDontSurroundHeader/><!--边界不围绕尾部--><w:bordersDontSurroundFooter/><w:defaultTabStop w:val="420"/><!--绘图网格垂直间距--><w:drawingGridVerticalSpacing w:val="156"/><!--显示水平绘制网格间隔--><w:displayHorizontalDrawingGridEvery w:val="0"/><!--显示垂直绘制网格间隔--><w:displayVerticalDrawingGridEvery w:val="2"/><!--兼容性描述--><w:compat><!--调整表格中的线条高度--><w:adjustLineHeightInTable/><!--URL尾部空间--><w:ulTrailSpace/><!--不展开移位--><w:doNotExpandShiftReturn/><!--平衡单字节双字节宽度--><w:balanceSingleByteDoubleByteWidth/><!--使用EF布局--><w:useFELayout/><w:spaceForUL/><!--带双关语的包装文本--><w:wrapTextWithPunct/><!--表格换行兼容--><w:breakWrappedTables/><!--使用Asian规则--><w:useAsianBreakRules/><!--自动调整--><w:dontGrowAutofit/></w:compat></w:docPr><!--文档内容--><w:body><!--内容主体--><wx:sect><w:p><w:pPr><w:spacing w:line="360" w:line-rule="exact"/><w:jc w:val="center"/><w:rPr><w:rFonts w:ascii="宋体" w:h-ansi="宋体" w:hint="default"/><w:b/><w:sz w:val="28"/><w:sz-cs w:val="28"/><w:lang w:fareast="ZH-CN"/></w:rPr></w:pPr><w:r><w:rPr><w:rFonts w:ascii="宋体" w:h-ansi="宋体" w:hint="fareast"/><w:b/><w:sz w:val="28"/><w:sz-cs w:val="28"/><w:lang w:fareast="ZH-CN"/></w:rPr><w:t>xxx</w:t></w:r></w:p></wx:sect><wx:sect><!--内容样式区域--><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="851" w:footer="992" w:gutter="0"/><w:cols w:space="720"/><w:docGrid w:type="lines" w:line-pitch="312"/></w:sectPr></wx:sect></w:body>
</w:wordDocument>

2、SpringBoot使用FreeMarker模板导出自定义样式的文档

1、新建Word,里面插入个Table

2、另存为xml文件

3、格式化xml文件并重命名为ftl后缀

可以使用在线格式化工具:在线 XML 格式化 | 菜鸟工具 (runoob.com)

4、修改ftl文件

将ftl文件中1,2,3单元格位置变成${param1},${param2},${param3}

 5、java代码

这里使用SpringBoot2.7.4

5.1、添加pom依赖

<!-- freemarker依赖 -->
<dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.32</version>
</dependency>

5.2、application配置

【application.properties改成application.yml方便一些】

server:port: 9090
spring:#freemarker配置#默认的classpath:/templates/?freemarker:template-loader-path: /ftl_templates#后缀suffix: .ftl#编码charset: utf-8#RequestContextrequest-context-attribute: request

5.3、工具类WordUtil

import freemarker.template.Configuration;
import freemarker.template.Template;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;import java.io.*;
import java.net.URLEncoder;
import java.util.Map;public class WordUtil {/*** 生成word文件*/@SuppressWarnings("unchecked")public static void createWord(HttpServletResponse response, Map dataMap, String templateName, String fileName, String fileSuffix){File outFile=null;Writer out=null;InputStream fin=null;ServletOutputStream out2=null;try {//创建配置实例Configuration configuration = new Configuration(Configuration.getVersion());//设置编码configuration.setDefaultEncoding("UTF-8");//ftl模板文件 取模板文件存放地址configuration.setClassForTemplateLoading(WordUtil.class,"/ftl_templates");//获取模板Template template = configuration.getTemplate(templateName);//创建临时文件outFile = File.createTempFile(fileName, fileSuffix);//获取临时文件目录方便后面使用String tempFilePath = outFile.getAbsolutePath();//将模板和数据模型合并生成文件out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile),"UTF-8"));//生成文件 实际这里已经将文件生成在指定位置template.process(dataMap, out);//以下操作是将文件下载File file = new File(tempFilePath);fin = new FileInputStream(file);response.setCharacterEncoding("utf-8");response.setContentType("application/msword");// 设置浏览器以下载的方式,处理该文件名  ps:docx格式office可能存在打不开等问题fileName = URLEncoder.encode(fileName+fileSuffix, "utf-8");response.setHeader("Content-Disposition","attachment;filename="+fileName);out2 = response.getOutputStream();byte[] buffer = new byte[512];int bytesToRead = -1;// 通过循环将读入的Word文件的内容输出到浏览器中while ((bytesToRead = fin.read(buffer)) != -1) {out2.write(buffer, 0, bytesToRead);}//关闭流out.flush();} catch (Exception e) {e.printStackTrace();}finally {try {if (out != null) {out.close();}if (fin != null) {fin.close();}if (out2 != null) {out2.close();}if(outFile!=null) {outFile.delete();}}catch (Exception e){}}}
}

5.4、Controller类

import com.example.ftldemo.utils.WordUtil;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;@Controller
@RequestMapping("/demo")
public class DemoController {@RequestMapping("/export")public void exportDemo(HttpServletResponse response){/** 用于组装word页面需要的数据 */Map<String, Object> dataMap = new HashMap<>();dataMap.put("param1","111");dataMap.put("param2","222");dataMap.put("param3","333");String fileName = "生成Word文档";String fileSuffix=".doc";/** 生成word  数据包装,模板名,文件生成路径,生成的文件名*/WordUtil.createWord(response,dataMap, "导出wordDemo.ftl", fileName, fileSuffix);}
}

5.5、运行使用浏览器

访问    localhost:9090/demo/export  可以下载示例word文档