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

背景    

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

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

代码实现

导入POM

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

        
            org.apache.poi
            poi
            4.1.2
        

        
            org.apache.poi
            poi-ooxml
            4.1.2
        
        
            commons-io
            commons-io
            2.12.0
        

        
            org.jsoup
            jsoup
            1.14.3
        

        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 {
        // 处理元素类型,例如

等 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 {
        // 处理元素类型,例如

等 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,特别是针对水印功能,针对系统函数的功能和美观上的缺失做了方法扩展,

本文来自网络,不代表协通编程立场,如若转载,请注明出处:https://net2asp.com/4256960781.html