FreeMarker生成word文档,固定word模板

news2024/9/28 23:29:05

该方法也就是通过freemarker生成固定的word文档,动态的word模板布局不能用该方法。

也就是必须有一个固定的模板文档是.ftl类型

如果初始文件为

 需要手动改为:

 也就是所有需要替换的地方,都需要有${XX}替换。

 

主要步骤为:

  1. 将 word 中需要填充的数据用占位符${变量名}替换。
  2. 将该 word 另存为 .xml 的格式,并检查看格式是否有误(主要看占位符有没被分割开来)。
  3. 将后缀.xml改成.ftl后,再调用相关 API 即可生成 word 文档。

特别注意,一定是将word另存为xml格式,而不是在外面修改后缀,不然会乱码。

其次一定要在xml或者ftl格式下检查格式,查询${XX}是否正确,看是否有占位符被分隔开的情况,如果有,只需将中间多余的部分删除即可。

处理普通文本
处理文本比较简单,在原文件中直接用占位符 ${} 替换即可。

处理表格
处在生成 word 表格时,FreeMarker 是利用列表一行一行循环填充的,而表头只会生成一次,因此我们还需手动改动一下 .ftl 文件。

注意:<w:tbl> 表示一个表格 、<w: tr> 表示一行、<w: tc> 表示一列,我们先找到第一行填充数据的那行,在前后分别加上如下语句即可:
 

<#list itemList as item>
</#list>

在这里插入图片描述

 

另一种情况:还有一种情况,即需要进行单元格的合并操作,前面和上面都差不多,不过还要加上另一种标签:

<w:vmerge w:val='restart'/>
<w:vmerge/>

我们先用 ${item.startMerge}(开始合并)和 ${item.endMerge}(结束合并)分别替换上面2行。

我们可以看到第一列分组是有合并单元格存在的,因此,找到第一列的 <w: tc> 那,如下图所示:

在这里插入图片描述 

 

1.导入相关依赖

我们主要用到了 FreeMarker,在这里,只需要导入以下依赖即可:

 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>

2.生成 word 的工具类

此方法将生成的文档传到前端;


import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.Version;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;

public class WordUtils {

    /**
     * 生成 word 文档方法
     *
     * @param dataMap      要填充的数据
     * @param templateName 模版名称
     * @param fileName     要输出的文件路径
     * @throws Exception 抛出的异常
     */
    public static void generateWord(HttpServletResponse response,Map<String, Object> dataMap, String templateName, String fileName) throws Exception {

        // 设置FreeMarker的版本和编码格式
        Configuration configuration = new Configuration(new Version("2.3.28"));
        configuration.setDefaultEncoding("UTF-8");

        // 设置FreeMarker生成Word文档所需要的模板的路径
        // configuration.setDirectoryForTemplateLoading(new File("/Users/xxx/Desktop/"));
        // 此处把模版文件都放在 resources 下的 templates 中
        configuration.setClassForTemplateLoading(WordUtils.class, "/templates");

        // 设置FreeMarker生成Word文档所需要的模板
        Template tem = configuration.getTemplate(templateName, "UTF-8");
        // 创建一个Word文档的输出流
//        Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(fileName)), StandardCharsets.UTF_8));
//         FreeMarker使用Word模板和数据生成Word文档
//        response.setCharacterEncoding("UTF-8");
        response.setContentType("multipart/form-data");
//        response.setHeader("content-type", "application/octet-stream");
//        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));

        response.setCharacterEncoding("utf-8");
        response.setContentType("applicaiton/msword");
//        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".docx");
        response.addHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));
        PrintWriter writer = response.getWriter();
        //tem.process(dataMap,new FileWriter("C:\\Users\\14017\\Desktop\\word.docx"));
        tem.process(dataMap, writer);
        writer.close();
        //tem.process(dataMap,response.getWriter());
//        writer.flush();
//        writer.close();
//        tem.process(dataMap,out);
//        out.flush();
//        out.close();
    }
}

此方法是将生成的文档存储到固定位置--目前在桌面

package com.iwiti.qcc.manage;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.Version;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;

public class WordUtils {

    /**
     * 生成 word 文档方法
     *
     * @param dataMap      要填充的数据
     * @param templateName 模版名称
     * @param fileName     要输出的文件路径
     * @throws Exception 抛出的异常
     */
    public static void generateWord(HttpServletResponse response,Map<String, Object> dataMap, String templateName, String fileName) throws Exception {

        // 设置FreeMarker的版本和编码格式
        Configuration configuration = new Configuration(new Version("2.3.28"));
        configuration.setDefaultEncoding("UTF-8");

        // 设置FreeMarker生成Word文档所需要的模板的路径
        // configuration.setDirectoryForTemplateLoading(new File("/Users/xxx/Desktop/"));
        // 此处把模版文件都放在 resources 下的 templates 中
        configuration.setClassForTemplateLoading(WordUtils.class, "/templates");

        // 设置FreeMarker生成Word文档所需要的模板
        Template tem = configuration.getTemplate(templateName, "UTF-8");
        // 创建一个Word文档的输出流
//        Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(fileName)), StandardCharsets.UTF_8));
//         FreeMarker使用Word模板和数据生成Word文档
//        response.setCharacterEncoding("UTF-8");
        response.setContentType("multipart/form-data");
//        response.setHeader("content-type", "application/octet-stream");
//        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));

//        response.setCharacterEncoding("utf-8");
//        response.setContentType("applicaiton/msword");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".docx");
//        response.addHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));
//        PrintWriter writer = response.getWriter();
        tem.process(dataMap,new FileWriter("C:\\Users\\14017\\Desktop\\word.docx"));
//        tem.process(dataMap, writer);
//        writer.close();
        //tem.process(dataMap,response.getWriter());
//        writer.flush();
//        writer.close();
//        tem.process(dataMap,out);
//        out.flush();
//        out.close();
    }
}

3.准备填充所需的数据

一般来说,我们的数据可能是从数据库中查询出来的各种对象,这里为了方便,就直接利用 HashMap 存储数据了。

 public static Map<String,Object> initData(){
        // 对应单元格的合并
        final String startMerge = "<w:vmerge w:val='restart'/>";
        final String endMerge = "<w:vmerge/>";
        
        final LocalDate nowDate = LocalDate.now();
        Map<String, Object> data = new HashMap<>();
        data.put("name", "张三");
        data.put("dept", "办公室");
        data.put("time", nowDate);

        List<Item> itemList = new ArrayList<>();
        Item item1 = new Item();
        item1.setProject("分组A")
                .setProjectDetail.setTime("2-13")
                .setProjectDetail.setPeople("小米")
                ..setProjectDetail.setAddress("北京")
                .setStartMerge(startMerge);
        itemList.add(item1);

        Item item2 = new Item();
        item2.setProject("分组A")
                .setProjectDetail.setTime("2-13")
                .setProjectDetail.setPeople("小米")
                ..setProjectDetail.setAddress("北京")
                .setEndMerge(endMerge);
        itemList.add(item2);Project

        Item item3 = new Item();
        item3.setProject("分组B")
                 .setProjectDetail.setTime("2-13")
                .setProjectDetail.setPeople("小米")
                ..setProjectDetail.setAddress("北京")
        itemList.add(item3);
        data.put("itemList", itemList);


        return data;
    }

注意的是表格的map的value是实体类,且这个实体类还有一个实体类嵌套,其次在修改模板是,将itemList  as item, 所以占位符就是${item.project}与${item.projectDetail.time}

4.生成 word 文档

 

         String templateName = QCC_TEMPLATE_WORD;
        String fileName = DateUtil.format(new Date(), "yyyyMMddHH") + QCC__WORD ;
        WordUtils.generateWord(response,data, templateName, fileName);


    //Qcc模板文件
    public static final String QCC_TEMPLATE_WORD = "QccTemplate.ftl";

    //Qcc生成文件名
    public static final String QCC__WORD = "QCC_REPORT.docx";

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

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

相关文章

JVM学习8: 字符串

基本特性 代表不可变字符序列final不可被继承实现了Serializable、Comparable等接口jdk8及以前使用final char[]存储&#xff0c;jdk9开始改为使用byte[]存储通过字面量方式给一个字符串变量赋值&#xff0c;此时字符串对象在字符串常量池里面 字符串常量池 字符串常量池不会…

《论文阅读》PAL: Persona-Augmented Emotional Support Conversation Generation

《论文阅读》PAL: Persona-Augmented Emotional Support Conversation Generation 前言简介思路出发点相关知识coefficient of determination任务定义模型框架实验结果前言 你是否也对于理解论文存在困惑? 你是否也像我之前搜索论文解读,得到只是中文翻译的解读后感到失望?…

企企通:企业供应商风险管理,如何用采购管理软件赋能?

企业采购过程中&#xff0c;最怕/最担心的事情无非是&#xff1a;供应链异常。供应链异常&#xff0c;也就是我们常说的供应链风险&#xff0c;可以简单分为需求风险、供应商风险、物流风险和财务风险四大类。其中&#xff0c;最为突出的风险便是供应商风险。从寻找合适的供应商…

用VSCode搭建Vue.js开发环境及Vue.js第一个应用

目录 一、VSCode安装 二、VSCode简单配置 三、Vue.js的下载和引入 四、Vue.js第一个应用 一、VSCode安装 Visual Studio Code是一个轻量级但功能强大的源代码编辑器&#xff0c;可在您的桌面上运行&#xff0c;可用于Windows&#xff0c;macOS和Linux。它内置了对JavaScrip…

阿里一P7员工为证明自己年入百万,晒出工资,却被网友...

阿里的工资在行业内确实是比较高的一类&#xff0c;之前网络上流传着阿里P7年入百万的消息也不是空穴来风&#xff0c;日前&#xff0c;有位阿里P7员工&#xff0c;为了证明自己的确年入百万&#xff0c;晒出了他的工资&#xff0c;网友们看完都沸腾了。什么情况&#xff1f;一…

BSN全球伙伴大会于本周五召开在即,重磅嘉宾演讲主题前瞻

“第三届区块链服务网络&#xff08;BSN&#xff09;全球合作伙伴大会”召开在即&#xff0c;将于2023年2月17日&#xff08;本周五&#xff09;在杭州市拱墅区举办。 BSN已邀请到来自国内外的行业专家学者与生态合作伙伴&#xff0c;与各界来宾就“建设数字中国”指导思想中的…

iOS 客户端 IM 消息卡片插件化

背景 目前探探 IM 聊天消息列表由于长年累月的代码堆积&#xff0c;对业务迭代产生了很多的困扰。所以趁着工作中的一些空隙&#xff0c;对聊天页消息卡片做了插件化&#xff0c;使得不同的消息类型&#xff0c;可以根据具体需求方便的增删迭代。下面分享一下自己重构过程中一…

项目经理,千万不要在这时候跳槽

早上好&#xff0c;我是老原。节后开工也一段时间了&#xff0c;有不少小友私信老原想要面试题库&#xff0c;大多都是想要跳槽涨薪的......当然除了在做准备的&#xff0c;也有不少朋友都在诉苦&#xff1a;其实&#xff0c;不少人回头去看自己过去经验感觉就像个打杂的&#…

PCB中的HDI板生产中的变化

关键词&#xff1a;HDI概述 HDI发展演变 HDI生产难点如果把一整个电子产业比作浩瀚的宇宙&#xff0c;那些智能电子设备就像宇宙中闪耀的星光&#xff0c;当你以“上帝”的视角手持放大镜去观察时&#xff0c;这些闪烁的星光点点其实都是一个个由精密的“自然规律”所“设计”好…

金三银四丨黑蛋老师带你剖析-CTF岗

作者丨黑蛋二进制是个庞大的方向&#xff0c;对应着许许多多方向的岗位&#xff0c;除了之前说过的逆向岗位&#xff0c;漏洞岗位&#xff0c;病毒岗位&#xff0c;还有专门打CTF的岗位&#xff0c;CTF是网络安全领域的一种比赛。普遍来讲&#xff0c;大学生学习网络安全都会参…

percona软件介绍 、 innobackupex备份与恢复

1. 常用的mysql备份工具 物理备份缺点&#xff1a; 跨平台差。备份时间长、冗余备份、浪费存储空间。 解释如下&#xff1a;如Linux操作系统和Windows操作系统之间&#xff0c;由于文件系统不一样&#xff0c;如Linux操作系统的文件系统是ext4、xfs&#xff0c;Windows操作系统…

K8s+SpringBoot+gRpc

本文使用K8s当做服务注册与发现、配置管理&#xff0c;使用gRpc用做服务间的远程通讯一、先准备K8s我在本地有个K8s单机二、准备service-providerpom<?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.…

浅谈性能测试监控系统,做好关键指标的监控

随着业务的增长&#xff0c;服务器部署由单一架构向分布式集群架构转变&#xff0c;性能测试过程中指标监控也由单一服务器向集群服务器转变。 对于性能测试团队来说&#xff0c;需要建立起适用于测试的多机监控系统&#xff0c;以便后期顺利且高效地进行监控分析调优&#xf…

Java程序员拿下高薪offer需要具备哪些能力?这份Java面试专题汇总助你拿下心仪offer!!

背景今天这篇文章的灵感来自一个粉丝的亲身经历&#xff0c;想必也是求职浪潮中很多朋友的经历&#xff0c;内卷大环境找不到满意工作的人太多了&#xff0c;之前也有很多人问过我怎么才能找到不错的工作&#xff0c;甚至是进大厂&#xff0c;所以今天就借这位粉丝的经历来聊聊…

对JAVA 中“指针“理解

对于Java中的指针&#xff0c;以下典型案例会让你对指针的理解更加深刻。 首先对于&#xff1a; 系统自动分配对应空间储存数字 1&#xff0c;这个空间被变量名称b所指向即: b ——> 1 变量名称 空间 明…

linux下yum安装consul实现动态配置管理

一、yum安装consul #安装yum-utils yum install -y yum-utils#配置consul的下载仓库 yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo#必须上面步骤&#xff0c;不然会找不到仓库 yum -y install consul#查看版本 consul -v 二、启动…

基于深度学习的三维重建(二):pytorch的简单操作及DataLoader、Dataset类简介

目录 1.numpy举几个demo 2.pytorch基础 2.1 tensor介绍 3.简单版DataSet & DataLoader 4.模型构建 5.深度学习模型demo&#xff1a;手写文字识别 5.1 构建网络 5.2 前向传播过程 5.3 训练部分 5.4 测试部分 5.5 模型导出 5.6 模型测试 6.pytorch可视化工具ten…

MySQL数据库调优————索引数据结构

B-TREE B-TREE数据结构 B-TREE特性 根节点的子结点个数2 < X < m&#xff0c;m是树的阶 假设m 3&#xff0c;则根节点可有2-3个孩子 中间节点的子节点个数m/2 < y < m 假设m 3&#xff0c;中间节点至少有2个孩子&#xff0c;最多3个孩子 每个中间节点包含n个关…

《MySql学习》 行锁对业务的影响

一. 行锁介绍 行锁由各个存储引擎分别实现&#xff0c;MyISAM存储引擎是不支持行锁的&#xff0c;这也是MySQL使用InnoDB作为默认存储引擎的一个重要原因&#xff0c;锁更细的InnoDB能支持更多的并发业务。但需要注意的是&#xff0c;行锁在InnoDB的实现是给索引加的锁&#x…

智慧养殖无线通讯解决方案

一、方案概述农植畜禽/水产养殖智能监控系统可以在远端设备实现对如温度、湿度、气体浓度、光照度等传感设备的自动调节与控制功能。管理者可随时通过电脑了解养殖场各环节的运行状况&#xff0c;并根据养殖现场内外环境因子的变化情况将命令下发到现场执行设备。为动植物营造舒…