java使用freemark实现word(.doc/.docx)/pdf生成和导出(附源码和模板文件)

一、 背景

工作需要,需要实现word和pdf的生成,其中包含:word模板生成,.docx转pdf生成,由于.docx是以xml方式读取,.doc是以二进制读取所以,目前我还没有找到好的方案可以实现.doc转pdf,如果网友有什么好的解决方案,请留言告知不胜感激,由于是第一次玩这个所以不是很熟悉,网上以统百度,各种尝试各种采坑,?。网上这样的例子很多,但是坑也很多。我踩了很多坑,特此记载,避免自己和同等需求的网友再次踩坑。如果看完博客还有什么不懂的可以加群一起探讨:821605718, 或者加我个人qq: 2768861003

二、实现的技术选型以及遇到的坑

  1. 网上有人推荐htmlcss实现,样式复杂实现麻烦,且兼容性不好,不考虑
  2. apache poi实现,我一开始采用的这个,网上下载了个demo,跑起来了也成功导出了,欣喜若狂,开始用在自己的项目上,结果有一个类一直报错,具体报啥错,我不记得了,谷歌了很久才发现是版本问题,目前项目框架里面用的excel导出是基于easypoi的easypoi基于apache poi 3.7,而apache poi3.7 是阉割版的,不支持word/pdf导出。我尝试排除依赖无果后,遂放弃apache poi。
  3. 朋友推荐用freemark,我试了一下,虽然中间也遇到很坑,word的模板替换问题,中文不展示问题等。但最终一一解决之后,效果确实很好,不论是导出xml的.docx,还是导出二进制的doc都挺好,而且也可以直接在word上面调整好模板,替换相关参数即可实现变量word/pdf导出。很是方便。就它了,如果大家还有什么推荐,请留言告知。感激不尽。

三、最终的效果

2.1 .doc word效果展示

.doc原始模板
在这里插入图片描述
.doc word替换后模板模板

在这里插入图片描述

2.1 .docx word效果展示

转化前
在这里插入图片描述
在这里插入图片描述
转化后

2.2 docx word转pdf效果展示

在这里插入图片描述

三、准备工作及代码实现

maven导入freemark、xdocreport的包

如果只需要导出word(.doc)的话,只需要一个freemark的包就可以了,如果有pdf导出的需要的话加后面3个包

			<!--freemarker begin-->
			<!-- https://mvnrepository.com/artifact/freemarker/freemarker -->
			<!-- 如果只是想实现word导出,只需要这一个包:freemarker就行了 -->
			<dependency>
				<groupId>org.freemarker</groupId>
				<artifactId>freemarker</artifactId>
				<version>2.3.20</version>
			</dependency>
			<!-- 导出pdf需要使用的包:xdocreport -->
			<dependency>
				<groupId>fr.opensagres.xdocreport</groupId>
				<artifactId>org.apache.poi.xwpf.converter.core</artifactId>
				<version>1.0.4</version>
			</dependency>
			<dependency>
				<groupId>fr.opensagres.xdocreport</groupId>
				<artifactId>org.apache.poi.xwpf.converter.pdf</artifactId>
				<version>1.0.4</version>
			</dependency>
			<dependency>
				<groupId>fr.opensagres.xdocreport</groupId>
				<artifactId>fr.opensagres.xdocreport.itext.extension</artifactId>
				<version>1.0.4</version>
			</dependency>
			<!--freemarker begin-->

3.1后缀为.doc的word生成

1. 创建word.doc,设置word模板,另存为word2003.xml。便于在xml中替换相关变量
注意:这里有(坑多的想放弃,刚开始做的时候,主要是没做过,手动捂脸):
(1)如果word模板是之前编辑好,并且保存了的,注意word模板必须是.doc不能是.docx。LZ亲测,注意别踩坑,原因上面已经讲了,.doc是二进制读取的,word2007以后支持doc和docx。据说word2003不支持.docx。我电脑没装word2003。所以没有测试是否支持。
(2) word模板千万不要提前替换好相关变量,再修改后缀为xml。LZ亲测,替换后很可能你打开xml,你的变量就不再一起了,需要重新找到再次
替换。
(3)wps另存的时候没有word2003.xml。LZ亲测:我特地去激活了我电脑上的windows。。。
在这里插入图片描述
在这里插入图片描述
3. 重命名word后缀为.xml,使用notpad++打开该xml文件notepad++使用xmlTools格式化xml

4. 替换相关参数并保存

(1)替换普通变量:ctrl+f 找到我们需要替换的关键字:title–> 替换为–> ${title}
在这里插入图片描述
在这里插入图片描述
(2) 循环替换变量:例如我们这里的table
ctrl + f 搜索:w:tr, 注意:

  • 这里的w:tr就代表我们table里面的每一行,这里我们是要从第二行开始循环,第一行是表头.
  • 所以我们找到第二个<w:tr>,该标签前面添加关键标签: <#list itemList as l>, 在</w:tr>后面加闭合标签: </#list>。这里的list表示循环,listItem表示java代码需要注入的参数,as l 表示别名,用于指定需要循环的变量
  • 这里面需要循环的变量修改为: ${l.item}${l.name} 以此类推。

在这里插入图片描述

  • 这里的坑: 标签展开后会发现部分变量被切割了,不知道什么原因,这里我们直接把切割的变量恢复就成
    在这里插入图片描述
    在这里插入图片描述

(3) 替换图片,转成xml后,图片是base64编码。我们直接删除编码,放置变量即可。这种一堆字母的就是图片了,删除掉,替换为你想要替换的图片变量:${base64_image}

这里的坑: >${base64_image}<中间不要有任何空格

在这里插入图片描述
在这里插入图片描述
5. 修改后缀为freemark可识别的后缀.ftl

6. 代码解析ftl文件为word.doc

package com.ads4each.adspilot.utils;

import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.misc.BASE64Encoder;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class FtlToWordUtil {
   

    private static Logger logger = LoggerFactory.getLogger(FtlToWordUtil.class);


    /**
     * 图片转base64的字符串
     *
     * @param imageAbsolutePath 图片路径
     * @return String
     */
    public static String imageToBase64Str(String imageAbsolutePath) {
   
        InputStream is = null;
        byte[] data = null;
        try {
   
            is = new FileInputStream(imageAbsolutePath);
            data = new byte[is.available()];
            is.read(data);
            is.close();
        } catch (Exception e) {
   
            e.printStackTrace();
            return null;
        }
        BASE64Encoder encoder = new BASE64Encoder();
        return encoder.encode(data);
    }

    /**
     * 初始化配置文件
     *
     * @param folderPath 生成word的文件夹路径
     * @return Configuration
     */
    private static Configuration initConfiguration(String folderPath) {
   
        Configuration configuration = new Configuration();
        configuration.setDefaultEncoding("utf-8");
        try {
   
            configuration.setDirectoryForTemplateLoading(new File(folderPath));
        } catch (IOException e) {
   
            logger.error("初始化configuration失败,路径不存在:{}", folderPath);
            e.printStackTrace();
        }
        return configuration;
    }

    /**
     * 将数据写入word,并输出到指定路径
     *
     * @param dataMap        需要写入word的数据
     * @param ftlFolderPath  指定的word模板所在的文件夹
     * @param tempName       指定的word模板名称
     * @param outputFilePath 输出路径
     */
    
  • 11
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值