使用忠告
使用该方式进行xhtml到word的转换, 简单转换是可以, 但是可能并没有想象中那么满意, 转换出来的word格式并不完美, 比如目录和标题都会丢失, 标题显示看起来一样, 但是是用正文加粗和加大字号来显示的. 毕竟word是一种文档格式, 而html是一种标记性语言, 要想实现完美兼容和转换很难
加上word与html互转(2) -- html转word, 虽然word与html互转都有实现手段, 但是考虑到转换的格式复杂度和后期的维护成本, 我们最后放弃去实现这个成本高但是对项目影响不大的功能
其中word转html功能实现中, 转出的html的格式并没有想象中的好, 某些样式是通过class样式来显示的, 并不全是行内样式, 并且html所有文本标签都是使用的p标签, 包括标题.
实现
实现方式
我在网上搜集了很多实现方式, 各式各样的, 最后我决定使用poi+xdocreport来实现
poi都熟悉, 这边我不作介绍
xdocreport是github上的一个开源项目, 他的具体介绍可以去他的项目地址查看--项目地址, 选择这个开源项目主要有以下几个原因:
1. 他是开源的(免费)
2项目本身模块化, 我们可以只引用需要的功能(轻量化)
3.转换是基于poi的转换进行补充扩展的,感觉比poi原生的更好一些(emm...没验证)
4.使用简单便捷
这里只使用了xdocreport的转换器功能, 可以点这里直接查看对应的wiki
引入相关程序包
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.14</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>3.14</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.14</version>
</dependency>
<dependency>
<groupId>fr.opensagres.xdocreport</groupId>
<artifactId>fr.opensagres.poi.xwpf.converter.xhtml</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>3.14</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>ooxml-schemas</artifactId>
<version>1.3</version>
</dependency>
docx转html
public static void main(String[] args) {
String fileInName = "test.docx";
XWPFDocument document = null;
try {
document = new XWPFDocument(new FileInputStream(fileInName));
XHTMLOptions options = XHTMLOptions.create();
options.setImageManager( new ImageManager(new File(""), "") {
@Override
public void extract(String imagePath, byte[] imageData) throws IOException {
System.out.println("这里上传图片到图片服务器");
}
@Override
public String resolve(String uri) {
return "https://csdnimg.cn/pubfooter/images/csdn_cs_qr.png";
}
});
StringWriter stringWriter = new StringWriter();
// XHTMLConverter.getInstance().convert( document, out, options );
XHTMLConverter xhtmlConverter = (XHTMLConverter) XHTMLConverter.getInstance();
xhtmlConverter.convert(document, stringWriter, options);
} catch (IOException e) {
e.printStackTrace();
}
}
上面我自己写的示例跟官方的示例有所区别, 下面我贴出官方示例然后在进行解释
/**
* 官方示例
*/
import org.apache.poi.xwpf.converter.xhtml.XHTMLOptions;
import org.apache.poi.xwpf.converter.xhtml.XHTMLConverter;
...
// 1) Load DOCX into XWPFDocument
InputStream in= new FileInputStream(new File("HelloWord.docx"));
XWPFDocument document = new XWPFDocument(in);
// 2) Prepare XHTML options (here we set the `ImageManager` to store image and resolve iamge src)
XHTMLOptions options = XHTMLOptions.create().setImageManager( new ImageManager( new File(root), "images" ) );
// 3) Convert XWPFDocument to XHTML
OutputStream out = new FileOutputStream(new File("HelloWord.htm"));
XHTMLConverter.getInstance().convert(document, out, options);
跟官方不一样的地方的解释
1.在给XHTMLOption设置图片管理器对象的时候
官方是直接设置了一个图片路径, 生成的html里面的图片引用指向的是设 置的路径, 而我这边有专门的文件服务器, 所以需要将里面的图片上传到图片服务器中, 然后将html中图片的引用指向文件服务器, 所以我重写了图片管理器的代码, 将其中保存图片和给html中图片引用换成了自己的实现
XHTMLOptions options = XHTMLOptions.create();
options.setImageManager( new ImageManager(new File(""), "") {
@Override
public void extract(String imagePath, byte[] imageData) throws IOException {
System.out.println("这里上传图片到图片服务器");
}
@Override
public String resolve(String uri) {
return "https://csdnimg.cn/pubfooter/images/csdn_cs_qr.png";
}
});
2.转换并保存html的时候
官方示例是将html保存成文件到一个路径下面, 而我的需求并不是保存文件, 而是要将生成的html分段下沉到DB, 所以可以在这里
StringWriter stringWriter = new StringWriter();
XHTMLConverter xhtmlConverter = (XHTMLConverter) XHTMLConverter.getInstance();
xhtmlConverter.convert(document, stringWriter, options);
将官方示例的文件输出流换成自己的StringWriter就可以了(你也可以换成自己需要的流), 我这样替换就可以拿到html的字符串, 接着就可以使用jsoup进行html的解析并分段存储了
doc转html
public String doc2html() throws Exception {
HWPFDocument hwpfDocument = new HWPFDocument(new FileInputStream("test.doc"));
Document newDocument = XMLHelper.getDocumentBuilderFactory().newDocumentBuilder().newDocument();
WordToHtmlConverter wordToHtmlConverter = new WordToHtmlConverter(newDocument);
wordToHtmlConverter.setPicturesManager((content, pictureType, suggestedName, widthInches, heightInches) -> {
//content是图片内容, 这里将图片保存到图片服务器, 然后将保存的图片路径返回
//同样, 你也可以将图片保存到本地相对路径, 然后将相对路径返回, html也能正常显示图片
return "https://csdnimg.cn/pubfooter/images/csdn_cs_qr.png";
});
wordToHtmlConverter.processDocument(hwpfDocument);
Transformer transformer = TransformerFactory.newInstance()
.newTransformer();
//指定Transformer在输出结果树时是否可以添加额外的空格
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
//指定输出编码
transformer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
transformer.setOutputProperty(OutputKeys.METHOD, "html");
//这里是希望将转换后的流最终输出到字符串进行返回, 如果你希望直接输出文件, 你可以创建一个文件流放进下面的参数
StringWriter stringWriter = new StringWriter();
transformer.transform(new DOMSource(wordToHtmlConverter.getDocument()), new StreamResult(stringWriter));
return stringWriter.toString();
}
示例代码比较简单, 但是已经具备转换的功能, 需要注意和可能变动的点我在代码注释中已经说明, 可以根据需求来修改图片的保存和最后输出的结果