SpringBoot uses Freemarker to export word templates (OpenXML)

1、OpenXML

This article is limited to WPS word, and the format of saving Microsoft word as XML is slightly different

After the word.docx document is saved as xml, a document with OpenXML tags will be generated.

1.1. Commonly used labels

Label explain
<w:wordDocument> Description at the beginning of the XML document, including descriptions of various namespaces
<o:DocumentProperties>
<o:CustomDocumentProperties>
<w:fonts>
<w:styles>
<w:bgPict>
<w:docPr>
<w:body>
In <w:wordDocument>, all document body tags contained
<w:body> document body
<w:sect> In <w:body>, describe the specific document body
<w:sectPr> In <w:sect>, describe the document style, note: when there are multiple <w:sect>s, it may cause inexplicable page breaks
<w:t> Indicates the real text content <w:t xml:space="preserve"> means that spaces will be ignored when there is no content
<w:p> paragraph
<w:r>  A style string specifying the display style of the text it contains
<w:hdr> header
<w:ftr>  footer
<w:val > a value
<w:rPr> The tag in <w:r> is the style inside the r tag
<w:pPr> The tag in <w:p> is the style inside the p tag
<w:b w:val=”on”> Inside the style tag, describe the font in bold
<w:jc w:val="right"/> In the style tag, the alignment of the description paragraph is right alignment, and the optional values ​​​​are right alignment rignt, left alignment left, center alignment center, and both ends alignment both
<w:vAlign w:val="center"/> In the style tag, describe the top and bottom alignment of the cells in the table. The optional values ​​are: upper top, middle center, and lower bottom
<w:sz w:val="40"/> In the style tag, describe the font size, szwhich means Non-Complex Script Font Size, which is the size of single-byte characters (such as ASCII encoded characters, etc.)
<w:szCs w:val="40"/> Font size, szCswhich means Complex Script Font Size, which can be simply understood as the size of double-byte characters (such as Chinese, Japanese, Korean, Arabic, etc.)
<w:attr> Custom XML attributes
<w:bookmarkStart>
<w:bookmarkEnd>
bookmark start, end
<w:bCs> Composite font bold
<w:rFronts> Inside the style tag, describe the font
<w:hint> Use inside the w:rFonts tag inside the style tag:
<w:rFonts w:ascii="Arial" w:h-ansi="Arial" w:cs="Arial" w:hint="fareast"/>
<w:docPr> Describes the overall style of the document
<w:zoom w:percent="100"/> Indicates that the view scale is 100% under the <w:docPr> style tag
<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:wordDocument
    xmlns:*="****">
    <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
    #RequestContext
    request-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文档

Guess you like

Origin blog.csdn.net/JohnGene/article/details/130074210