Loading

【Apache POI - Excel导出】html代码导出到单元格,支持简单样式渲染

需求:将渲染后的html代码,导出到单元格中。

依赖

<dependency>
    <groupId>com.deepoove</groupId>
    <artifactId>poi-tl</artifactId>
    <version>1.8.2</version>
</dependency>

代码实现

public class ExcelUtil {

    /**
     * 设置单元格富文本值
     */
    public static void setCellRichTextString(Workbook wb, Cell cell, Object obj, boolean isHead){
        if(obj == null){
            cell.setCellValue(StringPool.EMPTY);
            return;
        }
        String htmlCode = (String) obj;
        Document document = Jsoup.parse(htmlCode);
        //获取html文本内容
        StringBuilder htmlCodeStrSb = new StringBuilder();
        //前端特殊字符组件每个<p>标签为一行
        Elements allP = document.select("p");
        if(allP.size() == 0){
            htmlCodeStrSb.append(obj);
        }else {
            setTextByElements(allP, htmlCodeStrSb);
        }
        //对于表格头不需要进行字体样式渲染
        if(isHead){
            cell.setCellValue(htmlCodeStrSb.toString());
            return;
        }
        //html转为RichTextString
        RichTextString richTextString = ExcelUtil.convertToRichTextString(wb, document.body(), htmlCodeStrSb.toString());
        cell.setCellValue(richTextString);

    }



    public static void setTextByElements(Elements elements, StringBuilder htmlCodeStrSb){
        if(!elements.isEmpty()) {
            for (Element element : elements) {
                for (Node childNode : element.childNodes()) {
                    setTextByNode(childNode, htmlCodeStrSb);
                }
                htmlCodeStrSb.append("\n");
            }
            htmlCodeStrSb.deleteCharAt(htmlCodeStrSb.length() - 1);
        }
    }

    public static void setTextByNode(Node node, StringBuilder htmlCodeStrSb){
        if (node instanceof TextNode) {
            TextNode textNode = (TextNode) node;
            String text = textNode.getWholeText();
            if (!text.isEmpty()) {
                htmlCodeStrSb.append(text);
            }
        } else if (node instanceof Element) {
            for (Node childNode : node.childNodes()) {
                setTextByNode(childNode, htmlCodeStrSb);
            }
        }

    }



    public static RichTextString convertToRichTextString(Workbook workbook, Element element, String htmlCode) {
        RichTextString richTextString = new HSSFRichTextString(htmlCode);
        int startIndex = 0;
        for (Node node : element.childNodes()) {
            Font font = workbook.createFont();
            startIndex = applyFontRecursive(workbook, richTextString, node, startIndex, font);
        }
        return richTextString;
    }

    public static int applyFontRecursive(Workbook workbook, RichTextString richTextString,
                                         Node node, int startIndex, Font parentFont) {
        if (node instanceof TextNode) {
            TextNode textNode = (TextNode) node;
            String text = textNode.getWholeText();
            if (!text.isEmpty()) {
                startIndex = startIndex + text.length();
            }
        } else if (node instanceof Element) {
            Element childElement = (Element) node;
            String tagName = childElement.tagName();
            Font font = copyFont(workbook, parentFont);
            switch (tagName) {
                case "strong": //加粗
                    font.setBold(true);
                    break;
                case "em": //斜体
                    font.setItalic(true);
                    break;
                case "sup": //上标
                    font.setTypeOffset(Font.SS_SUPER);
                    break;
                case "sub": //下标
                    font.setTypeOffset(Font.SS_SUB);
                    break;
                case "span":
                    String style = childElement.attr("style");
                    if(StringUtils.isNotBlank(style)) {
                        if (style.contains("text-decoration: line-through;")) {  //水平删除斜线
                            font.setStrikeout(true);
                        }
                        if (style.contains("text-decoration: underline;")) { //下划线
                            font.setUnderline(Font.U_SINGLE);
                        }
                    }
                default:
                    break;
            }
            richTextString.applyFont(startIndex, startIndex + ((Element) node).text().length(), font);
            for (Node childNode : childElement.childNodes()) {
                startIndex = applyFontRecursive(workbook, richTextString, childNode, startIndex, font);
            }
        }
        return startIndex;
    }

    /**
     * 拷贝字体
     */
    public static Font copyFont(Workbook workbook, Font font){
        Font copyFont = workbook.createFont();
        copyFont.setBold(font.getBold());
        copyFont.setItalic(font.getItalic());
        copyFont.setStrikeout(font.getStrikeout());
        copyFont.setUnderline(font.getUnderline());
        copyFont.setTypeOffset(font.getTypeOffset());
        return copyFont;
    }



}

注意事项

如果html代码中含有<img>标签,则需要删除或者替代。目前并不支持导出文字+图片的形式。

/**
 * 
 * @param htmlCode html代码
 * @param replaceStr 替换的字符串
 */
private String replaceImg(String htmlCode, String replaceStr){
    Document doc = Jsoup.parse(htmlCode);
    Elements imgElements = doc.select("img");
    if(!imgElements.isEmpty()) {
        for (Element img : imgElements) {
            img.replaceWith(new TextNode(replaceStr));
        }
    }
    return doc.body().html();
}
posted @ 2023-07-24 17:38  IamHzc  阅读(264)  评论(0编辑  收藏  举报