前段时间调研POI和docx4j对word的操作,结合网上其他大佬的代码,自己补充写了并整合HTML转word的相关的公用方法。

用到的jar包
‘org.docx4j:docx4j:6.0.1’,
‘org.docx4j:xhtmlrenderer:3.0.0’,
‘org.docx4j:xmlgraphics-commons:2.3’,
‘org.docx4j:docx4j-ImportXHTML:6.0.1’,

import org.apache.commons.lang.StringUtils;
import org.docx4j.convert.in.xhtml.XHTMLImporterImpl;
import org.docx4j.jaxb.Context;
import org.docx4j.model.structure.PageSizePaper;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.wml.*;
import org.jsoup.Jsoup;
import org.jsoup.select.Elements;

import javax.xml.bind.JAXBElement;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by Administrator on 2019/9/3.
 */
public class Docx4jWord {

    private WordprocessingMLPackage wordMLPackage = null;
    private MainDocumentPart mp = null;
    private ObjectFactory factory = null;

    private Docx4jWord(WordprocessingMLPackage wordMLPackage) {
        this.wordMLPackage = wordMLPackage;
        this.mp = wordMLPackage.getMainDocumentPart();
        this.factory = Context.getWmlObjectFactory();
    }

    public static Docx4jWord createWord() throws Exception {
        WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage();
        return new Docx4jWord(wordMLPackage);
    }

    public static Docx4jWord createWord(PageSizePaper pageSizePaper, Boolean formatType) throws Exception {
        WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage(pageSizePaper, formatType);
        return new Docx4jWord(wordMLPackage);
    }

    public WordprocessingMLPackage getWordMLPackage() {
        return wordMLPackage;
    }

    public MainDocumentPart getMp() {
        return mp;
    }

    public void setMp(MainDocumentPart mp) {
        this.mp = mp;
    }

    public ObjectFactory getFactory() {
        return factory;
    }

    public void setFactory(ObjectFactory factory) {
        this.factory = factory;
    }


    //以下为生成Word通用方法/

    /**
     * 解决解析html里不识别 
     *
     * @param html
     * @return
     * @throws Exception
     */
public String setHTMLHead(String html) throws Exception {
        html = "<!DOCTYPE html [<!ENTITY nbsp \"&#160;\"><!ENTITY iexcl \"&#161;\"><!ENTITY cent \"&#162;\"><!ENTITY pound \"&#163;\"><!ENTITY curren \"&#164;\"><!ENTITY yen \"&#165;\"><!ENTITY brvbar \"&#166;\"><!ENTITY sect \"&#167;\"><!ENTITY uml \"&#168;\"><!ENTITY copy \"&#169;\"><!ENTITY ordf \"&#170;\"><!ENTITY laquo \"&#171;\"><!ENTITY not \"&#172;\"><!ENTITY shy \"&#173;\"><!ENTITY reg \"&#174;\"><!ENTITY macr \"&#175;\"><!ENTITY deg \"&#176;\"><!ENTITY plusmn \"&#177;\"><!ENTITY sup2 \"&#178;\"><!ENTITY sup3 \"&#179;\"><!ENTITY acute \"&#180;\"><!ENTITY micro \"&#181;\"><!ENTITY para \"&#182;\"><!ENTITY middot \"&#183;\"><!ENTITY cedil \"&#184;\"><!ENTITY sup1 \"&#185;\"><!ENTITY ordm \"&#186;\"><!ENTITY raquo \"&#187;\"><!ENTITY frac14 \"&#188;\"><!ENTITY frac12 \"&#189;\"><!ENTITY frac34 \"&#190;\"><!ENTITY iquest \"&#191;\"><!ENTITY Agrave \"&#192;\"><!ENTITY Aacute \"&#193;\"><!ENTITY Acirc \"&#194;\"><!ENTITY Atilde \"&#195;\"><!ENTITY Auml \"&#196;\"><!ENTITY Aring \"&#197;\"><!ENTITY AElig \"&#198;\"><!ENTITY Ccedil \"&#199;\"><!ENTITY Egrave \"&#200;\"><!ENTITY Eacute \"&#201;\"><!ENTITY Ecirc \"&#202;\"><!ENTITY Euml \"&#203;\"><!ENTITY Igrave \"&#204;\"><!ENTITY Iacute \"&#205;\"><!ENTITY Icirc \"&#206;\"><!ENTITY Iuml \"&#207;\"><!ENTITY ETH \"&#208;\"><!ENTITY Ntilde \"&#209;\"><!ENTITY Ograve \"&#210;\"><!ENTITY Oacute \"&#211;\"><!ENTITY Ocirc \"&#212;\"><!ENTITY Otilde \"&#213;\"><!ENTITY Ouml \"&#214;\"><!ENTITY times \"&#215;\"><!ENTITY Oslash \"&#216;\"><!ENTITY Ugrave \"&#217;\"><!ENTITY Uacute \"&#218;\"><!ENTITY Ucirc \"&#219;\"><!ENTITY Uuml \"&#220;\"><!ENTITY Yacute \"&#221;\"><!ENTITY THORN \"&#222;\"><!ENTITY szlig \"&#223;\"><!ENTITY agrave \"&#224;\"><!ENTITY aacute \"&#225;\"><!ENTITY acirc \"&#226;\"><!ENTITY atilde \"&#227;\"><!ENTITY auml \"&#228;\"><!ENTITY aring \"&#229;\"><!ENTITY aelig \"&#230;\"><!ENTITY ccedil \"&#231;\"><!ENTITY egrave \"&#232;\"><!ENTITY eacute \"&#233;\"><!ENTITY ecirc \"&#234;\"><!ENTITY euml \"&#235;\"><!ENTITY igrave \"&#236;\"><!ENTITY iacute \"&#237;\"><!ENTITY icirc \"&#238;\"><!ENTITY iuml \"&#239;\"><!ENTITY eth \"&#240;\"><!ENTITY ntilde \"&#241;\"><!ENTITY ograve \"&#242;\"><!ENTITY oacute \"&#243;\"><!ENTITY ocirc \"&#244;\"><!ENTITY otilde \"&#245;\"><!ENTITY ouml \"&#246;\"><!ENTITY divide \"&#247;\"><!ENTITY oslash \"&#248;\"><!ENTITY ugrave \"&#249;\"><!ENTITY uacute \"&#250;\"><!ENTITY ucirc \"&#251;\"><!ENTITY uuml \"&#252;\"><!ENTITY yacute \"&#253;\"><!ENTITY thorn \"&#254;\"><!ENTITY yuml \"&#255;\"><!ENTITY fnof \"&#402;\"><!ENTITY Alpha \"&#913;\"><!ENTITY Beta \"&#914;\"><!ENTITY Gamma \"&#915;\"><!ENTITY Delta \"&#916;\"><!ENTITY Epsilon \"&#917;\"><!ENTITY Zeta \"&#918;\"><!ENTITY Eta \"&#919;\"><!ENTITY Theta \"&#920;\"><!ENTITY Iota \"&#921;\"><!ENTITY Kappa \"&#922;\"><!ENTITY Lambda \"&#923;\"><!ENTITY Mu \"&#924;\"><!ENTITY Nu \"&#925;\"><!ENTITY Xi \"&#926;\"><!ENTITY Omicron \"&#927;\"><!ENTITY Pi \"&#928;\"><!ENTITY Rho \"&#929;\"><!ENTITY Sigma \"&#931;\"><!ENTITY Tau \"&#932;\"><!ENTITY Upsilon \"&#933;\"><!ENTITY Phi \"&#934;\"><!ENTITY Chi \"&#935;\"><!ENTITY Psi \"&#936;\"><!ENTITY Omega \"&#937;\"><!ENTITY alpha \"&#945;\"><!ENTITY beta \"&#946;\"><!ENTITY gamma \"&#947;\"><!ENTITY delta \"&#948;\"><!ENTITY epsilon \"&#949;\"><!ENTITY zeta \"&#950;\"><!ENTITY eta \"&#951;\"><!ENTITY theta \"&#952;\"><!ENTITY iota \"&#953;\"><!ENTITY kappa \"&#954;\"><!ENTITY lambda \"&#955;\"><!ENTITY mu \"&#956;\"><!ENTITY nu \"&#957;\"><!ENTITY xi \"&#958;\"><!ENTITY omicron \"&#959;\"><!ENTITY pi \"&#960;\"><!ENTITY rho \"&#961;\"><!ENTITY sigmaf \"&#962;\"><!ENTITY sigma \"&#963;\"><!ENTITY tau \"&#964;\"><!ENTITY upsilon \"&#965;\"><!ENTITY phi \"&#966;\"><!ENTITY chi \"&#967;\"><!ENTITY psi \"&#968;\"><!ENTITY omega \"&#969;\"><!ENTITY thetasym \"&#977;\"><!ENTITY upsih \"&#978;\"><!ENTITY piv \"&#982;\"><!ENTITY bull \"&#8226;\"><!ENTITY hellip \"&#8230;\"><!ENTITY prime \"&#8242;\"><!ENTITY Prime \"&#8243;\"><!ENTITY oline \"&#8254;\"><!ENTITY frasl \"&#8260;\"><!ENTITY weierp \"&#8472;\"><!ENTITY image \"&#8465;\"><!ENTITY real \"&#8476;\"><!ENTITY trade \"&#8482;\"><!ENTITY alefsym \"&#8501;\"><!ENTITY larr \"&#8592;\"><!ENTITY uarr \"&#8593;\"><!ENTITY rarr \"&#8594;\"><!ENTITY darr \"&#8595;\"><!ENTITY harr \"&#8596;\"><!ENTITY crarr \"&#8629;\"><!ENTITY lArr \"&#8656;\"><!ENTITY uArr \"&#8657;\"><!ENTITY rArr \"&#8658;\"><!ENTITY dArr \"&#8659;\"><!ENTITY hArr \"&#8660;\"><!ENTITY forall \"&#8704;\"><!ENTITY part \"&#8706;\"><!ENTITY exist \"&#8707;\"><!ENTITY empty \"&#8709;\"><!ENTITY nabla \"&#8711;\"><!ENTITY isin \"&#8712;\"><!ENTITY notin \"&#8713;\"><!ENTITY ni \"&#8715;\"><!ENTITY prod \"&#8719;\"><!ENTITY sum \"&#8721;\"><!ENTITY minus \"&#8722;\"><!ENTITY lowast \"&#8727;\"><!ENTITY radic \"&#8730;\"><!ENTITY prop \"&#8733;\"><!ENTITY infin \"&#8734;\"><!ENTITY ang \"&#8736;\"><!ENTITY and \"&#8743;\"><!ENTITY or \"&#8744;\"><!ENTITY cap \"&#8745;\"><!ENTITY cup \"&#8746;\"><!ENTITY int \"&#8747;\"><!ENTITY there4 \"&#8756;\"><!ENTITY sim \"&#8764;\"><!ENTITY cong \"&#8773;\"><!ENTITY asymp \"&#8776;\"><!ENTITY ne \"&#8800;\"><!ENTITY equiv \"&#8801;\"><!ENTITY le \"&#8804;\"><!ENTITY ge \"&#8805;\"><!ENTITY sub \"&#8834;\"><!ENTITY sup \"&#8835;\"><!ENTITY nsub \"&#8836;\"><!ENTITY sube \"&#8838;\"><!ENTITY supe \"&#8839;\"><!ENTITY oplus \"&#8853;\"><!ENTITY otimes \"&#8855;\"><!ENTITY perp \"&#8869;\"><!ENTITY sdot \"&#8901;\"><!ENTITY lceil \"&#8968;\"><!ENTITY rceil \"&#8969;\"><!ENTITY lfloor \"&#8970;\"><!ENTITY rfloor \"&#8971;\"><!ENTITY lang \"&#9001;\"><!ENTITY rang \"&#9002;\"><!ENTITY loz \"&#9674;\"><!ENTITY spades \"&#9824;\"><!ENTITY clubs \"&#9827;\"><!ENTITY hearts \"&#9829;\"><!ENTITY diams \"&#9830;\"><!ENTITY quot \"&#34;\"><!ENTITY amp \"&#38;\"><!ENTITY lt \"&#60;\"><!ENTITY gt \"&#62;\"><!ENTITY OElig \"&#338;\"><!ENTITY oelig \"&#339;\"><!ENTITY Scaron \"&#352;\"><!ENTITY scaron \"&#353;\"><!ENTITY Yuml \"&#376;\"><!ENTITY circ \"&#710;\"><!ENTITY tilde \"&#732;\"><!ENTITY ensp \"&#8194;\"><!ENTITY emsp \"&#8195;\"><!ENTITY thinsp \"&#8201;\"><!ENTITY zwnj \"&#8204;\"><!ENTITY zwj \"&#8205;\"><!ENTITY lrm \"&#8206;\"><!ENTITY rlm \"&#8207;\"><!ENTITY ndash \"&#8211;\"><!ENTITY mdash \"&#8212;\"><!ENTITY lsquo \"&#8216;\"><!ENTITY rsquo \"&#8217;\"><!ENTITY sbquo \"&#8218;\"><!ENTITY ldquo \"&#8220;\"><!ENTITY rdquo \"&#8221;\"><!ENTITY bdquo \"&#8222;\"><!ENTITY dagger \"&#8224;\"><!ENTITY Dagger \"&#8225;\"><!ENTITY permil \"&#8240;\"><!ENTITY lsaquo \"&#8249;\"><!ENTITY rsaquo \"&#8250;\"><!ENTITY euro \"&#8364;\">\n]>\n" + html;
        return new String(html.getBytes(), "GB2312");
    }

    /**
     * 格式化html
     *
     * @param element
     * @param basePath
     * @throws Exception
     */
    public void convertReportHtml(org.jsoup.nodes.Element element, String basePath) throws Exception {
        if (element.id().equals("customerImg")) {
            element.remove();
            return;
        }

        String tagName = element.tagName();
        if (tagName.equals("table") && !"printTable".equals(element.id())) { //printTable 是需求版本输出Word时,用于布局的表格,不应该显示边框
            String style = element.attr("style");
            style += "width: 100%; border:1px solid #CCC; border-collapse:collapse;";
            element.attr("style", style);
        } else if (tagName.equals("th") && !"printTable".equals(element.parent().parent().parent().id())) {
            String style = element.attr("style");
            style += " border:1px solid #CCC;";
            element.attr("style", style);
        } else if (tagName.equals("td") && !"printTable".equals(element.parent().parent().parent().id())) {
            String style = element.attr("style");
            style += " border:1px solid #EEE;";
            element.attr("style", style);
        } else if (tagName.equals("img")) {
            String src = element.attr("src");
            if (!src.startsWith("http")) {
                src = basePath + src;
                element.attr("src", src);
            }
            if (src.contains("svg") && src.contains("version")) {//如果highchart图表,先删除掉
                element.remove();
                return;
            }
        } else if (tagName.equals("a")) {
            String href = element.attr("href");
            if (!href.startsWith("http")) {
                href = basePath + href;
                element.attr("href", href);
            }
        }

        Elements elements = element.children();
        if (elements.isEmpty()) {
            return;
        }

        for (org.jsoup.nodes.Element e : elements) {
            convertReportHtml(e, basePath);
        }
    }

    /**
     * 将html转成段落
     */
    public void html2WordWithParagram(String htmlContent, String basePath) throws Exception {
        org.jsoup.nodes.Document document = Jsoup.parse(htmlContent, basePath);
        convertReportHtml(document, basePath);
        String html = document.toString();
        html = setHTMLHead(html);
        RPr rpr = getRPr("宋体", "000000", "22",
                STHint.EAST_ASIA, false, false, false, false);
        P p = factory.createP();
        setParagraphSpacing(p, JcEnumeration.CENTER, true, "100", "100", null,
                null, true, "240", STLineSpacingRule.AUTO);
        R run = factory.createR();
        // 设置表格内容字体样式
        run.setRPr(rpr);
        XHTMLImporterImpl XHTMLImporter = new XHTMLImporterImpl(wordMLPackage);
        run.getContent().addAll(XHTMLImporter.convert(html, null));
        p.getContent().add(run);
        mp.addObject(p);
    }

    /**
     * 将html生成文档
     */
    public void html2WordWithDocument(String html) throws Exception {
        XHTMLImporterImpl XHTMLImporter = new XHTMLImporterImpl(wordMLPackage);
        wordMLPackage.getMainDocumentPart().getContent().addAll(
                XHTMLImporter.convert(html, null));
    }

    /**
     * 写标题或段落
     */
    public void addParagraph(String txtValue, boolean isTitle, int fontSize, boolean isBlod) throws Exception {
        RPr rpr;
        JcEnumeration jcEnumeration;

        if (isTitle) {
            rpr = getRPr("微软雅黑", "000000", fontSize + "", STHint.EAST_ASIA,
                    isBlod, false, false, false);
            jcEnumeration = JcEnumeration.CENTER;
        } else {
            rpr = getRPr("宋体", "000000", fontSize + "", STHint.EAST_ASIA,
                    isBlod, false, false, false);
            jcEnumeration = JcEnumeration.LEFT;
        }

        Text txt = factory.createText();
        txt.setValue(txtValue);
        R run = factory.createR();
        run.getContent().add(txt);
        run.setRPr(rpr);

        P paragraph = factory.createP();
        paragraph.getContent().add(run);
        setParagraphSpacing(paragraph, jcEnumeration, true,
                "0", "0", null, null, true, "240", STLineSpacingRule.AUTO);
        mp.addObject(paragraph);
    }

    /**
     * 根据等级设置字体
     *
     * @param level
     */
    public RPr getRPrByHeadLevel(int level) {
        int fontSize = 30 - level;
        RPr rpr = getRPr("宋体", "000000", fontSize + "", STHint.EAST_ASIA,
                level <= 1, false, false, false);
        return rpr;
    }

    /**
     * 添加段落
     *
     * @param paragraph
     * @throws Exception
     */
    public void addParagraph(P paragraph) throws Exception {
        mp.addObject(paragraph);
    }

    /**
     * 分割线
     */
    public void createLine() {
        addPageBreak(STBrType.TEXT_WRAPPING);
        CTBorder topBorder = new CTBorder();
        topBorder.setSpace(new BigInteger("1"));
        topBorder.setSz(new BigInteger("1"));
        topBorder.setVal(STBorder.SINGLE);
        P p = factory.createP();
        PPr ppr = new PPr();
        PPrBase.PBdr pBdr = new PPrBase.PBdr();
        pBdr.setTop(topBorder);
        ppr.setPBdr(pBdr);
        p.setPPr(ppr);
        mp.addObject(p);
    }


    // 设置段间距-->行距 段前段后距离
    // 段前段后可以设置行和磅 行距只有磅
    // 段前磅值和行值同时设置,只有行值起作用
    // TODO 1磅=20 1行=100 单倍行距=240 为什么是这个值不知道

    /**
     * @param jcEnumeration     对齐方式
     * @param isSpace           是否设置段前段后值
     * @param before            段前磅数
     * @param after             段后磅数
     * @param beforeLines       段前行数
     * @param afterLines        段后行数
     * @param isLine            是否设置行距
     * @param lineValue         行距值
     * @param sTLineSpacingRule 自动auto 固定exact 最小 atLeast
     */
    public void setParagraphSpacing(P p, JcEnumeration jcEnumeration, boolean isSpace, String before, String after,
                                    String beforeLines, String afterLines, boolean isLine, String lineValue, STLineSpacingRule sTLineSpacingRule) {
        PPr pPr = p.getPPr();
        if (pPr == null) {
            pPr = factory.createPPr();
        }
        Jc jc = pPr.getJc();
        if (jc == null) {
            jc = new Jc();
        }
        jc.setVal(jcEnumeration);
        pPr.setJc(jc);

        PPrBase.Spacing spacing = new PPrBase.Spacing();
        if (isSpace) {
            if (before != null) {
                // 段前磅数
                spacing.setBefore(new BigInteger(before));
            }
            if (after != null) {
                // 段后磅数
                spacing.setAfter(new BigInteger(after));
            }
            if (beforeLines != null) {
                // 段前行数
                spacing.setBeforeLines(new BigInteger(beforeLines));
            }
            if (afterLines != null) {
                // 段后行数
                spacing.setAfterLines(new BigInteger(afterLines));
            }
        }
        if (isLine) {
            if (lineValue != null) {
                spacing.setLine(new BigInteger(lineValue));
            }
            spacing.setLineRule(sTLineSpacingRule);
        }
        pPr.setSpacing(spacing);
        p.setPPr(pPr);
    }


    /**
     * 创建字体
     *
     * @param isBlod      粗体
     * @param isUnderLine 下划线
     * @param isItalic    斜体
     * @param isStrike    删除线
     */
    public RPr getRPr(String fontFamily, String colorVal, String fontSize, STHint sTHint, boolean isBlod,
                      boolean isUnderLine, boolean isItalic, boolean isStrike) {
        RPr rPr = factory.createRPr();
        RFonts rf = new RFonts();
        rf.setHint(sTHint);
        rf.setAscii(fontFamily);
        rf.setHAnsi(fontFamily);
        rPr.setRFonts(rf);

        BooleanDefaultTrue bdt = factory.createBooleanDefaultTrue();
        rPr.setBCs(bdt);
        if (isBlod) {
            rPr.setB(bdt);
        }
        if (isItalic) {
            rPr.setI(bdt);
        }
        if (isStrike) {
            rPr.setStrike(bdt);
        }
        if (isUnderLine) {
            U underline = new U();
            underline.setVal(UnderlineEnumeration.SINGLE);
            rPr.setU(underline);
        }

        Color color = new Color();
        color.setVal(colorVal);
        rPr.setColor(color);

        HpsMeasure sz = new HpsMeasure();
        sz.setVal(new BigInteger(fontSize));
        rPr.setSz(sz);
        rPr.setSzCs(sz);
        return rPr;
    }


    // 分页
    public void addPageBreak(STBrType sTBrType) {
        MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart();
        Br breakObj = new Br();
        breakObj.setType(sTBrType);
        P paragraph = factory.createP();
        paragraph.getContent().add(breakObj);
        documentPart.addObject(paragraph);
    }

    // 得到页面宽度
    public int getWritableWidth()
            throws Exception {
        return wordMLPackage.getDocumentModel().getSections().get(0)
                .getPageDimensions().getWritableWidthTwips();
    }


    /**
     * 表格占页面宽度
     */
    public void setTableGridCol(Tbl table, int colSize) throws Exception {
        TblGrid tblGrid = factory.createTblGrid();
        for (int i = 0; i < colSize; i++) {
            TblGridCol gridCol = factory.createTblGridCol();
            gridCol.setW(BigInteger.valueOf(2256));
            tblGrid.getGridCol().add(gridCol);
        }
        table.setTblGrid(tblGrid);

        TblPr tblPr = table.getTblPr();
        if (tblPr == null) {
            tblPr = factory.createTblPr();
        }
        TblWidth tblWidth = new TblWidth();
        tblWidth.setType("dxa");// 这一行是必须的,不自己设置宽度默认是auto
        tblWidth.setW(new BigInteger("9027"));
        tblPr.setTblW(tblWidth);
        table.setTblPr(tblPr);
    }

    // 表格水平对齐方式
    public void setTableAlign(Tbl table,
                              JcEnumeration jcEnumeration) {
        TblPr tablePr = table.getTblPr();
        if (tablePr == null) {
            tablePr = factory.createTblPr();
        }
        Jc jc = tablePr.getJc();
        if (jc == null) {
            jc = new Jc();
        }
        jc.setVal(jcEnumeration);
        tablePr.setJc(jc);
        table.setTblPr(tablePr);
    }


    // 表格增加边框 可以设置上下左右四个边框样式以及横竖水平线样式
    public void addBorders(Tbl table, CTBorder topBorder, CTBorder bottomBorder, CTBorder leftBorder, CTBorder rightBorder,
                           CTBorder hBorder, CTBorder vBorder) {
        table.setTblPr(new TblPr());
        TblBorders borders = new TblBorders();
        borders.setBottom(bottomBorder);
        borders.setLeft(leftBorder);
        borders.setRight(rightBorder);
        borders.setTop(topBorder);
        borders.setInsideH(hBorder);
        borders.setInsideV(vBorder);
        table.getTblPr().setTblBorders(borders);
    }


    public void mergeCellsHorizontalByGridSpan(Tbl tbl, int row, int fromCell,
                                               int toCell) {
        if (row < 0 || fromCell < 0 || toCell < 0) {
            return;
        }
        List<Tr> trList = getTblAllTr(tbl);
        if (row > trList.size()) {
            return;
        }
        Tr tr = trList.get(row);
        List<Tc> tcList = getTrAllCell(tr);
        for (int cellIndex = Math.min(tcList.size() - 1, toCell); cellIndex >= fromCell; cellIndex--) {
            Tc tc = tcList.get(cellIndex);
            TcPr tcPr = getTcPr(tc);
            if (cellIndex == fromCell) {
                TcPrInner.GridSpan gridSpan = tcPr.getGridSpan();
                if (gridSpan == null) {
                    gridSpan = new TcPrInner.GridSpan();
                    tcPr.setGridSpan(gridSpan);
                }
                gridSpan.setVal(BigInteger.valueOf(Math.min(tcList.size() - 1,
                        toCell) - fromCell + 1));
            } else {
                tr.getContent().remove(cellIndex);
            }
        }
    }

    /**
     * 跨列合并
     */
    public void mergeCellsHorizontal(Tbl tbl, int row, int fromCell, int toCell, TblWidth tblWidth) {
        if (row < 0 || fromCell < 0 || toCell < 0) {
            return;
        }
        List<Tr> trList = getTblAllTr(tbl);
        if (row > trList.size()) {
            return;
        }
        Tr tr = trList.get(row);
        List<Tc> tcList = getTrAllCell(tr);
        Tc cell = tcList.get(0);
        TcPr cellPr = getTcPr(cell);
        cellPr.setTcW(tblWidth);
        for (int cellIndex = fromCell, len = Math
                .min(tcList.size() - 1, toCell); cellIndex <= len; cellIndex++) {
            Tc tc = tcList.get(cellIndex);
            TcPr tcPr = getTcPr(tc);
            TcPrInner.HMerge hMerge = tcPr.getHMerge();
            if (hMerge == null) {
                hMerge = new TcPrInner.HMerge();
                tcPr.setHMerge(hMerge);
            }
            if (cellIndex == fromCell) {
                hMerge.setVal("restart");
            } else {
                hMerge.setVal("continue");
            }
        }
    }

    /**
     * 跨行合并
     */
    public void mergeCellsVertically(Tbl tbl, int col, int fromRow, int toRow) {
        if (col < 0 || fromRow < 0 || toRow < 0) {
            return;
        }
        for (int rowIndex = fromRow; rowIndex <= toRow; rowIndex++) {
            Tc tc = getTc(tbl, rowIndex, col);
            if (tc == null) {
                break;
            }
            TcPr tcPr = getTcPr(tc);
            TcPrInner.VMerge vMerge = tcPr.getVMerge();
            if (vMerge == null) {
                vMerge = new TcPrInner.VMerge();
                tcPr.setVMerge(vMerge);
            }
            if (rowIndex == fromRow) {
                vMerge.setVal("restart");
            } else {
                vMerge.setVal("continue");
            }
        }
    }

    /**
     * 得到指定位置的表格
     */
    public Tc getTc(Tbl tbl, int row, int cell) {
        if (row < 0 || cell < 0) {
            return null;
        }
        List<Tr> trList = getTblAllTr(tbl);
        if (row >= trList.size()) {
            return null;
        }
        List<Tc> tcList = getTrAllCell(trList.get(row));
        if (cell >= tcList.size()) {
            return null;
        }
        return tcList.get(cell);
    }

    /**
     * 获取所有的单元格
     */
    public List<Tc> getTrAllCell(Tr tr) {
        List<Object> objList = getAllElementFromObject(tr, Tc.class);
        List<Tc> tcList = new ArrayList<Tc>();
        if (objList == null) {
            return tcList;
        }
        for (Object tcObj : objList) {
            if (tcObj instanceof Tc) {
                Tc objTc = (Tc) tcObj;
                tcList.add(objTc);
            }
        }
        return tcList;
    }

    public static TcPr getTcPr(Tc tc) {
        TcPr tcPr = tc.getTcPr();
        if (tcPr == null) {
            tcPr = new TcPr();
            tc.setTcPr(tcPr);
        }
        return tcPr;
    }

    /**
     * 得到表格所有的行
     */
    public List<Tr> getTblAllTr(Tbl tbl) {
        List<Object> objList = getAllElementFromObject(tbl, Tr.class);
        List<Tr> trList = new ArrayList<Tr>();
        if (objList == null) {
            return trList;
        }
        for (Object obj : objList) {
            if (obj instanceof Tr) {
                Tr tr = (Tr) obj;
                trList.add(tr);
            }
        }
        return trList;
    }

    /**
     * 得到指定类型的元素
     */
    public List<Object> getAllElementFromObject(Object obj,
                                                Class<?> toSearch) {
        List<Object> result = new ArrayList<Object>();
        if (obj instanceof JAXBElement)
            obj = ((JAXBElement<?>) obj).getValue();
        if (obj.getClass().equals(toSearch))
            result.add(obj);
        else if (obj instanceof ContentAccessor) {
            List<?> children = ((ContentAccessor) obj).getContent();
            for (Object child : children) {
                result.addAll(getAllElementFromObject(child, toSearch));
            }
        }
        return result;
    }


    /**
     * 栏目内容(表格)
     */
    public void createNormalTable(List<String[]> tableValue, String basePath) throws Exception {
        RPr titleRpr = getRPr("宋体", "000000", "22", STHint.EAST_ASIA,
                true, false, false, false);
        RPr contentRpr = getRPr("宋体", "000000", "22",
                STHint.EAST_ASIA, false, false, false, false);
        Tbl table = factory.createTbl();
        CTBorder topBorder = new CTBorder();
        topBorder.setVal(STBorder.DOUBLE);
        topBorder.setSz(new BigInteger("2"));
        CTBorder leftBorder = new CTBorder();
        leftBorder.setVal(STBorder.NONE);
        leftBorder.setSz(new BigInteger("0"));

        CTBorder hBorder = new CTBorder();
        hBorder.setVal(STBorder.SINGLE);
        hBorder.setSz(new BigInteger("1"));

        addBorders(table, topBorder, topBorder, leftBorder, leftBorder, hBorder, null);

        setTableGridCol(table, 4);

        String[] colorStr = new String[]{"E3E3E3", "D3D3D3"};

        for (int i = 0; i < tableValue.size(); i++) {

            String[] trValue = tableValue.get(i);

            Tr contentRow = factory.createTr();

            addTableCell(contentRow, StringUtils.isNotBlank(trValue[0]) ? trValue[0] : "", titleRpr,
                    JcEnumeration.CENTER, true, colorStr[i % 2], basePath);
            addTableCell(contentRow, StringUtils.isNotBlank(trValue[1]) ? trValue[1] : "", contentRpr,
                    JcEnumeration.LEFT, true, colorStr[i % 2], basePath);
            addTableCell(contentRow, StringUtils.isNotBlank(trValue[2]) ? trValue[2] : "", titleRpr,
                    JcEnumeration.CENTER, true, colorStr[i % 2], basePath);
            addTableCell(contentRow, StringUtils.isNotBlank(trValue[3]) ? trValue[3] : "", contentRpr,
                    JcEnumeration.LEFT, true, colorStr[i % 2], basePath);

            table.getContent().add(contentRow);

            if (!StringUtils.isNotBlank(trValue[2])) {//需要合并
                TblWidth tblWidth = new TblWidth();
                tblWidth.setType("dxa");
                tblWidth.setW(new BigInteger("2256"));
                mergeCellsHorizontal(table, i, 1, 3, tblWidth);
            }
        }

        setTableAlign(table, JcEnumeration.CENTER);
        mp.addObject(table);
    }


    /**
     * 栏目
     *
     * @param titleColumnName
     * @throws Exception
     */
    public void createTitleColumn(String titleColumnName) throws Exception {
        RPr boldRPr = getRPr("宋体", "000000", "24", STHint.EAST_ASIA,
                true, false, false, false);
        ObjectFactory factory = getFactory();
        P paragraph = factory.createP();
        Text txt = factory.createText();
        txt.setValue(titleColumnName);
        R run = factory.createR();
        run.getContent().add(txt);
        run.setRPr(boldRPr);
        paragraph.getContent().add(run);
        setParagraphSpacing(paragraph, JcEnumeration.LEFT, true, "0",
                "0", "200", "100", true, "240", STLineSpacingRule.AUTO);
        mp.addObject(paragraph);
    }

    // 新增单元格
    private void addTableCell(Tr tableRow, String content,
                              RPr rpr, JcEnumeration jcEnumeration, boolean hasBgColor,
                              String backgroudColor, String basePath) throws Exception {
        Tc tableCell = factory.createTc();
        P p = factory.createP();
        setParagraphSpacing(p, jcEnumeration, true, "100", "100", null,
                null, true, "240", STLineSpacingRule.AUTO);

        TcPr tcPr = tableCell.getTcPr();
        if (tcPr == null) {
            tcPr = factory.createTcPr();
        }

        CTVerticalJc valign = factory.createCTVerticalJc();
        valign.setVal(STVerticalJc.CENTER);
        tcPr.setVAlign(valign);

        R run = factory.createR();
        // 设置表格内容字体样式
        run.setRPr(rpr);

        //写值
        if (content.endsWith("##$html$##")) {
            content = content.replace("##$html$##", "");
            content = content.replace("&nbsp;", " ");
            if (content.contains("servlet/image?f=")) {
                content = content.replace("servlet/image?f=", basePath + "servlet/image?f=");
            }
            XHTMLImporterImpl XHTMLImporter = new XHTMLImporterImpl(wordMLPackage);
            run.getContent().addAll(XHTMLImporter.convert("<div>" + content + "</div>", null));
            p.getContent().add(run);
            tableCell.getContent().add(p);
        } else {
            Text t = factory.createText();
            t.setValue(content);
            run.getContent().add(t);
            p.getContent().add(run);
            tableCell.getContent().add(p);
        }

        if (hasBgColor) {
            CTShd shd = tcPr.getShd();
            if (shd == null) {
                shd = factory.createCTShd();
            }
            shd.setColor("auto");
            shd.setFill(backgroudColor);
            tcPr.setShd(shd);
        }
        tableCell.setTcPr(tcPr);
        tableRow.getContent().add(tableCell);
    }
}

以上是公用方法,简单使用

//html转word
public void exportFormatItemPage(String content, String basePath) throws Exception {
            //创建文档
            Docx4jWord word = Docx4jWord.createWord();

            org.jsoup.nodes.Document document = Jsoup.parse(content, basePath);
            word.convertReportHtml(document, basePath);
            String html = document.toString();
            html = word.setHTMLHead(html);

            //html转word
            word.html2WordWithDocument(html);
            
			WordprocessingMLPackage wordMLPackage = word.getWordMLPackage();;
			
            wordMLPackage.save(outputStream());
    }

	//写word
	public WordprocessingMLPackage exportWordByDoc4j(String basePath, ViewFormatItemInformation info, List<PageColumnConfigBean> colums,
				String tagPrefix, String docTypeName, String docName) throws Exception{
		//创建文档
		Docx4jWord word = Docx4jWord.createWord();

		//写标题
		word.addParagraph(docTypeName + "-详细信息", true, 34, true);
		word.addParagraph("所属文档《" + docName + "》", true, 22, false);

		//读内容
		String colName = "";
		List<List<PageColumnConfigBean>> content = new ArrayList<>();//记录栏目内属性
		List<String> columNames = new ArrayList<>();//记录栏目
		for (int i = 0; i < colums.size(); i++) {
			PageColumnConfigBean colum = colums.get(i);
			//栏目
			if (colum.getPojoName() == null && colum.getTitle() != null) {
				colName = colum.getTitle();
				columNames.add(colName);
				List<PageColumnConfigBean> list = new ArrayList<>();
				content.add(list);
			} else {//属性
				List<PageColumnConfigBean> list = content.get(content.size() - 1);
				list.add(colum);
			}
		}

		for (int i = 0; i < columNames.size(); i++) {
			//写栏目
			word.createTitleColumn(columNames.get(i));
			//写栏目属性
			if (content.get(i).size() > 0) {
				List<String[]> table = getTableValuesByColums( content.get(i), info, tagPrefix);
				word.createNormalTable(table, basePath);
			}
		}
		return word.getWordMLPackage();
	}

特殊字符声明头:

<!ENTITY iexcl "¡"><!ENTITY cent "¢"><!ENTITY pound "£"><!ENTITY curren "¤"><!ENTITY yen "¥"><!ENTITY brvbar "¦"><!ENTITY sect "§"><!ENTITY uml "¨"><!ENTITY copy "©"><!ENTITY ordf "ª"><!ENTITY laquo "«"><!ENTITY not "¬"><!ENTITY shy "­"><!ENTITY reg "®"><!ENTITY macr "¯"><!ENTITY deg "°"><!ENTITY plusmn "±"><!ENTITY sup2 "²"><!ENTITY sup3 "³"><!ENTITY acute "´"><!ENTITY micro "µ"><!ENTITY para "¶"><!ENTITY middot "·"><!ENTITY cedil "¸"><!ENTITY sup1 "¹"><!ENTITY ordm "º"><!ENTITY raquo "»"><!ENTITY frac14 "¼"><!ENTITY frac12 "½"><!ENTITY frac34 "¾"><!ENTITY iquest "¿"><!ENTITY Agrave "À"><!ENTITY Aacute "Á"><!ENTITY Acirc "Â"><!ENTITY Atilde "Ã"><!ENTITY Auml "Ä"><!ENTITY Aring "Å"><!ENTITY AElig "Æ"><!ENTITY Ccedil "Ç"><!ENTITY Egrave "È"><!ENTITY Eacute "É"><!ENTITY Ecirc "Ê"><!ENTITY Euml "Ë"><!ENTITY Igrave "Ì"><!ENTITY Iacute "Í"><!ENTITY Icirc "Î"><!ENTITY Iuml "Ï"><!ENTITY ETH "Ð"><!ENTITY Ntilde "Ñ"><!ENTITY Ograve "Ò"><!ENTITY Oacute "Ó"><!ENTITY Ocirc "Ô"><!ENTITY Otilde "Õ"><!ENTITY Ouml "Ö"><!ENTITY times "×"><!ENTITY Oslash "Ø"><!ENTITY Ugrave "Ù"><!ENTITY Uacute "Ú"><!ENTITY Ucirc "Û"><!ENTITY Uuml "Ü"><!ENTITY Yacute "Ý"><!ENTITY THORN "Þ"><!ENTITY szlig "ß"><!ENTITY agrave "à"><!ENTITY aacute "á"><!ENTITY acirc "â"><!ENTITY atilde "ã"><!ENTITY auml "ä"><!ENTITY aring "å"><!ENTITY aelig "æ"><!ENTITY ccedil "ç"><!ENTITY egrave "è"><!ENTITY eacute "é"><!ENTITY ecirc "ê"><!ENTITY euml "ë"><!ENTITY igrave "ì"><!ENTITY iacute "í"><!ENTITY icirc "î"><!ENTITY iuml "ï"><!ENTITY eth "ð"><!ENTITY ntilde "ñ"><!ENTITY ograve "ò"><!ENTITY oacute "ó"><!ENTITY ocirc "ô"><!ENTITY otilde "õ"><!ENTITY ouml "ö"><!ENTITY divide "÷"><!ENTITY oslash "ø"><!ENTITY ugrave "ù"><!ENTITY uacute "ú"><!ENTITY ucirc "û"><!ENTITY uuml "ü"><!ENTITY yacute "ý"><!ENTITY thorn "þ"><!ENTITY yuml "ÿ"><!ENTITY fnof "ƒ"><!ENTITY Alpha "Α"><!ENTITY Beta "Β"><!ENTITY Gamma "Γ"><!ENTITY Delta "Δ"><!ENTITY Epsilon "Ε"><!ENTITY Zeta "Ζ"><!ENTITY Eta "Η"><!ENTITY Theta "Θ"><!ENTITY Iota "Ι"><!ENTITY Kappa "Κ"><!ENTITY Lambda "Λ"><!ENTITY Mu "Μ"><!ENTITY Nu "Ν"><!ENTITY Xi "Ξ"><!ENTITY Omicron "Ο"><!ENTITY Pi "Π"><!ENTITY Rho "Ρ"><!ENTITY Sigma "Σ"><!ENTITY Tau "Τ"><!ENTITY Upsilon "Υ"><!ENTITY Phi "Φ"><!ENTITY Chi "Χ"><!ENTITY Psi "Ψ"><!ENTITY Omega "Ω"><!ENTITY alpha "α"><!ENTITY beta "β"><!ENTITY gamma "γ"><!ENTITY delta "δ"><!ENTITY epsilon "ε"><!ENTITY zeta "ζ"><!ENTITY eta "η"><!ENTITY theta "θ"><!ENTITY iota "ι"><!ENTITY kappa "κ"><!ENTITY lambda "λ"><!ENTITY mu "μ"><!ENTITY nu "ν"><!ENTITY xi "ξ"><!ENTITY omicron "ο"><!ENTITY pi "π"><!ENTITY rho "ρ"><!ENTITY sigmaf "ς"><!ENTITY sigma "σ"><!ENTITY tau "τ"><!ENTITY upsilon "υ"><!ENTITY phi "φ"><!ENTITY chi "χ"><!ENTITY psi "ψ"><!ENTITY omega "ω"><!ENTITY thetasym "ϑ"><!ENTITY upsih "ϒ"><!ENTITY piv "ϖ"><!ENTITY bull "•"><!ENTITY hellip "…"><!ENTITY prime "′"><!ENTITY Prime "″"><!ENTITY oline "‾"><!ENTITY frasl "⁄"><!ENTITY weierp "℘"><!ENTITY image "ℑ"><!ENTITY real "ℜ"><!ENTITY trade "™"><!ENTITY alefsym "ℵ"><!ENTITY larr "←"><!ENTITY uarr "↑"><!ENTITY rarr "→"><!ENTITY darr "↓"><!ENTITY harr "↔"><!ENTITY crarr "↵"><!ENTITY lArr "⇐"><!ENTITY uArr "⇑"><!ENTITY rArr "⇒"><!ENTITY dArr "⇓"><!ENTITY hArr "⇔"><!ENTITY forall "∀"><!ENTITY part "∂"><!ENTITY exist "∃"><!ENTITY empty "∅"><!ENTITY nabla "∇"><!ENTITY isin "∈"><!ENTITY notin "∉"><!ENTITY ni "∋"><!ENTITY prod "∏"><!ENTITY sum "∑"><!ENTITY minus "−"><!ENTITY lowast "∗"><!ENTITY radic "√"><!ENTITY prop "∝"><!ENTITY infin "∞"><!ENTITY ang "∠"><!ENTITY and "∧"><!ENTITY or "∨"><!ENTITY cap "∩"><!ENTITY cup "∪"><!ENTITY int "∫"><!ENTITY there4 "∴"><!ENTITY sim "∼"><!ENTITY cong "≅"><!ENTITY asymp "≈"><!ENTITY ne "≠"><!ENTITY equiv "≡"><!ENTITY le "≤"><!ENTITY ge "≥"><!ENTITY sub "⊂"><!ENTITY sup "⊃"><!ENTITY nsub "⊄"><!ENTITY sube "⊆"><!ENTITY supe "⊇"><!ENTITY oplus "⊕"><!ENTITY otimes "⊗"><!ENTITY perp "⊥"><!ENTITY sdot "⋅"><!ENTITY lceil "⌈"><!ENTITY rceil "⌉"><!ENTITY lfloor "⌊"><!ENTITY rfloor "⌋"><!ENTITY lang "〈"><!ENTITY rang "〉"><!ENTITY loz "◊"><!ENTITY spades "♠"><!ENTITY clubs "♣"><!ENTITY hearts "♥"><!ENTITY diams "♦"><!ENTITY quot """><!ENTITY amp "&"><!ENTITY lt "<"><!ENTITY gt ">"><!ENTITY OElig "Œ"><!ENTITY oelig "œ"><!ENTITY Scaron "Š"><!ENTITY scaron "š"><!ENTITY Yuml "Ÿ"><!ENTITY circ "ˆ"><!ENTITY tilde "˜"><!ENTITY ensp " "><!ENTITY emsp " "><!ENTITY thinsp " "><!ENTITY zwnj "‌"><!ENTITY zwj "‍"><!ENTITY lrm "‎"><!ENTITY rlm "‏"><!ENTITY ndash "–"><!ENTITY mdash "—"><!ENTITY lsquo "‘"><!ENTITY rsquo "’"><!ENTITY sbquo "‚"><!ENTITY ldquo "“"><!ENTITY rdquo "”"><!ENTITY bdquo "„"><!ENTITY dagger "†"><!ENTITY Dagger "‡"><!ENTITY permil "‰"><!ENTITY lsaquo "‹"><!ENTITY rsaquo "›"><!ENTITY euro "€">

]>

更多推荐

使用Docx4j导出word,及使用ImportXHTML将HTML转成word工具类