背景
在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水印效果,本方法提供了增强具体可以看代码文章来源:https://www.toymoban.com/news/detail-775515.html
/**
* 添加水印,在调用系统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,特别是针对水印功能,针对系统函数的功能和美观上的缺失做了方法扩展,文章来源地址https://www.toymoban.com/news/detail-775515.html
到了这里,关于JAVA POI富文本导出WORD添加水印的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!