page contents

HTML文件怎么转换成Word

html转换为word 实现思路就是先把html中的所有图片元素提取出来,统一替换为变量字符”${imgReplace}“,如果多张图片,可以依序排列下去,之后生成对应的doc文件(之前试过直接生成docx文件发...

attachments-2021-06-FIspwOF760cff8d70ffcb.png

html转换为word

实现思路就是先把html中的所有图片元素提取出来,统一替换为变量字符”${imgReplace}“,如果多张图片,可以依序排列下去,之后生成对应的doc文件(之前试过直接生成docx文件发现打不开,这个问题尚未找到好的解决方法),我们将其另存为docx文件,之后就可以替换变量为图片了:

public static String writeWordFile(String content) {
        String path = "D:/wordFile";
        Map<String, Object> param = new HashMap<String, Object>();

        if (!"".equals(path)) {
            File fileDir = new File(path);
            if (!fileDir.exists()) {
                fileDir.mkdirs();
            }
            content = HtmlUtils.htmlUnescape(content);
            List<HashMap<String, String>> imgs = getImgStr(content);
            int count = 0;
            for (HashMap<String, String> img : imgs) {
                count++;
                //处理替换以“/>”结尾的img标签
                content = content.replace(img.get("img"), "${imgReplace" + count + "}");
                //处理替换以“>”结尾的img标签
                content = content.replace(img.get("img1"), "${imgReplace" + count + "}");
                Map<String, Object> header = new HashMap<String, Object>();

                try {
                    File filePath = new File(ResourceUtils.getURL("classpath:").getPath());
                    String imagePath = filePath.getAbsolutePath() + "\\static\\";
                    imagePath += img.get("src").replaceAll("/", "\\\\");
                    //如果没有宽高属性,默认设置为400*300
                    if(img.get("width") == null || img.get("height") == null) {
                        header.put("width", 400);
                        header.put("height", 300);
                    }else {
                        header.put("width", (int) (Double.parseDouble(img.get("width"))));
                        header.put("height", (int) (Double.parseDouble(img.get("height"))));
                    }
                    header.put("type", "jpg");
                    header.put("content", OfficeUtil.inputStream2ByteArray(new FileInputStream(imagePath), true));
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
                param.put("${imgReplace" + count + "}", header);
            }
            try {
                // 生成doc格式的word文档,需要手动改为docx
                byte by[] = content.getBytes("UTF-8");
                ByteArrayInputStream bais = new ByteArrayInputStream(by);
                POIFSFileSystem poifs = new POIFSFileSystem();
                DirectoryEntry directory = poifs.getRoot();
                DocumentEntry documentEntry = directory.createDocument("WordDocument", bais);
                FileOutputStream ostream = new FileOutputStream("D:\\wordFile\\temp.doc");
                poifs.writeFilesystem(ostream);
                bais.close();
                ostream.close();

                // 临时文件(手动改好的docx文件)
                CustomXWPFDocument doc = OfficeUtil.generateWord(param, "D:\\wordFile\\temp.docx");
                //最终生成的带图片的word文件
                FileOutputStream fopts = new FileOutputStream("D:\\wordFile\\final.docx");
                doc.write(fopts);
                fopts.close();
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
        return "D:/wordFile/final.docx";
    }

    //获取html中的图片元素信息
    public static List<HashMap<String, String>> getImgStr(String htmlStr) {
        List<HashMap<String, String>> pics = new ArrayList<HashMap<String, String>>();

        Document doc = Jsoup.parse(htmlStr);
        Elements imgs = doc.select("img");
        for (Element img : imgs) {
            HashMap<String, String> map = new HashMap<String, String>();
            if(!"".equals(img.attr("width"))) {
                map.put("width", img.attr("width").substring(0, img.attr("width").length() - 2));
            }
            if(!"".equals(img.attr("height"))) {
                map.put("height", img.attr("height").substring(0, img.attr("height").length() - 2));
            }
            map.put("img", img.toString().substring(0, img.toString().length() - 1) + "/>");
            map.put("img1", img.toString());
            map.put("src", img.attr("src"));
            pics.add(map);
        }
        return pics;
    }

OfficeUtil工具类,之前发现网上的写法只支持一张图片的修改,多张图片就会报错,是因为添加了图片,processParagraphs方法中的runs的大小改变了,会报ArrayList的异常,就和我们循环list中删除元素会报异常道理一样,解决方法就是复制一个新的Arraylist进行循环即可:

package com.example.demo.util;  

import java.io.ByteArrayInputStream;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;import java.util.ArrayList;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.Map.Entry;import org.apache.poi.POIXMLDocument;import org.apache.poi.hwpf.extractor.WordExtractor;import org.apache.poi.openxml4j.opc.OPCPackage;import org.apache.poi.xwpf.usermodel.XWPFParagraph;import org.apache.poi.xwpf.usermodel.XWPFRun;import org.apache.poi.xwpf.usermodel.XWPFTable;import org.apache.poi.xwpf.usermodel.XWPFTableCell;import org.apache.poi.xwpf.usermodel.XWPFTableRow;  

/** 
 * 适用于word 2007
 */  public class OfficeUtil {  

    /** 
     * 根据指定的参数值、模板,生成 word 文档 
     * @param param 需要替换的变量 
     * @param template 模板 
     */  
    public static CustomXWPFDocument generateWord(Map<String, Object> param, String template) {  
        CustomXWPFDocument doc = null;        try {  
            OPCPackage pack = POIXMLDocument.openPackage(template);  
            doc = new CustomXWPFDocument(pack);  
            if (param != null && param.size() > 0) {  

                //处理段落  
                List<XWPFParagraph> paragraphList = doc.getParagraphs();  
                processParagraphs(paragraphList, param, doc);  

                //处理表格  
                Iterator<XWPFTable> it = doc.getTablesIterator();  
                while (it.hasNext()) {
                    XWPFTable table = it.next();  
                    List<XWPFTableRow> rows = table.getRows();  
                    for (XWPFTableRow row : rows) {  
                        List<XWPFTableCell> cells = row.getTableCells();  
                        for (XWPFTableCell cell : cells) {  
                            List<XWPFParagraph> paragraphListTable =  cell.getParagraphs();  
                            processParagraphs(paragraphListTable, param, doc);  
                        }  
                    }  
                }  
            }  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return doc;  
    }  
    /** 
     * 处理段落 
     * @param paragraphList 
     */  
    public static void processParagraphs(List<XWPFParagraph> paragraphList,Map<String, Object> param,CustomXWPFDocument doc){  
        if(paragraphList != null && paragraphList.size() > 0){  
            for(XWPFParagraph paragraph:paragraphList){                //poi转换过来的行间距过大,需要手动调整                if(paragraph.getSpacingBefore() >= 1000 || paragraph.getSpacingAfter() > 1000) {
                    paragraph.setSpacingBefore(0);
                    paragraph.setSpacingAfter(0);
                }                //设置word中左右间距
                paragraph.setIndentationLeft(0);
                paragraph.setIndentationRight(0);
                List<XWPFRun> runs = paragraph.getRuns();                //加了图片,修改了paragraph的runs的size,所以循环不能使用runs
                List<XWPFRun> allRuns = new ArrayList<XWPFRun>(runs);                for (XWPFRun run : allRuns) {
                    String text = run.getText(0);  
                    if(text != null){                        boolean isSetText = false;  
                        for (Entry<String, Object> entry : param.entrySet()) {  
                            String key = entry.getKey();  
                            if(text.indexOf(key) != -1){  
                                isSetText = true;  
                                Object value = entry.getValue();  
                                if (value instanceof String) {//文本替换  
                                    text = text.replace(key, value.toString());  
                                } else if (value instanceof Map) {//图片替换  
                                    text = text.replace(key, "");  
                                    Map pic = (Map)value;  
                                    int width = Integer.parseInt(pic.get("width").toString());  
                                    int height = Integer.parseInt(pic.get("height").toString());  
                                    int picType = getPictureType(pic.get("type").toString());  
                                    byte[] byteArray = (byte[]) pic.get("content");  
                                    ByteArrayInputStream byteInputStream = new ByteArrayInputStream(byteArray);  
                                    try {  
                                        String blipId = doc.addPictureData(byteInputStream,picType);  
                                        doc.createPicture(blipId,doc.getNextPicNameNumber(picType), width, height,paragraph);
                                    } catch (Exception e) {  
                                        e.printStackTrace();  
                                    }  
                                }  
                            }  
                        }  
                        if(isSetText){  
                            run.setText(text,0);  
                        }  
                    }  
                }  
            }  
        }  
    }  
    /** 
     * 根据图片类型,取得对应的图片类型代码 
     * @param picType 
     * @return int 
     */  
    private static int getPictureType(String picType){  
        int res = CustomXWPFDocument.PICTURE_TYPE_PICT;  
        if(picType != null){  
            if(picType.equalsIgnoreCase("png")){  
                res = CustomXWPFDocument.PICTURE_TYPE_PNG;  
            }else if(picType.equalsIgnoreCase("dib")){  
                res = CustomXWPFDocument.PICTURE_TYPE_DIB;  
            }else if(picType.equalsIgnoreCase("emf")){  
                res = CustomXWPFDocument.PICTURE_TYPE_EMF;  
            }else if(picType.equalsIgnoreCase("jpg") || picType.equalsIgnoreCase("jpeg")){  
                res = CustomXWPFDocument.PICTURE_TYPE_JPEG;  
            }else if(picType.equalsIgnoreCase("wmf")){  
                res = CustomXWPFDocument.PICTURE_TYPE_WMF;  
            }  
        }  
        return res;  
    }  
    /** 
     * 将输入流中的数据写入字节数组 
     * @param in 
     * @return 
     */  
    public static byte[] inputStream2ByteArray(InputStream in,boolean isClose){  
        byte[] byteArray = null;  
        try {  
            int total = in.available();  
            byteArray = new byte[total];  
            in.read(byteArray);  
        } catch (IOException e) {  
            e.printStackTrace();  
        }finally{  
            if(isClose){  
                try {  
                    in.close();  
                } catch (Exception e2) {  
                    System.out.println("关闭流失败");  
                }  
            }  
        }  
        return byteArray;  
    }  
}

我认为之所以word2003不支持图片替换,主要是处理2003版本的HWPFDocument对象被声明为了final,我们就无法重写他的方法了。而处理2007版本的类为XWPFDocument,是可以继承的,通过继承XWPFDocument,重写createPicture方法即可实现图片替换,以下为对应的CustomXWPFDocument类:

package com.example.demo.util;    

import java.io.IOException;  
import java.io.InputStream;  
import org.apache.poi.openxml4j.opc.OPCPackage;  
import org.apache.poi.xwpf.usermodel.XWPFDocument;  
import org.apache.poi.xwpf.usermodel.XWPFParagraph;  
import org.apache.xmlbeans.XmlException;  
import org.apache.xmlbeans.XmlToken;  
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;  
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;  
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;  

/** 
 * 自定义 XWPFDocument,并重写 createPicture()方法 
 */  public class CustomXWPFDocument extends XWPFDocument {    
    public CustomXWPFDocument(InputStream in) throws IOException {    
        super(in);    
    }    

    public CustomXWPFDocument() {    
        super();    
    }    

    public CustomXWPFDocument(OPCPackage pkg) throws IOException {    
        super(pkg);    
    }    

    /** 
     * @param ind 
     * @param width 宽 
     * @param height 高 
     * @param paragraph  段落 
     */  
    public void createPicture(String blipId, int ind, int width, int height,XWPFParagraph paragraph) {    
        final int EMU = 9525;    
        width *= EMU;    
        height *= EMU;    
        CTInline inline = paragraph.createRun().getCTR().addNewDrawing().addNewInline();    
        String picXml = ""    
                + "<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">"    
                + "   <a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"    
                + "      <pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"    
                + "         <pic:nvPicPr>" + "            <pic:cNvPr id=\""    
                + ind    
                + "\" name=\"Generated\"/>"    
                + "            <pic:cNvPicPr/>"    
                + "         </pic:nvPicPr>"    
                + "         <pic:blipFill>"    
                + "            <a:blip r:embed=\""    
                + blipId    
                + "\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>"    
                + "            <a:stretch>"    
                + "               <a:fillRect/>"    
                + "            </a:stretch>"    
                + "         </pic:blipFill>"    
                + "         <pic:spPr>"    
                + "            <a:xfrm>"    
                + "               <a:off x=\"0\" y=\"0\"/>"    
                + "               <a:ext cx=\""    
                + width    
                + "\" cy=\""    
                + height    
                + "\"/>"    
                + "            </a:xfrm>"    
                + "            <a:prstGeom prst=\"rect\">"    
                + "               <a:avLst/>"    
                + "            </a:prstGeom>"    
                + "         </pic:spPr>"    
                + "      </pic:pic>"    
                + "   </a:graphicData>" + "</a:graphic>";    

        inline.addNewGraphic().addNewGraphicData();    
        XmlToken xmlToken = null;    
        try {    
            xmlToken = XmlToken.Factory.parse(picXml);    
        } catch (XmlException xe) {    
            xe.printStackTrace();    
        }    
        inline.set(xmlToken);   

        inline.setDistT(0);      
        inline.setDistB(0);      
        inline.setDistL(0);      
        inline.setDistR(0);      

        CTPositiveSize2D extent = inline.addNewExtent();    
        extent.setCx(width);    
        extent.setCy(height);    

        CTNonVisualDrawingProps docPr = inline.addNewDocPr();      
        docPr.setId(ind);      
        docPr.setName("图片" + ind);      
        docPr.setDescr("测试");   
    }    
}

更多相关技术内容咨询欢迎前往并持续关注六星社区了解详情。

程序员编程交流QQ群:805358732

如果你想用Python开辟副业赚钱,但不熟悉爬虫与反爬虫技术,没有接单途径,也缺乏兼职经验
关注下方微信公众号:Python编程学习圈,获取价值999元全套Python入门到进阶的学习资料以及教程,还有Python技术交流群一起交流学习哦。

attachments-2022-06-Z2HuDFDs62ac403e8796b.jpeg

0 条评论

请先 登录 后评论
轩辕小不懂
轩辕小不懂

2403 篇文章

作家榜 »

  1. 轩辕小不懂 2403 文章
  2. 小柒 1482 文章
  3. Pack 1135 文章
  4. Nen 576 文章
  5. 王昭君 209 文章
  6. 文双 71 文章
  7. 小威 64 文章
  8. Cara 36 文章