JAVA POI富文本导出WORD添加水印

背景    

        在java 开发中 特别是OA开发中,经常会遇到导出word的操作,同时随时AI时代的到来,很多导出文档都需要增加水印标识,用来追溯数据生产方。

        本文将介绍如何通过操作POI 来实现导出富文本到word ,并在文档中追加水印功能。

代码实现

导入POM

        首先我们需要导入需要引用的POM文件

        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</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>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.12.0</version>
        </dependency>

        <dependency>
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.14.3</version>
        </dependency>

        commons-io包为poi依赖如果缺失,会提示NotFoundClass 。

         jsoup 是一款Java 的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据。

将html转换为dom文档

        采用Jsoup处理类来实现将html内容转换为dom结构,便于后续操作

  public static Document convertToDom(String htmlContent) {
        Document doc = Jsoup.parse(htmlContent, "UTF-8");
        return doc;
    }

基于POI处理dom内容 

        首先解析dom中的body 获取body下的所有元素

        再根据Element 中解析的tagName来分别处理在word文档中不同样式,也可以Element.attr属性来获取html中的自定义属性,类似js或者xml node节点的操作

        针对图片由于html中的图片都来源于网络,所以本文基于实际操作,将图片转换为base64编码,保证图片在word中正确展示

 /**
     * 解析Document 并处理 body下的所有Elements
     *
     * @param htmlDocument
     * @param wordDocument
     * @throws IOException
     * @throws InvalidFormatException
     */
    public static void parseDocument(Document htmlDocument, XWPFDocument wordDocument) throws IOException, InvalidFormatException {
        Elements elements = htmlDocument.body().children();
        for (Element element : elements) {
            parseElement(element, wordDocument);
        }
    }

    /**
     * 解析Elements 处理标签中指定tagName
     *
     * @param element
     * @param wordDocument
     * @throws IOException
     * @throws InvalidFormatException
     */
    private static void parseElement(Element element, XWPFDocument wordDocument) throws IOException, InvalidFormatException {
        // 处理元素类型,例如<p>、<h1>等
        String tagName = element.tagName();
        switch (tagName) {
            case "p":
                // 处理段落
                // 也可以根据 element.attr来处理不通css样式的文字
                String text = element.text();
                XWPFRun runP = wordDocument.createParagraph().createRun();
                runP.setText(text);
                break;
            case "h1":
            case "h2":
                // 处理标题1 可以自定义样式
                //此处可以处理不同标签
                String heading1Text = element.text();
                XWPFRun runH1 = wordDocument.createParagraph().createRun();
                runH1.setText(heading1Text);
                runH1.setBold(true);
                runH1.setFontSize(16);
                break;
            case "img":
                //处理图片,由于html的图片来源为网络图片,所以此处将网络图片转换为base64编码,并插入word文档
                XWPFRun run = wordDocument.createParagraph().createRun();
                String src = element.attr("src").toString();
                byte[] imageData = org.apache.commons.codec.binary.Base64.decodeBase64(ImageToBase64ByOnline(src));
                run.addPicture(new ByteArrayInputStream(imageData), XWPFDocument.PICTURE_TYPE_JPEG, "image", Units.toEMU(300), Units.toEMU(200));
                break;
            default:
                break;
        }
        // 递归处理子元素
        Elements children = element.children();
        for (Element child : children) {
            parseElement(child, wordDocument);
        }
    }

 基于POM添加水印

        调用POI 的 XWPFHeaderFooterPolicy.createWatermark api可以添加水印,但是添加之后会存在后续编辑新增段落水印不会新增,同时样式不能调整,位置为水平居中效果不是很好看,基于系统createWatermark水印效果,本方法提供了增强具体可以看代码

  /**
     * 添加水印,在调用系统api添加水印的同时,并针对系统水印的确定进行额外处理
     *
     * @param doc
     * @param markStr
     */
    public static void addWatermark(XWPFDocument doc, String markStr) {
        XWPFHeaderFooterPolicy headerFooterPolicy = doc.getHeaderFooterPolicy();
        if (headerFooterPolicy == null) {
            //兼容处理
            headerFooterPolicy = doc.createHeaderFooterPolicy();
        }
        //调用API添加水印,效果不好为水平居中
        headerFooterPolicy.createWatermark(markStr);

        //处理后续文档更新水印逻辑
        XWPFHeader header = headerFooterPolicy.getHeader(XWPFHeaderFooterPolicy.DEFAULT);

        XWPFParagraph paragraph;
        paragraph = header.getParagraphArray(0);

        //设置水印样式和位置,保持倾斜角度更好看和实用
        paragraph.getCTP().newCursor();
        org.apache.xmlbeans.XmlObject[] xmlobjects = paragraph.getCTP().getRArray(0).getPictArray(0).selectChildren(
                new javax.xml.namespace.QName("urn:schemas-microsoft-com:vml", "shape"));
        if (xmlobjects.length > 0) {
            CTShape ctshape = (CTShape) xmlobjects[0];
            ctshape.setFillcolor("#C0C0C0");
            ctshape.setStyle(ctshape.getStyle() + ";rotation:315");
        }
    }

完整代码

package com.dayouz.word;

import com.microsoft.schemas.vml.CTShape;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFHeader;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * @author dayouz
 * @classname WordUtil
 * @desc JAVA POI 实现 富文本导出 WORD 和添加水印
 */
public class WordUtil {


    /**
     * 将html内容转换为Document结构
     *
     * @param htmlContent
     * @return
     */
    public static Document convertToDom(String htmlContent) {
        Document doc = Jsoup.parse(htmlContent, "UTF-8");
        return doc;
    }

    /**
     * 解析Document 并处理 body下的所有Elements
     *
     * @param htmlDocument
     * @param wordDocument
     * @throws IOException
     * @throws InvalidFormatException
     */
    public static void parseDocument(Document htmlDocument, XWPFDocument wordDocument) throws IOException, InvalidFormatException {
        Elements elements = htmlDocument.body().children();
        for (Element element : elements) {
            parseElement(element, wordDocument);
        }
    }

    /**
     * 解析Elements 处理标签中指定tagName
     *
     * @param element
     * @param wordDocument
     * @throws IOException
     * @throws InvalidFormatException
     */
    private static void parseElement(Element element, XWPFDocument wordDocument) throws IOException, InvalidFormatException {
        // 处理元素类型,例如<p>、<h1>等
        String tagName = element.tagName();
        switch (tagName) {
            case "p":
                // 处理段落
                // 也可以根据 element.attr来处理不通css样式的文字
                String text = element.text();
                XWPFRun runP = wordDocument.createParagraph().createRun();
                runP.setText(text);
                break;
            case "h1":
            case "h2":
                // 处理标题1 可以自定义样式
                //此处可以处理不同标签
                String heading1Text = element.text();
                XWPFRun runH1 = wordDocument.createParagraph().createRun();
                runH1.setText(heading1Text);
                runH1.setBold(true);
                runH1.setFontSize(16);
                break;
            case "img":
                //处理图片,由于html的图片来源为网络图片,所以此处将网络图片转换为base64编码,并插入word文档
                XWPFRun run = wordDocument.createParagraph().createRun();
                String src = element.attr("src").toString();
                byte[] imageData = imageToBase64(src);
                run.addPicture(new ByteArrayInputStream(imageData), XWPFDocument.PICTURE_TYPE_JPEG, "image", Units.toEMU(300), Units.toEMU(200));
                break;
            default:
                break;
        }
        // 递归处理子元素
        Elements children = element.children();
        for (Element child : children) {
            parseElement(child, wordDocument);
        }
    }

    /**
     * 添加水印,在调用系统api添加水印的同时,并针对系统水印的确定进行额外处理
     *
     * @param doc
     * @param markStr
     */
    public static void addWatermark(XWPFDocument doc, String markStr) {
        XWPFHeaderFooterPolicy headerFooterPolicy = doc.getHeaderFooterPolicy();
        if (headerFooterPolicy == null) {
            //兼容处理
            headerFooterPolicy = doc.createHeaderFooterPolicy();
        }
        //调用API添加水印,效果不好为水平居中
        headerFooterPolicy.createWatermark(markStr);

        //处理后续文档更新水印逻辑
        XWPFHeader header = headerFooterPolicy.getHeader(XWPFHeaderFooterPolicy.DEFAULT);

        XWPFParagraph paragraph;
        paragraph = header.getParagraphArray(0);

        //设置水印样式和位置,保持倾斜角度更好看和实用
        paragraph.getCTP().newCursor();
        org.apache.xmlbeans.XmlObject[] xmlobjects = paragraph.getCTP().getRArray(0).getPictArray(0).selectChildren(
                new javax.xml.namespace.QName("urn:schemas-microsoft-com:vml", "shape"));
        if (xmlobjects.length > 0) {
            CTShape ctshape = (CTShape) xmlobjects[0];
            ctshape.setFillcolor("#C0C0C0");
            ctshape.setStyle(ctshape.getStyle() + ";rotation:315");
        }
    }

    /**
     * 在线图片转换成base64字符串
     *
     * @param imgURL 图片地址
     * @return
     */
    private static byte[] imageToBase64(String imgURL) {
        ByteArrayOutputStream data = new ByteArrayOutputStream();
        try {
            // 创建URL
            URL url = new URL(imgURL);
            byte[] by = new byte[1024];
            // 创建链接
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(5000);
            InputStream is = conn.getInputStream();
            // 将内容读取内存中
            int len = -1;
            while ((len = is.read(by)) != -1) {
                data.write(by, 0, len);
            }
            // 关闭流
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return data.toByteArray();

    }

    public static void main(String[] args) throws IOException, InvalidFormatException {
        //初始化文档
        XWPFDocument doc = new XWPFDocument(new FileInputStream("input.docx"));
        //将html转换为dom
        Document document = convertToDom("");
        //处理dom添加到word
        parseDocument(document, doc);
        //添加水印
        addWatermark(doc, "CSDN");
        //保存本地
        doc.write(new FileOutputStream("output.docx"));
        doc.close();
    }
}

        以上内容就是java 通过poi来实现富文本导出到word文档,针对图片也给力处理方式demo,特别是针对水印功能,针对系统函数的功能和美观上的缺失做了方法扩展,

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
可以使用Apache POI库来实现Java富文本导出Word。具体步骤如下: 1. 添加Apache POI库依赖,可以在Maven或Gradle中添加如下依赖: ```xml <!-- Apache POI --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>4.1.2</version> </dependency> ``` 2. 创建一个新的Word文档: ```java XWPFDocument document = new XWPFDocument(); ``` 3. 添加段落和文本: ```java XWPFParagraph paragraph = document.createParagraph(); XWPFRun run = paragraph.createRun(); run.setText("Hello, World!"); ``` 4. 添加富文本样式,例如字体、颜色、粗等: ```java run.setBold(true); run.setColor("FF0000"); run.setFontSize(20); ``` 5. 导出Word文档: ```java FileOutputStream out = new FileOutputStream("output.docx"); document.write(out); out.close(); document.close(); ``` 完整的示例代码如下: ```java import java.io.FileOutputStream; import java.io.IOException; import org.apache.poi.xwpf.usermodel.*; public class RichTextToWord { public static void main(String[] args) throws IOException { XWPFDocument document = new XWPFDocument(); XWPFParagraph paragraph = document.createParagraph(); XWPFRun run = paragraph.createRun(); run.setText("Hello, World!"); run.setBold(true); run.setColor("FF0000"); run.setFontSize(20); FileOutputStream out = new FileOutputStream("output.docx"); document.write(out); out.close(); document.close(); } } ``` 运行该程序将会在当前目录下生成一个名为`output.docx`的Word文档,其中包含了一个粗、红色、20号字体的Hello, World!文本。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值