记录:读取Word将内容原样渲染到html

一个需求:要求用户选择一个Word,能够自动读取Word里的内容,将内容以及格式原封不动的渲染到富文本编辑器里,作为草稿,用以发布。

t01f0a0554d8ee5643a.jpg 附赠壁纸一张

小弟菜鸡儿,挠头半天不得,幸得一老哥支持,分享一套代码,开始分析:

  • 引入得包
package com.itmake.tools.word;

import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.converter.WordToHtmlConverter;
import org.apache.poi.xwpf.converter.xhtml.XHTMLConverter;
import org.apache.poi.xwpf.converter.xhtml.XHTMLOptions;
import org.apache.poi.xwpf.usermodel.XWPFDocument;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
复制代码
  • 引入得依赖
<dependency>
    <groupId>fr.opensagres.xdocreport</groupId>
    <artifactId>fr.opensagres.xdocreport.document</artifactId>
    <version>1.0.5</version>
</dependency>
<dependency>
    <groupId>fr.opensagres.xdocreport</groupId>
    <artifactId>org.apache.poi.xwpf.converter.xhtml</artifactId>
    <version>1.0.5</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>3.12</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-scratchpad</artifactId>
    <version>3.12</version>
</dependency>
复制代码
  • 逻辑代码(转换".docx"格式Word)
/**
 * docx(2007版本word) 转换成 html
 *
 * @param docxIs docx 文件输入流
 * @return 转换成的 html 代码
 * @throws IOException 异常
 */
public String docxToHtml(InputStream docxIs) throws IOException {
        Map<String, String> image = new HashMap<>();
        // 转换参数设置
        XHTMLOptions options = XHTMLOptions.create();
        // 保存图片数据,并进行 base64 编码
        options.setExtractor((s, bytes) -> image.put(s, BASE64_IMAGE_PREFIX + Base64.getEncoder().encodeToString(bytes)));
        // 设置图片路径,这里替换为 base64 字符
        options.URIResolver(image::get);
        options.setIgnoreStylesIfUnused(false);
        options.setFragment(true);
        // 加载 word 文档生成 XWPFDocument对象
        XWPFDocument document = new XWPFDocument(docxIs);
        // 用于读取转换后的数据
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        // 转换 word
        XHTMLConverter.getInstance().convert(document, byteArrayOutputStream, options);
        String content = byteArrayOutputStream.toString();
        // 关闭流
        byteArrayOutputStream.close();
        // 替换图片数据
//        for (Map.Entry<String, String> entry : image.entrySet()) {
//            content = content.replace(entry.getKey(), BASE64_IMAGE_PREFIX + entry.getValue());
//        }
        return content;
    }
复制代码

此处是将".docx"格式得Word文档转换为html渲染

首先第一步转换参数设置: 在这里可以将XHTMLOptions理解为一个容器,create方法是创建了一个实例,然后setExtractor可以理解为一个图片转换器,后面几个set没去具体探究,只是理解为给这个转换器设置格式的,到时候直接按要求填充参数就好。

new XWPFDocument 是创建了一个".docx"文件的实例,参数是InputStream格式,也就是读取出来的文档流数据。

XHTMLConverter.getInstance().convert(document, byteArrayOutputStream, options)是正儿八经的转换器,getInstance获取到转换器工厂,convert获取到转换器实例,转换器的三个参数:document:拿到的word文档加载到的doc对象(前端不是也分什么doc、dom对象吗,我感觉是类似这样的,我不太懂哈);byteArrayOutputStream:读取到的内容要放到这个字节数组流里;options:按照这个设置好的格式往里面写(这是我简单粗暴的理解); 之后关闭流,直接返回byteArrayOutputStream.tosTring的字符串,自动渲染就好了。

这里面代码原作老哥做了一个修改:原先是下面被我注释掉的替换图片数据的部分,后面修改成了这行代码:

// 设置图片路径,这里替换为 base64 字符
options.URIResolver(image::get);
复制代码

先说下面for循环:前面在options.setExtracto的时候是已经设置好了对图片的处理,emmm就是在转换器转换的时候会把img标签的图片put进去了(具体什么原理我不懂哈,知道是这样的就行,有心的可以去瞅一下源码),然后entrySet或拿到所有图片信息,返回一个视图,在for里面遍历,通过replace将准备返回的字符串里面的img全部替换调,前面设置的格式是将图片直接转换成了Base64,这个格式可以在img标签里直接渲染成图片。这样就能够保证把word里面的图片也同步转换过去。

这时候小弟提了一个问题:提取出来的set有序吗,怎么保证能够原位替换,而不会错位呢?老哥回答说:概率极小,不考虑这回事。然后我去看了一下:

QQ图片20220122113808.png

QQ图片20220122113854.png 真相大白,返回的是linkset,有序,并且里面生成的KEY是按照自己的规则生成的一个唯一对应的KEY,所以不需要担心,错位,哦豁。

但是因为这个问题呢,老哥去重新修改了一下代码:就是上面的修改options.URIResolver(image::get);

········(午休结束,继续)

在这里,老哥直接设置了图片路径,(说实话,老弟儿不懂这个方法,也没去看,单纯靠自己理解噢,希望你们别被误导)Extractor已经将图片转换为Base64,通过URIResolver方法,又把Base64给img标签设置进去,这时候的操作对象应该是面对整个doc的,一一对应,所以不会存在替换失败的问题。(老哥反应好快啊)

这样呢,也解决了图片渲染的问题。

  • 逻辑代码(转换".doc"格式Word)
/**
 * doc(2003版本word) 转换成 html
 *
 * @param docIs doc 文件输入流
 * @return 转换成的 html 代码
 * @throws IOException 异常
 */
public static String docToHtml(InputStream docIs) throws IOException, ParserConfigurationException, TransformerException {
    // 构建文档对象
    HWPFDocument wordDocument = new HWPFDocument(docIs);
    WordToHtmlConverter wordToHtmlConverter = new WordToHtmlConverter(DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument());
    // 保存图片数据,并进行 base64 编码
    wordToHtmlConverter.setPicturesManager((content, pictureType, suggestedName, widthInches, heightInches) ->
            BASE64_IMAGE_PREFIX + Base64.getEncoder().encodeToString(content));
    wordToHtmlConverter.processDocument(wordDocument);
    // 解析word文档
    Transformer serializer = TransformerFactory.newInstance().newTransformer();
    serializer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
    serializer.setOutputProperty(OutputKeys.INDENT, "yes");
    serializer.setOutputProperty(OutputKeys.METHOD, "html");
    // 用于读取转换后的数据
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    // 转换 word
    serializer.transform(new DOMSource(wordToHtmlConverter.getDocument()), new StreamResult(byteArrayOutputStream));
    // 关闭流
    byteArrayOutputStream.close();
    return byteArrayOutputStream.toString();
}
复制代码

这里和上面的区别在于转换器工厂改变了。这里通过new HWPFDocument(docIs)获取到DOC对象,然后DocumentBuilderFactory.newInstance()获取转换器工厂对象,newDocumentBuilder()获取到转换器对象,最终由newDocument()返回一个Document类型,WordToHtmlConverter参数是Document类型。setPicturesManager可以理解为一个图片转换器插件,这里的几个set也是在设置格式。Transformer也是一种格式的转换器

image.png 这个转换器老弟儿就没有细看了,只知道是转换器哈。最终也是写入到byteArrayOutputStream里,然后返回字符串。

PS:补几张图

image.png

image.png

因为目前环境有点问题,还无法判断是否能够将图片渲染到富文本编辑器,但是字体样式是可以的。 (环境问题为拉取不到nacos服务里的配置信息,一直提示访问超时,但是网站可以正常访问,配置文件也是bootstrap.yml,隔壁同事帮我搞了半天,也还是不行,网络问题,目前还没解决~~~)

第一次写文,感觉还是思路没有整理清楚,一些东西也没有细究是个什么玩意儿,思维存在混乱~~~继续学习吧!

注明:代码出自群里老哥之手,链接:gitee.com/amjacks/top…

同时欢迎进入老哥群聊一起技术探讨,企鹅群:673318747

おすすめ

転載: juejin.im/post/7056574077313482765