记一次doc、docx转html的过程

本文档详细介绍了如何在Java项目中使用Apache POI和XDocReport库将.doc和.docx文件转换为HTML字符串。重点讲述了处理文档中的图片,包括上传图片到服务器和构建HTML中的图片URL。还提供了关键代码示例,涉及DOC到HTML及DOCX到HTML的转换方法。
摘要由CSDN通过智能技术生成

原因

近期由于项目开发的需求,需要将系统的文件(.doc或者.docx)里面的内容转成html字符串,然后作为请求的参数中body发送出去。
为了实现这个功能,前期踩了很多坑,试错了很多就能勉强实现功能需求。所以怎么也要记录一下,以免自己后续继续踩坑,以及大伙也跳进来。

方案

最开始,在网上搜了很多方案,主要归纳成就是通过三种方式,但是三种方法中都需要引入外部的工具jar包。
最后综合了一下目前所开发的系统内容,决定采用使用POI实现转换。

前期准备

决定使用POI来实现功能,就要找到合适的依赖。在这个过程也是出现很多问题,就是各个依赖包的版本不同,会出现某一类不存在的问题。为了不必要的麻烦,这里直接以poi的版本为4.1.2为准则,其他依赖包来兼容这个版本。

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-scratchpad</artifactId>
    <version>4.1.2</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>4.1.2</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>4.1.2</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml-schemas</artifactId>
    <version>4.1.2</version>
</dependency>
<!--用于docx转html-->
<dependency>
     <groupId>fr.opensagres.xdocreport</groupId>
     <artifactId>fr.opensagres.poi.xwpf.converter.xhtml</artifactId>
     <version>2.0.2</version>
 </dependency>

注意:不要随便改变包的版本,不然就要重新去验证是否兼不兼容、部分类是否缺失。

代码核心部分

这里,只是提出doc/docx转换成html的方法,但是里面的一些额外的函数/方法则只是描述其实现什么功能而已。

/**
 1. 将doc或docx文件转成html字符串
 2. @param ips 文件流
 3. @param fileName 文件名
 4. @param extension 后缀名
 5. @return html字符串
 6.  7. 若文档中存在图片,则需要设置图片的保存目录,以及图片服务器访问路径才能正常使用
 */
private String wordToHtml(InputStream ips, String fileName, String extension){

    File file = null;

    try {
        if (ips == null){
            return "";
        }
        //判断文档为doc或docx,分别进行处理转换
        if (extension.equals(".doc") || extension.equals(".DOC")){
            HWPFDocument wordDocument = new HWPFDocument(ips);
            WordToHtmlConverter wordToHtmlConverter = new WordToHtmlConverter(
                    DocumentBuilderFactory.newInstance().newDocumentBuilder()
                            .newDocument());
            //该部分为doc中的图片操作(如doc中存在图片),可将图片上传服务器和获取图片URL的逻辑放在重写的位置
            //参数说明:savePicture(图片byte, 图片type, 图片名, 图片宽度, 图片高度)
            wordToHtmlConverter.setPicturesManager(new PicturesManager() {
                @Override
                public String savePicture(byte[] content, PictureType pictureType, String suggestedName, float widthInches, float heightInches) {
                    return uploadPicFile(...); //返回的图片URL即为在生成的html文件中图片的src
                }
            });
            wordToHtmlConverter.processDocument(wordDocument);

            Document htmlDocument = wordToHtmlConverter.getDocument();
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            DOMSource domSource = new DOMSource(htmlDocument);
            StreamResult streamResult = new StreamResult(out);
            TransformerFactory tf = TransformerFactory.newInstance();
            //设置转换参数
            Transformer serializer = tf.newTransformer();
            serializer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
            serializer.setOutputProperty(OutputKeys.INDENT, "yes");
            serializer.setOutputProperty(OutputKeys.METHOD, "html");
            serializer.transform(domSource, streamResult);
            String result = new String(out.toByteArray());
            out.close();
            result = result.replaceAll("\\r\\n","<br/>");
            log.info("doc文件转换后的字符串为:{}", result);
            return result;
        }else if (extension.equals(".docx") || extension.equals(".DOCX")){
            file = inputstreamToFile(ips, fileName);

            XWPFDocument document = new XWPFDocument(new FileInputStream(file));
            XHTMLOptions options = XHTMLOptions.create();

            //若文档中存在图片,则将内容设置在option中的ImageManager
            //ImageManager imageManager = new ImageManager(new File(picPath), "");
            options.setIgnoreStylesIfUnused(false);
            options.setFragment(true);
            //options.setImageManager(imageManager); //设置文档内图片储存的位置
            options.setImageManager(new ImageManagerImpl()); //重写ImageManager类,用于构建图片路径

            ByteArrayOutputStream out = new ByteArrayOutputStream();
            XHTMLConverter.getInstance().convert(document, out, options);
            String result = new String(out.toByteArray());

            log.info("docx文件转换后的字符串为:{}", result);
            out.close();
            document.close();
            return result;
        }
    }catch (Exception e){
        log.error("word转html文件出现错误:{}", e);
    }finally {
        FileUtil.del(file);
    }
    return null;
}

代码描述:

  1. 该方法传入的参数有三个:被操作文件的文件流ips文件名fileName文件的后缀extension
  2. 重写的savePicture()方法作用是将doc中的图片构建成在生成的html文件中图片的src的url。
  3. savePicture()的参数说明:savePicture(图片byte, 图片type, 图片名, 图片宽度, 图片高度)
  4. uploadPicFile(…)方法是用来实现将图片的byte数组上传到图片服务器,并组装成一个完整可直接访问的路径返回。具体的实现过程就要根据小伙伴自己的需求做进一步开发了。
  5. 在处理docx文件的时候,由于我这边需要将图片上传到服务器,所以这边是采用重写ImageManager这个类来实现自己的上传逻辑。
/**
 1. 重写ImageManager类,用于docx文档中的图片进行保存和替换访问url到html字符串中
 */
public class ImageManagerImpl extends ImageManager {

    private byte[] picture; //图片的byte数组
    private String fileName; //文件名

    public ImageManagerImpl() {
        super(new File(""), "");
    }

    @Override
    public void extract(String imagePath, byte[] imageData) throws IOException {
        String[] split = imagePath.split("/");
        this.fileName = split[split.length - 1];
        this.picture = imageData;
    }

    @Override
    public String resolve(String uri) {
    	//可使用fileName和picture传入到uploadPicFile()方法中
        return uploadPicFile(...); //此处返回的应该是一个完整且可直接访问的图片url
    }
}
  1. 当然,如果你只想保存到本地的一个路径就要修改成下面的样子,可以看到在处理docx的时候,有注释掉的几行代码:
ImageManager imageManager = new ImageManager(new File(picPath), "");
options.setIgnoreStylesIfUnused(false);
options.setFragment(true);
options.setImageManager(imageManager); //设置文档内图片储存的位置

其中,picPath为图片保存的本地路径。
如果是处理doc文件,则可参考下面的代码

File file = new File("E:\\temp\\ww.doc");
FileInputStream fileInputStream = new FileInputStream(file);
HWPFDocument wordDocument = new HWPFDocument(fileInputStream);
WordToHtmlConverter wordToHtmlConverter = new WordToHtmlConverter(
        DocumentBuilderFactory.newInstance().newDocumentBuilder()
                .newDocument());
wordToHtmlConverter.setPicturesManager(new PicturesManager() {
    @Override
    public String savePicture(byte[] content,PictureType pictureType, String suggestedName,float widthInches, float heightInches) {
        return uploadPicFile(...);
    }
});
wordToHtmlConverter.processDocument(wordDocument);
//获取doc文件中的所有图片,并保存到本地,picPath为本地路径
List pics = wordDocument.getPicturesTable().getAllPictures();
if (pics != null) {
    for (int i = 0; i < pics.size(); i++) {
        Picture pic = (Picture) pics.get(i);
        pic.writeImageContent(new FileOutputStream(new File(picPath + pic.suggestFullFileName())));
    }
}

Document htmlDocument = wordToHtmlConverter.getDocument();
ByteArrayOutputStream out = new ByteArrayOutputStream();
DOMSource domSource = new DOMSource(htmlDocument);
StreamResult streamResult = new StreamResult(out);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer serializer = tf.newTransformer();
serializer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
serializer.setOutputProperty(OutputKeys.INDENT, "yes");
serializer.setOutputProperty(OutputKeys.METHOD, "html");
serializer.transform(domSource, streamResult);
String result = new String(out.toByteArray());
result = result.replaceAll("\\r\\n","<br/>");
out.close();
System.out.println(result);
  1. 在处理docx的时候,需要先将ips转成file,再转成FileInputStream,否则会报错的。
file = inputstreamToFile(ips, fileName);
XWPFDocument document = new XWPFDocument(new FileInputStream(file));

这里也把inputStream转成File的方法也贴出来了。

/**
 1. 将inputStream转成File
 2. @param input 文件的输入流
 3. @param fileName 文件名
 4. @return file
 */
private File inputstreamToFile(InputStream input, String fileName){
    File file = new File("文件保存路径");
    try {
        OutputStream os = new FileOutputStream(file);
        int bytesRead = 0;
        byte[] buffer = new byte[8192];
        while ((bytesRead = input.read(buffer, 0, 8192)) != -1) {
            os.write(buffer, 0, bytesRead);
        }
        os.close();
        input.close();
        return file;
    }catch (Exception e){
        log.error("转换出现错误:",e);
    }
    return file;
}
  1. FileUtil.del(file)这里主要是处理docx的时候转换出来的file,将其删除。
    该工具类是调用hutool的东西。可引入依赖
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.4</version>
</dependency>

最后

目前来说,只是验证了doc/docx文件中存在图片的情况是能够正常生成html字符串的,以及文字的一些样式也能够还原,但是具体像表格这些就没有去验证了。
至于后续功能上线后,遇到的实际问题和解决方法也会在这篇文章进行更新,大伙可以关注收藏一下。

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是哈猿啊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值