java word转pdf dox4j,使用 docx4j 将 Web 页面转换为 DOCX 与 PDF 格式
一、背景
项目中需要将某数据显示的内容,提供一个下载 DOCX 与 PDF 功能。在分析阶段发现 docx4j(http://www.docx4java.org/trac/docx4j)提供了转换功能。在调试开发时遇到了 HTML 格式兼容,样式丢失,PDF 中文字体等问题。
二、分析
docx4j-ImportXHTML(https://github.com/plutext/docx4j-ImportXHTML),从名称上一看就知道这个只支持 XHTML。如果是非 XHTML 格式,解析就有问题。
所以在样例中使用了jsoup(http://jsoup.org/)将 HTML 统一转换为 XHTML,并去掉不需要的一些内容(如:script)。这时再调用 docx4j-ImportXHTML 就可以正常解析。
注:这种转换不适用于常规 HTML 页面,转换过程中会丢失样式造成混乱。在这里想要做的是一种以特定 HTML 格式编写页面模板转出 DOCX 与 PDF 的方式。
三、样例程序
样例程序中有很多注释,这理就不再深入描述。该程序支持 Linux 环境。
1、主流程
a、jsoup 抓取指定 URL 的内容
b、使用 jsoup 清理内容,转为 XHTML
c、调用 docx4j-ImportXHTML,生成 WordprocessingMLPackage 对象(docx4j)
d、另存为 DOCX 与 PDF
2、POM 文件
这里使用了 Jetty,主要作用是测试时充当假 HTTP 服务器。
直接运行 mvn clean test 就可以看到转换效果。
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
org.noahx
html2docx
1.0.0-SNAPSHOT
org.docx4j
docx4j-ImportXHTML
3.2.2
slf4j-log4j12
org.slf4j
log4j
log4j
org.jsoup
jsoup
1.8.1
org.slf4j
slf4j-simple
1.7.10
test
org.eclipse.jetty
jetty-server
9.2.9.v20150224
test
3、TestHtmlConverter 单元测试类
该类创建模拟 HTTP 服务器,调用转换类将 HTML 内容转换为 DOCX 与 PDF,并调用操作系统打开文件操作。
出于调试目的,日志输出级别为 DEBUG,会产生大量日志。实际运行时可以提高日志级别。
package org.noahx.html2docx;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.slf4j.impl.SimpleLogger;
import java.awt.*;
import java.io.File;
/**
* Created by noah on 3/12/15.
*/
public class TestHtmlConverter {
private static HtmlServer htmlServer = new HtmlServer();
@BeforeClass
public static void before() {
System.setProperty(SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "DEBUG");
htmlServer.start();
}
@AfterClass
public static void after() {
htmlServer.stop();
}
@Test
public void test() throws Exception {
HtmlConverter converter = new HtmlConverter();
String url = "http://127.0.0.1:" + htmlServer.getPort() + "/report.html"; //输入要转换的网址
File fileDocx = converter.saveUrlToDocx(url);
File filePdf = converter.saveUrlToPdf(url);
Desktop.getDesktop().open(fileDocx); //由操作系统打开
Desktop.getDesktop().open(filePdf);
}
}
4、HTML 样本文件(report.html)
样式问题请查看注释。
测试标题
body {
font-family: SimSun;
}
.tb {
border-collapse: collapse;
empty-cells: show;
width: 100%; /*竖版时100%宽度不正确*/
}
.tb th {
text-align: center;
border: 1px solid #000000; /* pdf 输出时边颜色受 color 影响,所以指定 #000000 */
}
.tb td {
border: 1px solid #000000; /* pdf 输出时边颜色受 color 影响,所以指定 #000000 */
}
p {
/*不支持 text-indent 样式,用中文全角空格( ) */
/*text-indent: 2em;*/
}
标题1:大家好
标题2:大家好
标题3:大家好
这是一个中文段落。这是一个中文段落。这是一个中文段落。这是一个中文段落。这是一个中文段落。这是一个中文段落。这是一个中文段落。这是一个中文段落。这是一个中文段落。这是一个中文段落。
a |
第一列 | 第二列 | 第三列 | 第四列 |
---|---|---|---|
abc | efg | efg | efg |
abc | efg | efg | efg |
表1
第一列 | 第二列 | 第三列 | 第四列 |
---|---|---|---|
abc | efg | efg | efg |
abc | efg | efg | efg |
图1
图2
图3
5、主转换程序(HtmlConverter)
package org.noahx.html2docx;
import org.docx4j.Docx4J;
import org.docx4j.convert.in.xhtml.XHTMLImporterImpl;
import org.docx4j.fonts.IdentityPlusMapper;
import org.docx4j.fonts.Mapper;
import org.docx4j.fonts.PhysicalFont;
import org.docx4j.fonts.PhysicalFonts;
import org.docx4j.jaxb.Context;
import org.docx4j.model.structure.PageSizePaper;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.wml.RFonts;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Entities;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.OutputStream;
import java.net.URL;
/**
* Created by noah on 3/10/15.
*/
public class HtmlConverter {
/**
* 输出文件名
*/
public final String OUT_FILENAME = "OUT_ConvertInXHTMLURL";
private final Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 将页面保存为 docx
*
* @param url
* @return
* @throws Exception
*/
public File saveUrlToDocx(String url) throws Exception {
return saveDocx(url2word(url));
}
/**
* 将页面保存为 pdf
*
* @param url
* @return
* @throws Exception
*/
public File saveUrlToPdf(String url) throws Exception {
return savePdf(url2word(url));
}
/**
* 将页面转为 {@link org.docx4j.openpackaging.packages.WordprocessingMLPackage}
*
* @param url
* @return
* @throws Exception
*/
public WordprocessingMLPackage url2word(String url) throws Exception {
return xhtml2word(url2xhtml(url));
}
/**
* 将 {@link org.docx4j.openpackaging.packages.WordprocessingMLPackage} 存为 docx
*
* @param wordMLPackage
* @return
* @throws Exception
*/
public File saveDocx(WordprocessingMLPackage wordMLPackage) throws Exception {
File file = new File(genFilePath() + ".docx");
wordMLPackage.save(file); //保存到 docx 文件
if (logger.isDebugEnabled()) {
logger.debug("Save to [.docx]: {}", file.getAbsolutePath());
}
return file;
}
/**
* 将 {@link org.docx4j.openpackaging.packages.WordprocessingMLPackage} 存为 pdf
*
* @param wordMLPackage
* @return
* @throws Exception
*/
public File savePdf(WordprocessingMLPackage wordMLPackage) throws Exception {
File file = new File(genFilePath() + ".pdf");
OutputStream os = new java.io.FileOutputStream(file);
Docx4J.toPDF(wordMLPackage, os);
os.flush();
os.close();
if (logger.isDebugEnabled()) {
logger.debug("Save to [.pdf]: {}", file.getAbsolutePath());
}
return file;
}
/**
* 将 {@link org.jsoup.nodes.Document} 对象转为 {@link org.docx4j.openpackaging.packages.WordprocessingMLPackage}
* xhtml to word
*
* @param doc
* @return
* @throws Exception
*/
protected WordprocessingMLPackage xhtml2word(Document doc) throws Exception {
WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage(PageSizePaper.valueOf("A4"), true); //A4纸,//横版:true
configSimSunFont(wordMLPackage); //配置中文字体
XHTMLImporterImpl xhtmlImporter = new XHTMLImporterImpl(wordMLPackage);
wordMLPackage.getMainDocumentPart().getContent().addAll( //导入 xhtml
xhtmlImporter.convert(doc.html(), doc.baseUri()));
return wordMLPackage;
}
/**
* 将页面转为{@link org.jsoup.nodes.Document}对象,xhtml 格式
*
* @param url
* @return
* @throws Exception
*/
protected Document url2xhtml(String url) throws Exception {
Document doc = Jsoup.connect(url).get(); //获得
if (logger.isDebugEnabled()) {
logger.debug("baseUri: {}", doc.baseUri());
}
for (Element script : doc.getElementsByTag("script")) { //除去所有 script
script.remove();
}
for (Element a : doc.getElementsByTag("a")) { //除去 a 的 onclick,href 属性
a.removeAttr("onclick");
a.removeAttr("href");
}
Elements links = doc.getElementsByTag("link"); //将link中的地址替换为绝对地址
for (Element element : links) {
String href = element.absUrl("href");
if (logger.isDebugEnabled()) {
logger.debug("href: {} -> {}", element.attr("href"), href);
}
element.attr("href", href);
}
doc.outputSettings()
.syntax(Document.OutputSettings.Syntax.xml)
.escapeMode(Entities.EscapeMode.xhtml); //转为 xhtml 格式
if (logger.isDebugEnabled()) {
String[] split = doc.html().split("\n");
for (int c = 0; c < split.length; c++) {
logger.debug("line {}:\t{}", c + 1, split[c]);
}
}
return doc;
}
/**
* 为 {@link org.docx4j.openpackaging.packages.WordprocessingMLPackage} 配置中文字体
*
* @param wordMLPackage
* @throws Exception
*/
protected void configSimSunFont(WordprocessingMLPackage wordMLPackage) throws Exception {
Mapper fontMapper = new IdentityPlusMapper();
wordMLPackage.setFontMapper(fontMapper);
String fontFamily = "SimSun";
URL simsunUrl = this.getClass().getResource("/org/noahx/html2docx/simsun.ttc"); //加载字体文件(解决linux环境下无中文字体问题)
PhysicalFonts.addPhysicalFont(fontFamily, simsunUrl);
PhysicalFont simsunFont = PhysicalFonts.get(fontFamily);
fontMapper.put(fontFamily, simsunFont);
RFonts rfonts = Context.getWmlObjectFactory().createRFonts(); //设置文件默认字体
rfonts.setAsciiTheme(null);
rfonts.setAscii(fontFamily);
wordMLPackage.getMainDocumentPart().getPropertyResolver()
.getDocumentDefaultRPr().setRFonts(rfonts);
}
/**
* 生成文件位置
*
* @return
*/
protected String genFilePath() {
return System.getProperty("user.dir") + "/" + OUT_FILENAME;
}
}
四、转换效果
1、DOCX转换效果
2、PDF转换效果
五、源码下载
java word转pdf dox4j,使用 docx4j 将 Web 页面转换为 DOCX 与 PDF 格式相关推荐
- flyingsaucer转换多个html,java - 使用FlyingSaucer将包含阿拉伯字符的HTML页面转换为PDF - 堆栈内存溢出...
我想使用FlyingSaucer将包含阿拉伯字符的HTML页面转换为PDF文件,但生成的PDF不包含组合字符并向后打印输出. HTML: جميع الحقوق Java摘录: String inpu ...
- Word中的图片保存为无损图,转换为高质量pdf(无压缩)
首先确保图片经过压缩后,在Word中如何保证图片导入后分辨率不降低 教程:https://jingyan.baidu.com/article/fdffd1f8ef5effb3e98ca180.html ...
- 方便、免费的PDF在线处理网站汇总:PDF合并、文字编辑、页面提取与删除、格式转换…
本文介绍几个方便.免费.好用的PDF在线处理网站. 在工作与学习过程中,经常会需要对PDF进行一些基本处理,例如文件合并.文件格式转换.页面顺序修改等等:尽管这些需求可以通过许多成熟的PDF处 ...
- java 高德地图路线规划_高德地图 web 页面里的出行路线规划
高德地图的引入,有两种方式,第一种在引入链接里直接添加 plugin 参数: 第二种是引入链接里不添加 plugin 参数,而是在在使用插件之前,使用AMap.service方法加载插件,然后在回调 ...
- drawboard pdf拆分文件_PDF处理神器,几秒钟搞定格式转换+压缩+加水印+解密!
PDF对于一个科研学习/工作者来说几乎每天都会接触,尤其是PDF格式转换的时候不知道怎么办,还有些文件加密了只能看不能编辑,有些几十页甚至几百页的文件每次翻看起来都特别麻烦,想防盗给自己的pdf文件加 ...
- java 采集 cms_开源 java CMS - FreeCMS2.6 Web页面信息采集
java开源论坛系统http://javabbs.javaz.cn Web页面信息采集 从FreeCMS 2.1开始支持 通过简单配置即可抓取目标网页信息,支持增量式采集.关键字替换.定时采集,同一采 ...
- java word转pdf,docx4j转pdf,docx4j导出pdf乱码,docx4j导出pdf丢失插画和图片,aspose将word转pdf 一共两种方法
前言:一共有docx4j转pdf,aspose转pdf两种方式,不需要设置模板!!! java转pdf目前本人使用有两种方法,下面是方法代码 ps:因为本人是云桌面开发,所以只作截图,具体代码需要自己 ...
- java word转pdf三种方法(附有需要的jar)
一.jacob 1.jar下载 jacob.jar和jacob-1.17-x64.dll下载 提取码:0121 2.在jdk/bin目录下引入.dll文件(64位:jacob-1.17-x64.dll ...
- java word转pdf linux_Linux平台中使用PHP把word转pdf的实现方法
Linux平台中使用PHP把word转pdf的实现方法 1.ubantu下安装libreoffice sudo apt-get install libreoffice 2.命令行执行word转pdf ...
- java word转pdf_java里实现Word转PDF的几种方案
一.libreOffice 与openOffice类似,但比openOffice稳定. 优点:样式稳定 缺点:性能较差 调用方式:windows:1 2 3 4 5 6 7 8 9 10 11 12 ...
最新文章
- 简述nodejs、npm及其模块在windows下的安装与配置
- 如何修改 远程桌面的 默认端口号 3389
- 一键安装GitLab7在RHEL6.4上
- CentOS6.4 利用sendEmail发邮件
- 根据ip查经纬度软件_f.lux - 必须推荐给大家的开源免费的护眼软件
- SpringCloud 应用在 Kubernetes 上的最佳实践 — 部署篇(开发部署)
- 搜索2.0:利用用户点击记录改善搜索结果
- 光学模拟 Android,基于Android平台的光学字符识别应用的设计与实现
- mysql 字段操作
- linux下eclipse进行ndk调试,超简单,写的超清晰
- 离线语音识别技术品鉴——功能不同各有千秋
- Sengled Snap带摄像头的智能灯泡
- CentOS7中rpm,yum软件安装命令
- win10电脑切换窗口输入法总是变换怎么办?
- 【总结】浪潮杯第七届ACM山东省省赛山师场总结
- 暴雪即将公布《暗黑破坏神3》新职业
- containsAll和contains
- Android GMS认证项总结
- Blender雕刻模块:如何在雕刻过程中无缝合并物体
- 字节跳动的真实工作体验