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

news2024/11/13 3:48:49

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: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文档

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/411098.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

算法总结-深度优先遍历和广度优先遍历

深度优先遍历(Depth First Search&#xff0c;简称DFS) 与广度优先遍历(Breath First Search&#xff0c;简称BFS)是图论中两种非常重要的算法&#xff0c;生产上广泛用于拓扑排序&#xff0c;寻路(走迷宫)&#xff0c;搜索引擎&#xff0c;爬虫等。 一、深度优先遍历 深度优先…

网络编程三要素

网络编程三要素 IP、端口号、协议 三要素分别代表什么 ip&#xff1a;设备在网络中的地址&#xff0c;是唯一的标识 端口号&#xff1a;应用程序在设备中的唯一标识 协议&#xff1a;数据在网络中传输的规则 常见的协议有UDP、TCP、http、https、ftp ip&#xff1a;IPv4和…

mongodb $lookup 联表查询

ollection orders : orders record example collection items :items record example $lookup 联表查询 通过item字段连接两个集合orders和items,然后使用 $replaceRoot 中的 $mergeObjects 合并成items和orders的连接文档 db.orders.aggregate( [{$lookup: {from: …

ChatGPT原理解析

文章目录Transformer模型结构构成组件整体流程GPT预训练微调模型GPT2GPT3局限性GPT4相关论文Transformer Transformer&#xff0c;这是一种仅依赖于注意力机制而不使用循环或卷积的简单模型&#xff0c;它简单而有效&#xff0c;并且在性能方面表现出色。 在时序模型中&#…

Databend 开源周报第 88 期

Databend 是一款现代云数仓。专为弹性和高效设计&#xff0c;为您的大规模分析需求保驾护航。自由且开源。即刻体验云服务&#xff1a;https://app.databend.com 。 Whats On In Databend 探索 Databend 本周新进展&#xff0c;遇到更贴近你心意的 Databend 。 Support Eager…

瑞吉外卖——后台系统登录与退出功能

目录 一、登录功能 1.1 思路 1.2 代码 1.3 完善登录功能——过滤器 一、登录功能 1.1 思路 将页面提交的密码password进行md5加密处理 根据页面提交的用户名username查询数据库 如果没有查询到则返回登录失败结果 密码比对&#xff0c;如果不一致则返回登…

你真的会用background属性?

引言 在日常前端开发中&#xff0c;经常需要进行背景或背景图的处理。但是大多数前端er并未真正清楚背景的正确使用方式。经过本章的学习&#xff0c;相信你一定可以解决99%的背景处理问题。 一&#xff1a;简单使用 背景颜色和背景图片是可以共同出现的 div {width: 300px…

STM32F407移植LVGL基于RT-Thread和无操作系统版本

文章目录一、无操作系统1.源码获取&#xff1a;2.输出设备配置&#xff08;屏幕配置&#xff09;几个关键函数屏幕初始化函数&#xff1a;显示刷新(画点)函数3.输入配置&#xff08;触摸&#xff09;4.提供时基二、RT-Thread1.新建工程2.添加软件包&#xff0c;屏幕相关文件以及…

3.5 二维随机变量函数的分布

学习目标&#xff1a; 要学习二维随机变量的分布&#xff0c;我可能会遵循以下步骤&#xff1a; 了解基本概念&#xff1a;我会开始学习二维随机变量、联合概率密度函数、边缘概率密度函数、条件概率密度函数、期望值和方差等基本概念&#xff0c;以确保我对这些概念有一个牢固…

elasticsearch 跨索引联合多条件查询

文章目录Elasticsearch需求使用版本联合索引多条件查询示例相关API相关资料Elasticsearch Elasticsearch 是一个免费且开放的分布式搜索和分析引擎。适用于包括文本、数字、地理空间、结构化和非结构化数据等在内的所有类型的数据。Elasticsearch 在 Apache Lucene 的基础上开…

十分钟玩转3D绘图:WxGL完全手册

文章目录1 简介2 安装3 快速体验3.1 熟悉的风格3.2 Colorbar3.3 光照效果3.4 让模型动起来3.5 定制着色器3.6 三维曲面重建3.7 生成动画或视频文件4 在其他GUI库中使用WxGL4.1 与wxPython集成4.2 与PyQt集成5 API Reference5.1 常量5.2 函数wxgl.font_listwxgl.color_listwxgl.…

Java--反射

目录 反射 什么是反射&#xff1f; Class类 动态加载 小结 访问字段 获取字段值 设置字段值 练习 小结 调用方法 调用方法 调用静态方法 调用非public方法 多态 练习 小结 调用构造方法 小结 获取继承关系 获取父类的Class 获取interface 继承关系 小…

遗传算法优化深度信念网络DBN的分类预测,GA-DBN分类预测

目录 背影 DBN神经网络的原理 DBN神经网络的定义 受限玻尔兹曼机(RBM) 遗传算法的原理 遗传算法优化深度信念网络DBN的分类识别 基本结构 主要参数 数据 MATALB代码 结果图 展望 背影 DBN是一种深度学习神经网络,拥有提取特征,非监督学习的能力,本文用DBN提取特征,遗传…

如何在DevOps中进行API生命周期管理?

引言 随着DevOps理念在中国企业当中的普及和发展&#xff0c;中国企业DevOps落地成熟度不断提升&#xff0c;根据中国信通院的数据已有近6成企业向全生命周期管理迈进。而在研发全生命周期管理之中&#xff0c;API管理的地位愈发显得重要。随着API数量的大幅增长&#xff0c;也…

Java多线程编程—wait/notify机制

文章目录1. 不使用wait/notify机制通信的缺点2. 什么是wait/notify机制3. wait/notify机制原理4. wait/notify方法的基本用法5. 线程状态的切换6. interrupt()遇到方法wait()7. notify/notifyAll方法8. wait(long)介绍9. 生产者/消费者模式10. 管道机制11. 利用wait/notify实现…

【操作系统】半小时写一个微型操作系统-写一个启动扇区并且导入到软盘镜像中

一.什么是启动扇区 我们使用软盘来启动操作系统时&#xff0c;系统首先就是从软盘的第一个扇区中开始读取数据&#xff0c;也就是第0面&#xff0c;0磁道的第0个扇区&#xff0c;软盘的每个扇区为512个字节的大小&#xff0c;如果最后两个字节为0xaa55&#xff08;当BIOS看到这…

Java多线程基础面试总结(一)

进程、线程和协程 进程、线程和协程 进程 进程是程序的一次执行过程&#xff0c;是系统运行程序的基本单位&#xff0c;因此进程是动态的。系统运行一个程序即是一个进程从创建、运行到消亡的过程。 在Java中&#xff0c;当我们启动main函数其实就是启动了一个JVM进程&…

【Linux】全新服务器Centos7环境搭建和安装

1、简介 最近服务器重装后,环境啥的则需要从头全部搞一遍,于是开始搞起环境的配置和安装 2、环境配置安装 前期准备 给目录文件加文件传输权限(发现无法上传文件,于是增加权限 $ chmod 766 /home/lj/ 配置DNS服务 #配置DNS服务,如果没有8.8.8.8需要添加 cat /etc/re…

WRF模式与Python融合技术在多领域中的应用及精美绘图教程

当今从事气象及其周边相关领域的人员&#xff0c;常会涉及气象数值模式及其数据处理&#xff0c;无论是作为业务预报的手段、还是作为科研工具&#xff0c;掌握气象数值模式与高效前后处理语言是一件非常重要的技能。WRF作为中尺度气象数值模式的佼佼者&#xff0c;模式功能齐全…

QML控件--Dialog

文章目录一、控件基本信息二、控件使用三、属性成员四、成员函数五、信号一、控件基本信息 Import Statement&#xff1a;import QtQuick.Controls 2.14 Since&#xff1a;Qt 5.8 Inherits&#xff1a;Popup 二、控件使用 Dialog&#xff1a; 是一个弹出窗口&#xff0c;继承…