需求:动态生成pdf指定模板
实现途径:通过freemarker模板,导出word文档,同时可将word转为pdf。
技术选择思路
思路一:直接导出pdf
使用itext模板导出pdf
适用范围
业务生成的 pdf 是具有固定格式或者模板的文字及其图片等内容,使用模板,只需要将不一致的地方改成文本域,然后进行文字填充就可以了;如果涉及的业务不能有模块化可以提取出来东西,从开头一步一步去绘画。
参考链接
JAVA 使用Itext模板生成pdf,解决图片插入,文本域超出字体缩放,半自动换行[https://blog.csdn.net/a_lllk/article/details/109450972]
java根据模板生成pdf文件并导出https://blog.csdn.net/TOP__ONE/article/details/65442390
缺点
超出文本域的部分的文字(若不设置自动调整文字大小)则会不显示,无法自动分页。(暂未找到解决方案)
思路二:先导出word再转成pdf
1)导出word
-
FreemarkerFreemarker 将数据填入 .ftl 模板导出 word(.doc/.docx)
(注意:需要循环展示的内容还需要在xml文件中处理)FreeMarker 是一个用Java语言编写的模板引擎,它基于模板输出文本。FreeMarker 与 Web 容器无关,即在Web运行时,它并不知道 Servlet 或 HTTP。它不仅可以用作表现层的实现技术,而且还可以用于生成XML,JSP或Java 等。
Java 程序准备的数据来显示(比如 SQL 查询),FreeMarker 仅仅使用模板生成文本页面来呈现已经准备好的数据。
Freemarker 的使用步骤
1)、创建一个Configuration对象,直接new一个对象。构造方法的参数就是freemarker对于的版本号;
2)、设置模板文件所在的路径;
3)、设置模板文件使用的字符集。一般就是UTF-8;
4)、加载一个模板,创建一个模板对象;
5)、创建一个模板使用的数据集,可以是pojo也可以是map。一般是Map;
6)、创建一个Writer对象,一般创建一FileWriter对象,指定生成的文件名;
7)、调用模板对象的process方法输出文件;
8)、关闭流;
参考链接:
SpringBoot整合Freemarker导出word文档表格
freemarker导出Word,文本,可循环表格,合并单元格,可循环图片,目录更新(一)
缺点:
导出的 .doc / .docx 实际上是 xml 文件,用办公软件能正常打开使用。但是转 PDF 的时候发现转不成功。转过之后的 PDF 显示的不是 word 的格式字符,而是像 xml 文件的标签及字符。
Freemarker 结合 .docx 格式的本质将数据填入 .docx 里面的 document.xml 文件导出 .docx
参考链接:
freemarker动态生成word并将生成的word转为PDF
优点:
可转换为 pdf
相关错误:
A. Date 格式的数据传输报错!
解决方案:
${(initialTime?string("yyyy-MM-dd HH:mm:ss"))!}
附:
a. 循环行及表单行是否显示功能参考链接:
SpringBoot整合Freemarker导出word文档表格
freemarker合并单元格,if、else标签的使用,null、空字符串处理
-
dock4j结合 .docx 格式的本质将数据填入 .docx 里面的 document.xml 文件导出 .docx
docx4j 中模板的使用
-
POI
-
Aspose.word(需要license)
2)word转pdf
思路一:
将目标word文件另存为xml文件,将里面的需要动态生成的内容用freemarker的表达式${}替换.
用freemarker生成word的工具类,动态生成word. 这样生成的word实际上是xml文件,用办公软件能正常打开使用.
但是转PDF的时候发现转不成功.转过之后的PDF显示的不是word的格式字符,而是像xml文件的标签及字符,失败!
-
dock4j将.docx转pdf
- 使用 docxToPdf() 将 .docx 文件转换为 .pdf 时,中文的可以顺利换行,但是一连串的英文就会超出表格,无法自动换行。
-
Spire.Doc 实现 word (.doc / .docx)转 pdf
有付费版和免费版,免费版仅支持三页内的 word 转 pdf
-
aspose.word 将 word 转 pdf
使用freemarker生成动态的word文档的步骤如下:
前提:ftl文件是模板。通过word生成:先把模板word转换成.xml文件,进行修改后将后缀改成.ftl文件。
下面是我的word文件:
生成后的word长这样
在xml文件中,如果要实现循环列表:
代码实现:
1.添加依赖
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.19</version>
</dependency>
2.创建freemarker配置对象
Configuration configuration = new Configuration(Configuration.VERSION_2_3_20);
3.设置模板文件所在的目录
configuration.setDirectoryForTemplateLoading(new File("templates"));
4.获取模板文件
Template template = configuration.getTemplate("template.ftl");
5.创建数据模型
Map<String, Object> data = new HashMap<>();
data.put("title", "动态生成Word文档");
data.put("content", "这是一篇使用Freemarker生成的Word文档。");
6.创建输出流
File outFile = new File("output.doc");
Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "UTF-8"));
7.将数据模型和模板文件合并,并输出到文件中
template.process(data, out);
完整代码如下:
/**
* 通过模板导出word格式文件
*
* @param dataMap 导出数据
* @param templateName 模板名称
* @param path 导出word的路径以及文件名称
*/
public static void exportWord(Map<String, Object> dataMap, String templateName, String path) {
try {
//Configuration 用于读取ftl文件
Configuration configuration = new Configuration();
configuration.setDefaultEncoding("utf-8");
//指定路径(根据某个类的相对路径指定)
configuration.setClassForTemplateLoading(WordPDFUtil.class, "/template");
//输出文档路径及名称
File outFile = new File(path);
FileOutputStream os = new FileOutputStream(outFile);
//以utf-8的编码读取ftl文件
Template template = configuration.getTemplate(templateName, "utf-8");
Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"), 10240);
template.process(dataMap, out);
//导出成word时,\n换行替换成 <w:br/> 标签,不起作用,无法换行,所以用Document保存word
Document doc = new Document(path);
doc.save(os, SaveFormat.DOC);
out.close();
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}
# Freemaker设置HTML自动转义
freemarker作为"通用"模版引擎, 默认情况下不会对model中的值进行html转义, 然而在web项目中, 为了防止跨站脚本攻击等问题, 必须在对model中的值进行转义.
解决办法:
https://www.iteye.com/blog/maria3905-2098745
Apose.word实现word转pdf:
/**
* word、pdf处理工具类
*/
public class WordPDFUtil {
protected static Logger logger = LoggerFactory.getLogger(WordPDFUtil.class);
// 读取license.xml的内容
public static boolean getLicense() {
boolean result = false;
Resource resource = new ClassPathResource("static/license.xml");
try (InputStream is = resource.getInputStream()) {
License aposeLic = new License();
aposeLic.setLicense(is);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* word转pdf文件
*
* @param Address 原文件地址
* @param pdfAddress 保存的pdf文件地址
*/
public static void wordConvertPdf(String Address, String pdfAddress) throws IOException {
// 验证License 若不验证则转化出的pdf文档会有水印产生
if (!getLicense()) {
return;
}
FileOutputStream os = null;
try {
// 新建一个空白pdf文档
File file = new File(pdfAddress);
os = new FileOutputStream(file);
// Address是将要被转化的word文档
Document doc = new Document(Address);
// 全面支持DOC, DOCX, OOXML, RTF HTML, OpenDocument, PDF, EPUB, XPS, SWF 相互转换
doc.save(os, SaveFormat.PDF);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != os)
os.close();
}
}
用到的import:
import com.aspose.words.Document;
import com.aspose.words.License;
import com.aspose.words.SaveFormat;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import java.io.*;
import java.util.Map;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;