快捷搜索:

使用POI将Word转为HTML时关于图片的处理

需求

之前发过一篇博客记录使用POI将Word文档转为HTML文件的方法. 最近在将那个方法整合为项目中能用的接口,但在实际操作中发现了一些问题. 由于我的需求是将试卷上传,将其内容转为HTML后按照题号进行分割再存入数据库,所以对于试题中的图片部分,要像之前项目中一样上传到我们的云服务器上,图片的src里也是一个url. 这样一来,必须要实现对img中的src替换,将网上其他例子中的通过File对象获取的路径替换为一个url.

实现

doc文档 先把全部代码贴上来

public File docToHtml(File docFile) {
        String htmlPath=docFile.getAbsolutePath().replaceAll(docFile.getName(),"")+docFile.getName().replaceAll(".doc",".html");
        OutputStreamWriter outputStreamWriter = null;
        if(!docFile.exists()){
            System.out.println("文件不存在");
        }else try {
            //加载word文档生成XWPF对象
            InputStream in = new FileInputStream(docFile);
            HWPFDocument doc=new HWPFDocument(in);
            org.w3c.dom.Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
            WordToHtmlConverter wordToHtmlConverter=new WordToHtmlConverter(document);
            //保存图片,并返回图片的相对路径
            //将图片上传,调用上传的方法
            wordToHtmlConverter.setPicturesManager((content, pictureType, name, width, height) -> {
                Map<String, String> gatewayConfig = fileConfig.getGatewayConfig(fileConfig.getGateway());
                String bucketName = gatewayConfig.get("bucketName");
                String imgName=System.currentTimeMillis() + "_"+name;

                try {
                    String hash = qiniuFileManager.uploadali(content,imgName, bucketName);//bucketName参数无用
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return gatewayConfig.get("alilink") + "/" + imgName;
            });
            wordToHtmlConverter.processDocument(doc);
            org.w3c.dom.Document htmlDocument = wordToHtmlConverter.getDocument();
            DOMSource domSource = new DOMSource(htmlDocument);
            StreamResult streamResult = new StreamResult(new File(htmlPath));
            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);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (TransformerConfigurationException e) {
            e.printStackTrace();
        } catch (TransformerException e) {
            e.printStackTrace();
        }

        return new File(htmlPath);
    }

对图片src的处理是wordToHtmlConverter的setPicturesManager方法,该方法的参数是

public void setPicturesManager(PicturesManager fileManager) {
        this.picturesManager = fileManager;
    }

一个PicturesManager接口,于是对该接口中的

String savePicture(byte[] var1, PictureType var2, String var3, float var4, float var5);

这个方法进行重写即可实现对src的修改,该接口中的方法的参数分别是:

byte[] var1, PictureType var2, String var3, float var4, float var5
图片byte,图片type,图片名,图片宽度,图片高度

所以在实现过程中,我将图片上传到云服务器和获取图片url的方法写在了这里

wordToHtmlConverter.setPicturesManager((content, pictureType, name, width, height) -> {
				//获取上传配置
                Map<String, String> gatewayConfig = fileConfig.getGatewayConfig(fileConfig.getGateway());
                String bucketName = gatewayConfig.get("bucketName");
                String imgName=System.currentTimeMillis() + "_"+name;//设置图片文件名

                try {
                	//上传图片
                    String hash = qiniuFileManager.uploadali(content,imgName, bucketName);//bucketName参数无用
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return gatewayConfig.get("alilink") + "/" + imgName;//获取图片url
            });

这样重写完成之后,调用该方法,生成的html文件中图片的src就是上传之后的url了 效果:

docx文档 对于docx文档的处理废了一些功夫,因为不像doc一样对于图片的处理的类是直接在converter里面的,而是在XHTMLOptions中的,对于图片的处理则是封装在options.setExtractor中的,所以找到可以重写的接口废了一段时间,最后还是论坛的朋友提供了方法. 这里贴一下帖子地址: 之前我考虑去写一个类继承ImageManager,但是论坛的朋友提出重写IURIResolver接口,实测可以. 源代码:

@Override
    public File docxToHtml(File docxFile) {
        String htmlPath=docxFile.getAbsolutePath().replaceAll(docxFile.getName(),"")+docxFile.getName().replaceAll(".docx",".html");
        String imagePath=docxFile.getAbsolutePath().replaceAll(docxFile.getName(),"")+"docxImage\";
        File imageFile=new File(imagePath);
        if(!docxFile.exists()){
            System.out.println("文件不存在!");
        }
        Map<String, String> gatewayConfig = fileConfig.getGatewayConfig(fileConfig.getGateway());
        String bucketName = gatewayConfig.get("bucketName");

        try {
            InputStream in=new FileInputStream(docxFile);
            XWPFDocument document=new XWPFDocument(in);
            //存储图片
            XHTMLOptions options=XHTMLOptions.create().URIResolver(new FileURIResolver(imageFile));
            options.setExtractor(new FileImageExtractor(imageFile));
            options.URIResolver((uri)->{
                File imgFile=new File(imagePath+uri);//获取图片
                String imgName=System.currentTimeMillis() + "_"+imgFile.getName();//设置图片文件名
                InputStream is= null;
                try {
                    is = new FileInputStream(imgFile);
                    byte[] isbyte=new byte[is.available()];
                    is.read(isbyte);
                    //上传图片
                    String hash = qiniuFileManager.uploadali(isbyte,imgName, bucketName);//bucketName参数无用
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return gatewayConfig.get("alilink") + "/" + imgName;//返回图片url
            });
            OutputStream out=new FileOutputStream(htmlPath);
            XHTMLConverter converter=new XHTMLConverter();
            converter.convert(document,out,options);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new File(htmlPath);
    }

大体上传过程与doc的类似 docx的方法是在options.URIResolver这个方法中,这个方法的参数是

public XHTMLOptions URIResolver(IURIResolver resolver) {
        this.resolver = resolver;
        return this;
    }

IURIResolver接口的resolve方法即根据参数uri返回uri,所以重写这个方法即可.

public interface IURIResolver {
    String resolve(String var1);
}

所以我按照上方贴的源代码重写了这个方法,

options.URIResolver((uri)->{
                File imgFile=new File(imagePath+uri);
                String imgName=System.currentTimeMillis() + "_"+imgFile.getName();
                InputStream is= null;
                try {
                    is = new FileInputStream(imgFile);
                    byte[] isbyte=new byte[is.available()];
                    is.read(isbyte);
                    String hash = qiniuFileManager.uploadali(isbyte,imgName, bucketName);//bucketName参数无用
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return gatewayConfig.get("alilink") + "/" + imgName;
            });

参数uri是图片在本地缓存的相对路径,根据路径得到图片文件,然后将File转为byte[],调用上传接口,最后返回上传之后的url.就能达到和doc同样的效果,这里就不再贴图了

再次感谢论坛回复我的那位朋友!

经验分享 程序员 微信小程序 职场和发展