在使用 poi-tl 生成 Word 文档时,我们经常会遇到这样的需求:在同一行文本中,需要同时展示多种不同的样式,例如一部分文字是红色加粗,另一部分是蓝色普通字体。本文将详细介绍如何在 poi-tl 中优雅地实现这一功能。
一、问题背景
在传统的 Word 模板开发中,要实现"一行多样式"的效果,通常需要手动在 Word 中编辑,这不仅繁琐,而且难以复用。poi-tl 提供了强大的 ParagraphRenderData 和 TextRenderData 模型,让我们可以通过代码精确控制每一段、每一个字的样式。
二、核心原理
实现"一行多样式"的核心思路是:
- 段落容器 :使用
ParagraphRenderData作为一个"容器",它代表 Word 中的一个段落。 - 文本片段 :在这个容器中,通过
addText()方法添加多个TextRenderData对象。每个TextRenderData代表一段具有独立样式的文本。 - 自动接续 :多个
TextRenderData片段会自动在同一行内接续显示,不会产生换行,从而实现"一行多样式"的效果。 - 渲染策略 :必须为
ParagraphRenderData绑定ParagraphRenderPolicy,否则 poi-tl 会将其当作普通对象,输出其toString()结果,而不是渲染成带样式的文本。
三、完整实现步骤
1. 依赖准备
确保你的项目中已经引入了 poi-tl 的依赖。以 Maven 为例:
xml
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>
<version>1.12.0</version> <!-- 请使用最新稳定版 -->
</dependency>
2. 构建混合样式段落
这是最核心的一步。我们使用 Paragraphs 和 Texts 工厂类来构建数据模型。
java
import com.deepoove.poi.data.ParagraphRenderData;
import com.deepoove.poi.data.Paragraphs;
import com.deepoove.poi.data.TextRenderData;
import com.deepoove.poi.data.Texts;
// 1. 构建混合样式的段落
ParagraphRenderData mixedStylePara = Paragraphs.of()
// 第一部分:红色 + 加粗 + 14号字体
.addText(Texts.of("这是第一种样式(红色加粗)")
.color("FF0000") // 红色(6位十六进制)
.bold() // 加粗
.fontSize(14)
.create())
// 第二部分:蓝色 + 普通 + 12号字体(同一行接续)
.addText(Texts.of(",这是第二种样式(蓝色普通)")
.color("0000FF") // 蓝色
.fontSize(12) // 字号可不同,仍在同一行
.create())
.create();
3. 配置渲染策略
在渲染模板前,必须通过 Configure 将 ParagraphRenderPolicy 绑定到对应的模板标签上。
java
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.policy.ParagraphRenderPolicy;
// 2. 配置渲染策略(关键:必须绑定ParagraphRenderPolicy)
Configure config = Configure.builder()
.bind("mixed_text", new ParagraphRenderPolicy()) // 绑定策略到标签名
.build();
4. 准备数据并渲染
将构建好的 ParagraphRenderData 对象放入数据 Map 中,然后使用配置好的 Configure 来编译和渲染模板。
java
import com.deepoove.poi.XWPFTemplate;
import java.util.HashMap;
import java.util.Map;
public class MixedStyleTextDemo {
public static void main(String[] args) throws Exception {
// ... 省略 ParagraphRenderData 和 Configure 的构建代码 ...
// 3. 准备渲染数据
Map<String, Object> data = new HashMap<>();
data.put("mixed_text", mixedStylePara); // 绑定到模板标签
// 4. 渲染模板(假设模板文件为 template.docx,里面有 {{mixed_text}} 标签)
XWPFTemplate template = XWPFTemplate.compile("template.docx", config)
.render(data);
// 5. 输出生成的文档
template.writeToFile("output.docx");
template.close();
System.out.println("文档生成成功!");
}
}
5. 模板文件配置
在你的 Word 模板(template.docx)中,只需要在你希望显示混合样式文本的位置,插入一个简单的标签即可:
{{mixed_text}}
注意:标签所在位置的行样式(如行距、对齐方式)会被保留,而文本的具体样式(颜色、字体、大小)则以你在代码中设置的为准。
四、完整代码
java
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.data.ParagraphRenderData;
import com.deepoove.poi.data.Paragraphs;
import com.deepoove.poi.data.Texts;
import com.deepoove.poi.policy.ParagraphRenderPolicy;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* poi-tl 一行文本实现多种样式示例
* 功能:生成包含混合样式文本的 Word 文档
*/
public class PoiTlMixedStyleDemo {
public static void main(String[] args) {
// 1. 构建混合样式段落(核心:同一行多个样式)
ParagraphRenderData mixedStyleParagraph = buildMixedStyleParagraph();
// 2. 准备渲染数据
Map<String, Object> renderData = new HashMap<>();
renderData.put("mixed_text", mixedStyleParagraph);
// 3. 配置渲染策略(必须绑定ParagraphRenderPolicy)
Configure configure = Configure.builder()
.bind("mixed_text", new ParagraphRenderPolicy())
.build();
// 4. 渲染模板并生成文档
try {
// 替换为你的模板文件路径(模板中只需包含 {{mixed_text}} 标签)
String templatePath = "template.docx";
// 生成的文档输出路径
String outputPath = "output_mixed_style.docx";
// 编译模板 → 渲染数据 → 输出文档
XWPFTemplate template = XWPFTemplate.compile(templatePath, configure)
.render(renderData);
// 写入文件
template.write(new FileOutputStream(outputPath));
// 关闭资源
template.close();
System.out.println("文档生成成功!输出路径:" + outputPath);
} catch (IOException e) {
System.err.println("文档生成失败:" + e.getMessage());
e.printStackTrace();
}
}
/**
* 构建混合样式的段落(一行包含多种样式文本)
* @return 混合样式段落对象
*/
private static ParagraphRenderData buildMixedStyleParagraph() {
return Paragraphs.of()
// 第一段:红色 + 加粗 + 14号字体
.addText(Texts.of("【重要提示】")
.color("FF0000") // 红色(6位十六进制,无需#)
.bold() // 加粗
.fontSize(14) // 字号
.create())
// 第二段:黑色 + 普通 + 12号字体
.addText(Texts.of("本次操作将修改核心配置,")
.color("000000") // 黑色
.fontSize(12)
.create())
// 第三段:蓝色 + 斜体 + 12号字体 + 下划线
.addText(Texts.of("请确认后再执行")
.color("0000FF") // 蓝色
.italic() // 斜体
.underline() // 下划线
.fontSize(12)
.create())
.create();
}
}
五、常见问题与避坑指南
-
样式不生效,输出
ParagraphRenderData[contents=...]- 原因 :最常见的原因是没有为标签绑定
ParagraphRenderPolicy。 - 解决 :检查
Configure配置,确保bind("标签名", new ParagraphRenderPolicy())已正确执行。
- 原因 :最常见的原因是没有为标签绑定
-
文本换行
- 原因 :如果每个
TextRenderData都单独创建了一个ParagraphRenderData,它们就会各自成段。 - 解决 :确保所有样式片段都添加到同一个
ParagraphRenderData对象中。
- 原因 :如果每个
-
颜色不显示
- 原因:颜色值格式不正确。
- 解决 :使用 6 位十六进制字符串,如
"FF0000",不要带#号。
-
*ParagraphRenderPolicy和普通的可以共用
- 一个模板方法中即使用了ParagraphRenderPolicy,依然可以使用普通的文本填充
六、总结
通过 ParagraphRenderData 组合多个 TextRenderData 是 poi-tl 实现"一行多样式"的官方推荐方案。它不仅灵活强大,而且代码结构清晰,易于维护。只要记住**"一个段落容器,多个文本片段,必须绑定渲染策略"**这三个关键点,就能轻松应对各种复杂的文本样式需求。