Pre Merge pull request !1311 from Nicely/v5-dev

This commit is contained in:
Nicely 2025-02-19 07:47:48 +00:00 committed by Gitee
commit 383524aca2
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
6 changed files with 396 additions and 6 deletions

View File

@ -6,19 +6,22 @@ import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.poi.exceptions.POIException;
import cn.hutool.poi.word.style.Bracket;
import cn.hutool.poi.word.style.StyleUtil;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.impl.xb.xmlschema.SpaceAttribute;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import java.awt.Font;
import java.awt.*;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
/**
* Word docx生成器
@ -29,6 +32,12 @@ import java.io.OutputStream;
public class Word07Writer implements Closeable {
private final XWPFDocument doc;
/**
* 页眉页脚策略
*/
protected XWPFHeaderFooterPolicy headerFooterPolicy;
/**
* 目标文件
*/
@ -70,6 +79,7 @@ public class Word07Writer implements Closeable {
public Word07Writer(XWPFDocument doc, File destFile) {
this.doc = doc;
this.destFile = destFile;
this.headerFooterPolicy = null;
}
// -------------------------------------------------------------------------- Constructor end
@ -94,6 +104,21 @@ public class Word07Writer implements Closeable {
return this;
}
/**
* 创建一个新的段落
*
* @param alignment 段落对齐方式 {@link ParagraphAlignment}
* @return XWPFParagraph
* @since 5.8.37
*/
public XWPFParagraph addParagraph(ParagraphAlignment alignment) {
XWPFParagraph paragraph = this.doc.createParagraph();
if (null != alignment) {
paragraph.setAlignment(alignment);
}
return paragraph;
}
/**
* 增加一个段落
*
@ -134,6 +159,173 @@ public class Word07Writer implements Closeable {
return this;
}
/**
* 为指定段落添加一行文本
*
* @param paragraph 指定段落 {@link XWPFParagraph}
* @param font 字体信息{@link Font}
* @param text 段落中的文本
* @return row
* @since 5.8.37
*/
public XWPFRun addRun(XWPFParagraph paragraph, Font font, String text) {
XWPFRun run = paragraph.createRun();
run.setText(text);
if (null != font) {
run.setFontFamily(font.getFamily());
run.setFontSize(font.getSize());
run.setBold(font.isBold());
run.setItalic(font.isItalic());
}
return run;
}
/**
* 为指定行添加尾注
*
* @param run 指定文本行 {@link XWPFRun}
* @param endNoteText 尾注说明
* @param bracket 标识样式 {@link Bracket}
* @return this
* @since 5.8.37
*/
public Word07Writer addEndNotesToRun(XWPFRun run, String endNoteText, Bracket bracket){
CTFtnEdnRef fr = run.getCTR().addNewEndnoteReference();
fr.setId(BigInteger.ONE);
this.doc.createEndnotes();
CTFtnEdn ctNote = CTFtnEdn.Factory.newInstance();
ctNote.setId(BigInteger.ONE);
ctNote.setType(STFtnEdn.NORMAL);
CTP ctp = ctNote.addNewP();
XWPFParagraph p2 = new XWPFParagraph(ctp, this.doc);
if (null != bracket) {
if (bracket != Bracket.NONE){
run = p2.createRun();
run.setText(bracket.getPrefix());
}
}
run = p2.createRun();
run.getCTR().addNewEndnoteRef();
if (null != bracket) {
if (bracket != Bracket.NONE){
run = p2.createRun();
run.setText(bracket.getSuffix());
}
}
CTText ctText = run.getCTR().addNewT();
ctText.setStringValue(" ");
ctText.setSpace(SpaceAttribute.Space.PRESERVE);
run.setText(endNoteText);
this.doc.addEndnote(ctNote);
return this;
}
/**
* 为指定行添加脚注
*
* @param run 指定文本行 {@link XWPFRun}
* @param footNoteText 脚注说明文本
* @param bracket 标识样式 {@link Bracket}
*
* @return this
* @since 5.8.37
*/
public Word07Writer addFootNotesToRun(XWPFRun run, String footNoteText, Bracket bracket) {
CTFtnEdnRef fr = run.getCTR().addNewFootnoteReference();
fr.setId(BigInteger.ONE);
XWPFFootnotes footnotes = this.doc.createFootnotes();
CTFtnEdn ctNote = CTFtnEdn.Factory.newInstance();
ctNote.setId(BigInteger.ONE);
ctNote.setType(STFtnEdn.NORMAL);
CTP ctp = ctNote.addNewP();
XWPFParagraph xwpfParagraph = new XWPFParagraph(ctp, this.doc);
if (null != bracket) {
if (bracket != Bracket.NONE){
run = xwpfParagraph.createRun();
run.setText(bracket.getPrefix());
}
}
run = xwpfParagraph.createRun();
run.getCTR().addNewFootnoteRef();
if (null != bracket) {
if (bracket != Bracket.NONE){
run = xwpfParagraph.createRun();
run.setText(bracket.getSuffix());
}
}
run = xwpfParagraph.createRun();
CTText ctText = run.getCTR().addNewT();
ctText.setStringValue(" ");
ctText.setSpace(SpaceAttribute.Space.PRESERVE);
run.setText(footNoteText);
footnotes.addFootnote(ctNote);
return this;
}
/**
* 为文档添加页眉
*
* @param alignment 页眉位置 {@link ParagraphAlignment}
* @param font 页眉样式 {@link Font}
* @param headerText 页脚内容
* @return this
* @since 5.8.37
*/
public Word07Writer addHeader(ParagraphAlignment alignment, Font font, String headerText) {
if (null == this.headerFooterPolicy) {
this.headerFooterPolicy = this.doc.createHeaderFooterPolicy();
}
XWPFHeader header = this.headerFooterPolicy.createHeader(XWPFHeaderFooterPolicy.DEFAULT);
XWPFParagraph headerParagraph = header.createParagraph();
if (null != alignment) {
headerParagraph.setAlignment(alignment);
}
addRun(headerParagraph, font, headerText);
return this;
}
/**
* 为文档添加页脚
*
* @param alignment 页脚位置 {@link ParagraphAlignment}
* @param font 页脚样式 {@link Font}
* @param footerText 页脚内容
* @return this
* @since 5.8.37
*/
public Word07Writer addFooter(ParagraphAlignment alignment, Font font, String footerText) {
if (null == this.headerFooterPolicy) {
this.headerFooterPolicy = this.doc.createHeaderFooterPolicy();
}
XWPFFooter footer = this.headerFooterPolicy.createFooter(XWPFHeaderFooterPolicy.DEFAULT);
XWPFParagraph footerParagraph = footer.createParagraph();
if (null != alignment) {
footerParagraph.setAlignment(ParagraphAlignment.CENTER);
}
addRun(footerParagraph, font, footerText);
return this;
}
/**
* 新开一页
*
* @return this
* @since 5.8.37
*/
public Word07Writer newPage() {
XWPFParagraph newPageParagraph = this.doc.createParagraph();
newPageParagraph.setPageBreak(true);
return this;
}
/**
* 增加表格数据
*

View File

@ -0,0 +1,44 @@
package cn.hutool.poi.word.style;
/**
* 脚注尾注括号枚举
*
* @author nicely🍊
* @since 5.8.37
*/
public enum Bracket {
/**
* 无额外标识
*/
NONE(null, null),
/**
* 大括号
*/
BRACES("{", "}"),
/**
* 中括号
*/
BRACKETS("[", "]"),
/**
* 小括号
*/
PARENTHESES("(", ")");
private final String prefix;
private final String suffix;
Bracket(String prefix, String suffix) {
this.prefix = prefix;
this.suffix = suffix;
}
public String getPrefix() {
return prefix;
}
public String getSuffix() {
return suffix;
}
}

View File

@ -0,0 +1,78 @@
package cn.hutool.poi.word.style;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import java.awt.*;
/**
* Docx样式工具类
*
* @author nicely🍊
* @since 5.8.37
*/
public class StyleUtil {
/**
* 为文本设置样式
* @param run 指定文本 {@link XWPFRun}
* @param font 字体 {@link Font}
* @param rgb 文本颜色rgb色值 ex: FF0000
* @param isUnderLine 是否启用下划线
* @param underLineColor 下划线颜色 (rgb)
* @param underLineStyle 下划线样式 (0:, 1:实线, >1: 值越大虚线间隔越大)
* @param isHighlight 是否启用高亮
* @param highlightValue 高亮背景色 {@link STHighlightColor.Enum}
* @param stRunEnum 垂直对齐方式 {@link STVerticalAlignRun.Enum}
*
* @since 5.8.37
*/
public static void setRunStyle(XWPFRun run, Font font, String rgb, boolean isUnderLine, String underLineColor,
int underLineStyle, boolean isHighlight, STHighlightColor.Enum highlightValue,
STVerticalAlignRun.Enum stRunEnum) {
CTRPr pRpr = null;
if (run.getCTR() != null) {
pRpr = run.getCTR().getRPr();
if (pRpr == null) {
pRpr = run.getCTR().addNewRPr();
}
}
assert pRpr != null;
if (null != font) {
// 设置字体
run.setFontFamily(font.getFamily());
run.setFontSize(font.getSize());
run.setBold(font.isBold());
run.setItalic(font.isItalic());
}
// 设置颜色
if (null != rgb) {
run.setColor(rgb);
}
// 设置下划线样式
if (isUnderLine) {
CTUnderline u = pRpr.isSetU() ? pRpr.getU() : pRpr.addNewU();
u.setVal(STUnderline.Enum.forInt(Math.abs(underLineStyle % 19)));
if (underLineColor != null) {
u.setColor(underLineColor);
}
}
// 设置突出显示文本
if (isHighlight) {
CTHighlight highlight = pRpr.isSetHighlight() ? pRpr
.getHighlight() : pRpr.addNewHighlight();
highlight.setVal(highlightValue);
}
if (stRunEnum != null) {
CTVerticalAlignRun ctV = CTVerticalAlignRun.Factory.newInstance();
ctV.setVal(stRunEnum);
pRpr.setVertAlign(ctV);
}
}
}

View File

@ -0,0 +1,7 @@
/**
* DOCX样式封装入口为StyleUtil
*
* @author nicely🍊
*
*/
package cn.hutool.poi.word.style;

View File

@ -5,10 +5,17 @@ import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.poi.word.style.Bracket;
import cn.hutool.poi.word.style.StyleUtil;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STHighlightColor;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STVerticalAlignRun;
import java.awt.Font;
import java.awt.*;
import java.io.File;
import java.util.ArrayList;
import java.util.LinkedHashMap;
@ -95,4 +102,66 @@ public class WordWriterTest {
word07Writer.addTable(list);
word07Writer.close();
}
@Test
@Disabled
public void endNotesTest() {
final Word07Writer word07Writer = new Word07Writer();
// 添加其他文本
word07Writer.addText(ParagraphAlignment.CENTER, new Font("宋体", Font.BOLD, 12), "《野步》(唐)齐己");
word07Writer.addText(ParagraphAlignment.CENTER, new Font("宋体", Font.PLAIN, 12), "城里无闲处,却寻城外行。田园经雨水,乡国忆桑耕。");
// 创建新段落
XWPFParagraph paragraph = word07Writer.addParagraph(ParagraphAlignment.CENTER);
// 为段落添加一行文本
XWPFRun run = word07Writer.addRun(paragraph, new Font("宋体", Font.PLAIN, 12), "傍涧蕨薇老,隔村冈陇横。何穷此心兴,时复鹧鸪声。");
// 为行文本添加尾注
word07Writer.addEndNotesToRun(run, "石夫、韩新愚编著.不可不知的中华24节气常识[M].郑州:中原农民出版社,2010.09:49—50.", Bracket.BRACKETS);
word07Writer.flush(FileUtil.file("e:/test/end_notes.docx"));
word07Writer.close();
}
@Test
@Disabled
public void footerTest() {
final Word07Writer word07Writer = new Word07Writer();
word07Writer.addFooter(ParagraphAlignment.CENTER, new Font("宋体", Font.BOLD, 12), "页脚");
word07Writer.flush(FileUtil.file("e:/test/footer.docx"));
word07Writer.close();
}
@Test
@Disabled
public void headerTest() {
final Word07Writer word07Writer = new Word07Writer();
word07Writer.addHeader(ParagraphAlignment.CENTER, new Font("宋体", Font.BOLD, 12), "页眉");
word07Writer.flush(FileUtil.file("e:/test/header.docx"));
word07Writer.close();
}
@Test
@Disabled
public void footerNotesTest() {
final Word07Writer word07Writer = new Word07Writer();
// 添加其他文本
word07Writer.addText(ParagraphAlignment.CENTER, new Font("宋体", Font.BOLD, 14), "《野步》(唐)齐己");
word07Writer.addText(ParagraphAlignment.CENTER, new Font("宋体", Font.PLAIN, 14), "城里无闲处,却寻城外行。田园经雨水,乡国忆桑耕。");
// 创建新段落
XWPFParagraph paragraph = word07Writer.addParagraph(ParagraphAlignment.CENTER);
// 为段落添加一行文本
XWPFRun run1 = word07Writer.addRun(paragraph, null, "傍涧蕨薇老,隔村冈陇横。");
// 为文本设置样式
StyleUtil.setRunStyle(run1, new Font("宋体", Font.PLAIN, 14), "FF0000", true,
"000000", 1, true, STHighlightColor.DARK_GRAY, STVerticalAlignRun.BASELINE);
// 为行文本添加脚注
word07Writer.addFootNotesToRun(run1, "石夫、韩新愚编著.不可不知的中华24节气常识[M]", Bracket.NONE);
XWPFRun run2 = word07Writer.addRun(paragraph, new Font("宋体", Font.PLAIN, 14), "何穷此心兴,时复鹧鸪声。");
word07Writer.addFootNotesToRun(run2, "郑州:中原农民出版社,2010.09:49—50.", Bracket.BRACKETS);
word07Writer.flush(FileUtil.file("e:/test/footer_notes.docx"));
word07Writer.close();
}
}

Binary file not shown.