在项目中需要以Word文件为模板,填充指定数据,并转换为Pdf文件。可以分为两步,第一步使用POI进行文本替换,第二步把替换后的Word转换为pdf文件。
当前遇到的问题是网上所有的转换工具依赖的包都过大,一般要30M以上。而自己通过Poi实现转换的成本又太高,且转换效果不够理想。最终尝试一下,先从Word转换为HTML,然后再从HTML转换为pdf。
虽然转换成功了,但是由于在从word转换给html时使用了ooxml-schema.jar包,此包有十几兆,总依赖仍旧超过30M。最终放弃了此方法。当过程值得记录下来,以供以后参考。
1.Word转换为html
除了poi相关包(我当前使用的4.1.2版本)以外,还需要ooxml-schemas.jar和xdocreport.jar,依赖配置如下:
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>ooxml-schemas</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>fr.opensagres.xdocreport</groupId>
<artifactId>xdocreport</artifactId>
<version>2.0.2</version>
</dependency>
代码实现及注释如下:
/**
* docx文件转html
* 参考: https://wooaooo.com/2022/02/12/Java/POI/java-poi5.2.0-word-to-html/
* @param wordInput word文件输入流。
* @param data 需要填充的数据。
*/
public static String word2007ToHtml(InputStream wordInput, Map<String, String> data)
throws IOException {
// 加载word文档生成 XWPFDocument对象
XWPFDocument document = new XWPFDocument(wordInput);
// 带图片的word,则将图片转为base64编码,保存在一个页面中
XHTMLOptions options = XHTMLOptions.create().indent(3).setImageManager(new Base64EmbedImgManager());
//若设置true,表示外层没有html\head\body标签,设为false,保留html等标签。
options.setFragment(true);
//转换为html
StringWriter writer = new StringWriter();
XHTMLConverter xhtmlConverter = (XHTMLConverter) XHTMLConverter.getInstance();
xhtmlConverter.convert(document, writer, options);
String html = writer.toString();
// 解析html并优化布局
Document doc = Jsoup.parseBodyFragment(html);
//去掉页边距和固定宽度
Elements elements = doc.getElementsByTag("div");
for(Element element : elements){
element.attr("style","line-height:2em;margin-left: 3em; margin-right: 3em;");
}
//设置所有table的样式
Elements tables = doc.getElementsByTag("table");
for (Element table : tables) {
table.attr("style", "border-collapse: collapse;");
}
//文本替换。
html = doc.outerHtml();
for(Map.Entry<String,String> item : data.entrySet()){
html = html.replace(item.getKey(),item.getValue());
}
return html;
}
2.html转换为pdf
需要用到的jar包配置如下:
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext7-core</artifactId>
<version>${itextpdf.version}</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>font-asian</artifactId>
<version>${itextpdf.version}</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>html2pdf</artifactId>
<version>3.0.3</version>
</dependency>
代码实现及注释如下:
/**
* html转换为pdf
* @param html html文本内容
* @param output pdf文件输出
*/
public static void htmlToPdf(String html, OutputStream output) throws IOException {
//转换时参数配置,例如字体,依赖图片等文件路径
ConverterProperties properties = new ConverterProperties();
//必须设置字体,否则转换的pdf文件不显示汉字
FontProvider fp = new FontProvider();
fp.addFont(FontProgramFactory.createFont("STSong-Light"),"UniGB-UCS2-H");
properties.setFontProvider(fp);
//转换
try(PdfDocument pdfDocument = new PdfDocument(new PdfWriter(output))){
//设置pdf页面大小为A4
pdfDocument.setDefaultPageSize(PageSize.A4);
HtmlConverter.convertToPdf(html,pdfDocument,properties);
}
}
3.其他实现word转换pdf的方法
其他实现word转换为pdf的方法可以参考:Java开发中Word转PDF文件5种方案横向评测,我最终选择的是aspose-words,因为其转换效果比较好,依赖包相对比较小,且代码量少。
放弃了通过html转换pdf后,就可以直接通过Word转换为pdf了。需要通过poi-tl.jar来实现word中的数据替换,然后再通过aspose-words.jar转换为pdf。依赖包如下:
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>4.1.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>
<version>1.10.5</version>
</dependency>
<dependency>
<groupId>com.luhuiguo</groupId>
<artifactId>aspose-words</artifactId>
<version>23.1</version>
</dependency>
代码实现相当简单,如下:文章来源:https://www.toymoban.com/news/detail-487308.html
package com.zhengzhaoxi.web.common;
import com.aspose.words.Document;
import com.aspose.words.PdfSaveOptions;
import com.deepoove.poi.XWPFTemplate;
import java.io.*;
import java.util.Map;
/**
* Word工具类
* @author donghx
* @author 2023-06-14
*/
public class WordUtils {
/**
* 填充数据
* @param input 输入word文件数据流
* @param data 需要替换的数据映射
* @param output 输出的word文件数据量
* @throws IOException
*/
public static void fillData(InputStream input, Map<String, Object> data, OutputStream output) throws IOException {
//使用poi-tl.jar中的类填充数据
try(XWPFTemplate template = XWPFTemplate.compile(input) ){
template.render(data).writeAndClose(output);
}catch (Exception ex){
throw ex;
}
}
/**
* word转换为pdf
* @param wordInput word文件输入流
* @param pdfOutput pdf文件输出流
* @throws Exception
*/
public static void wordToPdf(InputStream wordInput, OutputStream pdfOutput) throws Exception {
//通过aspose-words.jar中的类转换文件
Document wordDoc = new Document(wordInput);
if(SystemUtils.isLinux()){
//设置汉字字体,否则转换后的文档汉字会乱码。
FontSettings settings = new FontSettings();
settings.setFontsFolder("/mydata/fonts",false);
wordDoc.setFontSettings(settings);
}
PdfSaveOptions pso = new PdfSaveOptions();
wordDoc.save(pdfOutput, pso);
}
}
在word转换为pdf方法中,必须设置中文字体所在的目录。有两种方法:文章来源地址https://www.toymoban.com/news/detail-487308.html
- 把字体防止在目录/usr/share/fonts/下面,需要使用命令fontconfig 和mkfontscale 配置系统字体。
- 直接把字体复制到指定目录下,并在代码中指定此目录即可,如上面的示例。字体文件可以从Windows操作系统中复制过去。Windows字体目录为:C:\Windows\Fonts
到了这里,关于实现Word转Pdf文件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!