docx4j转换HTML并生成word文档实践
一、背景
在项目开发中,有一个需求需要将富文本编辑器中的内容转换为word文档。在网上看了很多开源第三方工具包的对比,最终选择了docx4j,主要原因有一下几点:
- 可以将html转换为word
- 对word操作功能强大,相对于开源工具
- docx4j官网提供在线word转Java代码功能。主要方便对比排查生成样式问题
二、遇到的问题
在使用docx4j对html进行转换,遇到了下面这些问题:
- docx4j生成table表格样式不正确。例如:在word中表格边框不展示、表格对齐方式不正确
- 对一些样式复杂或错误的html标签,无法处理会直接报错
三、docx4j问题使用办法
在介绍如何生成word之前,先介绍下,如何通过docx4j官网提供的在线word文档转为Java代码功能,当我们将html转为word文档后发现样式不正确或想单独设置样式是,这个功能可以帮助我们来如何进行设置,好我们先开始。
第一步:
- 你需要进入官网这个地址就是进行word转换的地址
第二步:
- 上传word文档。有必要说明下:这里上传的文档,是你要参考的word文档,也就是你想生成最终效果的文档。正常都是基于需求部门提供的一个文档模板,告诉IT生成出来的要长这样子。
- 上传之后点击【Process】按钮进行转换
第三步:
- 转换成功后,可以看到该word文档的XHTML标签,点击【/word/document.xml】标签,查看文档主体结构,该结构展示了整个文档的内如文字、内容样式属性,想了解每个标签含义可以复制发给大模型帮助解答。点击结构中的某一个标签,就可以看到该标签对于的Java代码。
-
这里分享下,我什么情况看代码什么情况看标签:
当我想要生成【模板文档】中某个样式效果时,我看去看代码,通过代码我可以知道文档样式如何设置的,我一般会直接把这段代码copy到项目中
当我发现生成的word样式与【模板文档】中的样式不一致,但不知道为什么,这时我会把生成的word文档XHTML标签与【模板文档】XHTML标签进行对比,查看标签样式属性哪里有区别。
四、实践过程
第一步,导入依赖包
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.15.3</version>
</dependency>
<!-- HTML 转 word文档XHTML -->
<dependency>
<groupId>org.docx4j</groupId>
<artifactId>docx4j-ImportXHTML</artifactId>
<version>8.3.11</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.docx4j</groupId>
<artifactId>docx4j-JAXB-ReferenceImpl</artifactId>
<version>8.3.11</version>
</dependency>
<!-- 修复异常的HTML标签 -->
<dependency>
<groupId>net.sf.jtidy</groupId>
<artifactId>jtidy</artifactId>
<version>r938</version>
</dependency>
第二步,创建word文档对象,设置文档样式。
- 我这里提供的代码,主要是基于我在实际开发中遇到的问题所写的,供大家作为参考。
- 代码中体现了我在【遇到的问题】章节中做提出的
- 代码中使用了大量【docx4j】包中的对象,因为我要对html转换后的XHTML标签样式进行重新设置,基本不使用html中自带样式。相当于重写了word样式
- 【docx4j】包对象操作代码,来自于我将需求部门提供的【模板文档】上传到【docx4j】官网进行转换,将转换生成的代码copy到项目进行稍微删减修改即可使用
package com.test.common;
import org.docx4j.convert.in.xhtml.XHTMLImporterImpl;
import org.docx4j.fonts.IdentityPlusMapper;
import org.docx4j.fonts.Mapper;
import org.docx4j.fonts.PhysicalFonts;
import org.docx4j.jaxb.Context;
import org.docx4j.openpackaging.exceptions.Docx4JException;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.wml.*;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Entities;
import org.w3c.tidy.Tidy;
import javax.xml.bind.JAXBElement;
import java.io.StringReader;
import java.io.StringWriter;
import java.math.BigInteger;
import java.net.URI;
import java.util.List;
public class test {
/**
* word文档 对象工厂类
*/
public static final org.docx4j.wml.ObjectFactory WML_OBJECT_FACTORY = new org.docx4j.wml.ObjectFactory();
public static void generateWord(String title, String html) throws Exception {
// 创建一个空白Word文档
WordprocessingMLPackage wordMlPackage = WordprocessingMLPackage.createPackage();
/*设置字体,把字体文件添加项目中,不依赖服务器*/
Mapper fontMapper = new IdentityPlusMapper();
URI uri = ClausesWordUtil.class.getResource("/fonts/simsun.ttc").toURI();
// 加载本地字体
PhysicalFonts.addPhysicalFonts("SimSunLocal", uri);
fontMapper.put("SimSun", PhysicalFonts.get("SimSunLocal"));
wordMlPackage.setFontMapper(fontMapper);
MainDocumentPart mainPart = wordMlPackage.getMainDocumentPart();
// 获取或创建 SectPr(Section Properties)
SectPr sectPr = wordMlPackage.getDocumentModel().getSections().get(0).getSectPr();
if (sectPr == null) {
sectPr = new SectPr();
mainPart.getJaxbElement().getBody().setSectPr(sectPr);
}
SectPr.PgSz sectprpgsz = WML_OBJECT_FACTORY.createSectPrPgSz();
sectPr.setPgSz(sectprpgsz);
sectprpgsz.setH( BigInteger.valueOf( 16838) );
sectprpgsz.setW( BigInteger.valueOf( 11906) );
// 创建并设置页面边距。 ⚠️文档页边距数值来源于模板文件的数值
SectPr.PgMar pgMar = WML_OBJECT_FACTORY.createSectPrPgMar();
pgMar.setTop(BigInteger.valueOf(1440)); // 上边距:1440 Twips = 1 inch
pgMar.setRight(BigInteger.valueOf(1800)); // 右边距:1800 Twips = 1.25 inch
pgMar.setBottom(BigInteger.valueOf(1440)); // 下边距:1440 Twips = 1 inch
pgMar.setLeft(BigInteger.valueOf(1800)); // 左边距:1800 Twips = 1.25 inch
pgMar.setHeader(BigInteger.valueOf(851)); // 页眉:851 Twips
pgMar.setFooter(BigInteger.valueOf(992)); // 页脚:992 Twips
pgMar.setGutter(BigInteger.valueOf(0)); // 装订线宽度:0
// 将 pgMar 设置到 sectPr 中
sectPr.setPgMar(pgMar);
}
/**
* word文档 标题 设置方法
* @param wordMlPackage 文档对象
* @param title 标题
*/
public static void addTitle(WordprocessingMLPackage wordMlPackage, String title) {
P p = WML_OBJECT_FACTORY.createP();
// Create object for pPr
PPr ppr = WML_OBJECT_FACTORY.createPPr();
p.setPPr(ppr);
// Create object for rPr
ParaRPr pararpr = WML_OBJECT_FACTORY.createParaRPr();
ppr.setRPr(pararpr);
// Create object for rFonts
RFonts rfonts = WML_OBJECT_FACTORY.createRFonts();
pararpr.setRFonts(rfonts);
rfonts.setAscii( "SimSun");
rfonts.setCs( "SimSun");
rfonts.setEastAsia( "SimSun");
rfonts.setHAnsi( "SimSun");
// Create object for spacing
CTSignedTwipsMeasure signedtwipsmeasure = WML_OBJECT_FACTORY.createCTSignedTwipsMeasure();
pararpr.setSpacing(signedtwipsmeasure);
signedtwipsmeasure.setVal( BigInteger.valueOf( 6) );
// Create object for sz
HpsMeasure hpsmeasure = WML_OBJECT_FACTORY.createHpsMeasure();
pararpr.setSz(hpsmeasure);
hpsmeasure.setVal( BigInteger.valueOf( 32) );
// Create object for bCs
BooleanDefaultTrue booleandefaulttrue = WML_OBJECT_FACTORY.createBooleanDefaultTrue();
pararpr.setBCs(booleandefaulttrue);
// Create object for szCs
HpsMeasure hpsmeasure2 = WML_OBJECT_FACTORY.createHpsMeasure();
pararpr.setSzCs(hpsmeasure2);
hpsmeasure2.setVal( BigInteger.valueOf( 32) );
// Create object for b
BooleanDefaultTrue booleandefaulttrue2 = WML_OBJECT_FACTORY.createBooleanDefaultTrue();
pararpr.setB(booleandefaulttrue2);
// Create object for adjustRightInd
BooleanDefaultTrue booleandefaulttrue3 = WML_OBJECT_FACTORY.createBooleanDefaultTrue();
ppr.setAdjustRightInd(booleandefaulttrue3);
// Create object for snapToGrid
BooleanDefaultTrue booleandefaulttrue4 = WML_OBJECT_FACTORY.createBooleanDefaultTrue();
ppr.setSnapToGrid(booleandefaulttrue4);
// Create object for spacing
PPrBase.Spacing pprbasespacing = WML_OBJECT_FACTORY.createPPrBaseSpacing();
ppr.setSpacing(pprbasespacing);
pprbasespacing.setAfter( BigInteger.valueOf( 156) );
pprbasespacing.setAfterLines( BigInteger.valueOf( 50) );
// Create object for jc
Jc jc = WML_OBJECT_FACTORY.createJc();
ppr.setJc(jc);
jc.setVal(org.docx4j.wml.JcEnumeration.CENTER);
// p.setParaId( "2399AB22");
// Create object for r
R r = WML_OBJECT_FACTORY.createR();
p.getContent().add( r);
// Create object for rPr
RPr rpr = WML_OBJECT_FACTORY.createRPr();
r.setRPr(rpr);
// Create object for rFonts
RFonts rfonts2 = WML_OBJECT_FACTORY.createRFonts();
rpr.setRFonts(rfonts2);
rfonts2.setAscii( "SimSun");
rfonts2.setCs( "SimSun");
rfonts2.setEastAsia( "SimSun");
rfonts2.setHint(org.docx4j.wml.STHint.EAST_ASIA);
rfonts2.setHAnsi( "SimSun");
// Create object for spacing
CTSignedTwipsMeasure signedtwipsmeasure2 = WML_OBJECT_FACTORY.createCTSignedTwipsMeasure();
rpr.setSpacing(signedtwipsmeasure2);
signedtwipsmeasure2.setVal( BigInteger.valueOf( 6) );
// Create object for sz
HpsMeasure hpsmeasure3 = WML_OBJECT_FACTORY.createHpsMeasure();
rpr.setSz(hpsmeasure3);
hpsmeasure3.setVal( BigInteger.valueOf( 32) );
// Create object for bCs
BooleanDefaultTrue booleandefaulttrue5 = WML_OBJECT_FACTORY.createBooleanDefaultTrue();
rpr.setBCs(booleandefaulttrue5);
// Create object for szCs
HpsMeasure hpsmeasure4 = WML_OBJECT_FACTORY.createHpsMeasure();
rpr.setSzCs(hpsmeasure4);
hpsmeasure4.setVal( BigInteger.valueOf( 32) );
// Create object for b
BooleanDefaultTrue booleandefaulttrue6 = WML_OBJECT_FACTORY.createBooleanDefaultTrue();
rpr.setB(booleandefaulttrue6);
// Create object for t (wrapped in JAXBElement)
Text text = WML_OBJECT_FACTORY.createText();
JAXBElement<Text> textWrapped = WML_OBJECT_FACTORY.createRT(text);
r.getContent().add( textWrapped);
text.setValue(title);
wordMlPackage.getMainDocumentPart().addObject( p);
}
/**
* 添加二级标题, 该方法用于添加不存在标题。 示例: 第x条
* 没有标题的二级条目数据处理需求: 将条目正文 与 二级标题序号 同时渲染在一行,示例:
* 第x条 xxxx正文内容
*
* @param wordMlPackage word文档对象
* @param entryLevel2TitleOrderIndex word二级序号
* @param entryContent word条目正文
* @throws Docx4JException docx4j异常
*/
public static void addLevel2TitleAndRichTextToWord(WordprocessingMLPackage wordMlPackage, String entryLevel2TitleOrderIndex, String entryContent) throws Docx4JException {
// 条目正文Html转为 word文档段落集合,一个段落为一个P对象
List<Object> htmlToXhtmlList = htmlToXhtmlImporter(wordMlPackage, entryContent);
if (htmlToXhtmlList.isEmpty()) {
return;
}
for (int i = 0; i < htmlToXhtmlList.size(); i++) {
Object item = htmlToXhtmlList.get(i);
if (item instanceof P) {
P htmlP = (P) item;
// Create object for pPr
PPr ppr = WML_OBJECT_FACTORY.createPPr();
htmlP.setPPr(ppr);
// Create object for ind
PPrBase.Ind pprbaseind = WML_OBJECT_FACTORY.createPPrBaseInd();
ppr.setInd(pprbaseind);
pprbaseind.setFirstLineChars(BigInteger.valueOf(200));
pprbaseind.setFirstLine(BigInteger.valueOf(444));
// Create object for snapToGrid
BooleanDefaultTrue booleandefaulttrue = WML_OBJECT_FACTORY.createBooleanDefaultTrue();
ppr.setSnapToGrid(booleandefaulttrue);
// Create object for spacing
PPrBase.Spacing pprbasespacing = WML_OBJECT_FACTORY.createPPrBaseSpacing();
ppr.setSpacing(pprbasespacing);
pprbasespacing.setAfter(BigInteger.valueOf(156));
pprbasespacing.setAfterLines(BigInteger.valueOf(50));
htmlP.getContent().removeIf(rObj -> ((R) rObj).getRPr() == null);
for (int j = 0; j < htmlP.getContent().size(); j++) {
R htmlR = (R) htmlP.getContent().get(j);
RPr htmlRpr = htmlR.getRPr();
// Create object for rFonts
RFonts rfonts = WML_OBJECT_FACTORY.createRFonts();
htmlRpr.setRFonts(rfonts);
rfonts.setAscii("SimSun");
rfonts.setCs("SimSun");
rfonts.setEastAsia("SimSun");
rfonts.setHint(org.docx4j.wml.STHint.EAST_ASIA);
rfonts.setHAnsi("SimSun");
// Create object for spacing
CTSignedTwipsMeasure signedtwipsmeasure = WML_OBJECT_FACTORY.createCTSignedTwipsMeasure();
htmlRpr.setSpacing(signedtwipsmeasure);
signedtwipsmeasure.setVal(BigInteger.valueOf(6));
// Create object for szCs
HpsMeasure hpsmeasure2 = WML_OBJECT_FACTORY.createHpsMeasure();
htmlRpr.setSzCs(hpsmeasure2);
htmlRpr.setSz(hpsmeasure2);
hpsmeasure2.setVal(BigInteger.valueOf(21));
}
wordMlPackage.getMainDocumentPart().addObject(htmlP);
}
else if (item instanceof Tbl) {
Tbl tbl = (Tbl) item;
TblPr tblpr = tbl.getTblPr();
setTblPr(tblpr);
tbl.setTblPr(tblpr);
CTTblPrBase.TblStyle tblStyle = Context.getWmlObjectFactory().createCTTblPrBaseTblStyle();
tblStyle.setVal("TableGrid");
tblpr.setTblStyle(tblStyle);
TblGrid tblgrid = tbl.getTblGrid();
// setTblGrid(tblgrid);
tbl.setTblGrid(tblgrid);
// 循环表格每行
tbl.getContent().forEach(trObj -> {
Tr tr = (Tr) trObj;
CTTblPrEx tblprex = WML_OBJECT_FACTORY.createCTTblPrEx();
setTblPrEx(tblprex);
tr.setTblPrEx(tblprex);
TrPr trPr = tr.getTrPr() == null ? WML_OBJECT_FACTORY.createTrPr() : tr.getTrPr();
setTrPr(trPr);
tr.setTrPr(trPr);
// 循环表格每列
tr.getContent().forEach(tcObj -> {
Tc tc = (Tc) tcObj;
TcPr tcPr = tc.getTcPr();
if (tcPr == null) {
tcPr = WML_OBJECT_FACTORY.createTcPr();
tc.setTcPr(tcPr);
}
tcPr.setTcMar(null);
CTVerticalJc tcPrValign = WML_OBJECT_FACTORY.createCTVerticalJc();
tcPrValign.setVal(STVerticalJc.CENTER);
// 默认设置单元格内容【垂直居中】
tcPr.setVAlign(tcPrValign);
TcPrInner.TcBorders tcBorders = WML_OBJECT_FACTORY.createTcPrInnerTcBorders();
setTcBorders(tcBorders);
tcPr.setTcBorders(tcBorders);
// 处理单元格内容
tc.getContent().forEach(pObj -> {
P p = (P) pObj;
PPr pPr = p.getPPr();
if (pPr != null) {
// 设置单元格文本 前后间距为0。 主要体现在单元格高度
PPrBase.Spacing sp = WML_OBJECT_FACTORY.createPPrBaseSpacing();
sp.setBefore(BigInteger.valueOf(0));
sp.setAfter(BigInteger.valueOf(0));
pPr.setSpacing(sp);
pPr.setInd(null);
}
p.getContent().removeIf(rObj -> ((R) rObj).getRPr() == null);
p.getContent().forEach(rObj -> {
R r = (R) rObj;
RPr rpr = r.getRPr();
// Create object for rFonts
RFonts rfonts = WML_OBJECT_FACTORY.createRFonts();
rpr.setRFonts(rfonts);
rfonts.setAscii("SimSun");
rfonts.setCs("SimSun");
rfonts.setEastAsia("SimSun");
rfonts.setHint(org.docx4j.wml.STHint.EAST_ASIA);
rfonts.setHAnsi("SimSun");
CTVerticalAlignRun pPrRprVertAlign = WML_OBJECT_FACTORY.createCTVerticalAlignRun();
// 设置文本在行内的垂直对齐方式
pPrRprVertAlign.setVal(STVerticalAlignRun.BASELINE);
rpr.setVertAlign(pPrRprVertAlign);
HpsMeasure hpsmeasure2 = WML_OBJECT_FACTORY.createHpsMeasure();
rpr.setSzCs(hpsmeasure2);
rpr.setSz(hpsmeasure2);
hpsmeasure2.setVal(BigInteger.valueOf(21));
});
});
});
});
wordMlPackage.getMainDocumentPart().addObject(item);
}else {
// 表示当前内容不是文本段落。 不是文本段落,默认不与二级标题 合并一行
wordMlPackage.getMainDocumentPart().addObject(item);
}
}
}
/**
* 富文本 html 转 xhtml
* @param wordMlPackage Word文档对象
* @param richText html字符串
* @return word文档对象标签集合
* @throws Docx4JException 转换word文档标签异常类型
*/
public static List<Object> htmlToXhtmlImporter(WordprocessingMLPackage wordMlPackage, String richText) throws Docx4JException {
Document htmlDocument = Jsoup.parse(richText);
htmlDocument.select("a").unwrap();
htmlDocument.select("script").remove();
htmlDocument.select("th").tagName("td");
htmlDocument.select("input").remove();
String html = htmlDocument.html().replace(" ", "\u00A0").replace("<br>", "<br/>");
log.info("打印富文本 html: {}", html);
XHTMLImporterImpl xhtmlImporter = new XHTMLImporterImpl(wordMlPackage);
try {
return xhtmlImporter.convert(html, null);
}catch (Exception e) {
log.error("htmlToXhtmlImporter html转换word文档标签异常", e);;
try {
String cleanHtml = fixHtmlByTidy(html);
log.info("Tidy 修复后的html: {}", cleanHtml);
return xhtmlImporter.convert(cleanHtml, null);
}catch (Exception e1) {
log.error("htmlToXhtmlImporter Tidy修复html转换word文档标签异常", e1);
// 转义文本中特殊字符
String escapeText = Entities.escape(htmlDocument.text());
return xhtmlImporter.convert("<html><head></head><body>文本生成失败,由于内容样式过于复杂导致word转换异常,请对该内容样式进系统调整:<p> <span style=\"background-color: #ffff00;\">"+escapeText+"</span></p> </body></html>", null);
}
}
}
/**
* 通过TIdy三方工具表,用于修复不符合规范的HTML富文本标签,不规范的HTML,会导致转换XHTML异常。
* @param html 富文本HTML
* @return 修复后的HTML
*/
public static String fixHtmlByTidy(String html) {
// 创建一个 Tidy 实例
Tidy tidy = new Tidy();
tidy.setXHTML(true);
tidy.setShowWarnings(true);
tidy.setQuiet(false);
tidy.setForceOutput(true); // 即使存在错误,仍然输出修复后的HTML
tidy.setWraplen(0); // 禁用换行
tidy.setFixComments(true); // 修复HTML注释
tidy.setFixBackslash(true); // 修复反斜杠问题
tidy.setDropEmptyParas(true); // 删除空的<p>标签
tidy.setFixUri(true); // 修复URL中的非法字符
// 将输入的 HTML 内容封装到 StringReader 中
StringReader reader = new StringReader(html);
// 使用 StringWriter 来存储修复后的 HTML
StringWriter writer = new StringWriter();
// 解析并修复 HTML,输出结果到 StringWriter
tidy.parse(reader, writer);
return writer.toString();
}
/**
* 设置表格行属性:
*<w:trPr>:
* 表示表格行(<w:tr>)的属性标签。所有子元素定义了这一行的样式和布局属性。
* <w:trHeight w:val="326" w:hRule="atLeast"/>:
* w:val="326":指定了行高为 326 twips,即二十分之一点。326 twips 大约等于 16.3 磅(~22像素)。
* w:hRule="atLeast":表示行高的规则为“至少”,即行的高度至少为 326 twips,但如果内容需要更多空间,行高可以增加。这种设置常用于允许表格行根据内容的高度自动扩展,但不会低于指定的最小高度。
* <w:jc w:val="center"/>:
* w:val="center":定义了行内内容的对齐方式为居中对齐。这影响的是整行中的文本和其他元素的水平对齐方式。
* @param trPr 当前表格行属性对象
*/
public static void setTrPr(TrPr trPr) {
trPr.getCnfStyleOrDivIdOrGridBefore().clear();
// Create object for trHeight (wrapped in JAXBElement)
CTHeight height = WML_OBJECT_FACTORY.createCTHeight();
JAXBElement<CTHeight> heightWrapped = WML_OBJECT_FACTORY.createCTTrPrBaseTrHeight(height);
trPr.getCnfStyleOrDivIdOrGridBefore().add(heightWrapped);
height.setVal(BigInteger.valueOf(326));
height.setHRule(STHeightRule.AT_LEAST);
Jc jc2 = WML_OBJECT_FACTORY.createJc();
JAXBElement<Jc> jcWrapped = WML_OBJECT_FACTORY.createCTTrPrBaseJc(jc2);
trPr.getCnfStyleOrDivIdOrGridBefore().add(jcWrapped);
jc2.setVal(JcEnumeration.CENTER);
}
/**
*设置单元格边框属性
* 上下左右
* insideH 定义表格内部水平边框(即行与行之间的水平线
* insideV 定义表格内部垂直边框(即列与列之间的垂直线
* w:val(Value):
* 指定边框的样式。常见的值包括:
* single:单线边框。
* double:双线边框。
* dotted:点状边框。
* dashed:虚线边框。
* none:无边框。
* w:color:
* 指定边框的颜色。auto 表示自动颜色,通常是黑色或基于文档主题的颜色。也可以使用十六进制颜色代码,如 w:color="FF0000" 表示红色。
* w:sz(Size):
* 定义边框的粗细,单位为 eights of a point(八分之一磅)。例如,w:sz="4" 表示 4/8 = 0.5 磅。
* w:space:
* 定义边框与内容之间的间距,单位为 eights of a point。w:space="0" 表示无间隙。
* @param tcBorders 单元格边框对象
*/
public static void setTcBorders(TcPrInner.TcBorders tcBorders) {
// CTBorder border7 = WML_OBJECT_FACTORY.createCTBorder();
// tcBorders.setLeft(border7);
// border7.setVal(STBorder.SINGLE);
// border7.setColor( "000000");
// border7.setSz( BigInteger.valueOf( 4) );
// border7.setSpace( BigInteger.valueOf( 0) );
// // Create object for right
CTBorder border8 = WML_OBJECT_FACTORY.createCTBorder();
tcBorders.setRight(border8);
border8.setVal(STBorder.SINGLE);
border8.setColor( "000000");
border8.setSz( BigInteger.valueOf( 4) );
border8.setSpace( BigInteger.valueOf( 0) );
// // Create object for top
// CTBorder border9 = WML_OBJECT_FACTORY.createCTBorder();
// tcBorders.setTop(border9);
// border9.setVal(STBorder.SINGLE);
// border9.setColor( "000000");
// border9.setSz( BigInteger.valueOf( 4) );
// border9.setSpace( BigInteger.valueOf( 0) );
// // Create object for bottom
CTBorder border10 = WML_OBJECT_FACTORY.createCTBorder();
tcBorders.setBottom(border10);
border10.setVal(STBorder.SINGLE);
border10.setColor( "000000");
border10.setSz( BigInteger.valueOf( 4) );
border10.setSpace( BigInteger.valueOf( 0) );
// // Create object for insideH
CTBorder border11 = WML_OBJECT_FACTORY.createCTBorder();
tcBorders.setInsideH(border11);
border11.setVal(STBorder.NONE);
border11.setColor( "000000");
border11.setSz( BigInteger.valueOf( 4) );
border11.setSpace( BigInteger.valueOf( 0) );
// Create object for insideV
CTBorder border12 = WML_OBJECT_FACTORY.createCTBorder();
tcBorders.setInsideV(border12);
border12.setVal(STBorder.SINGLE);
border12.setColor( "000000");
border12.setSz( BigInteger.valueOf( 4) );
border12.setSpace( BigInteger.valueOf( 0) );
}
/**
* 设置表格行扩展属性
* <w:tblCellMar> 作用:定义单元格内容与单元格边框之间的边距(即单元格的内边距)。
* 子元素:
* <w:top>:设置单元格顶部的内边距。
* <w:left>:设置单元格左侧的内边距。
* <w:bottom>:设置单元格底部的内边距。
* <w:right>:设置单元格右侧的内边距。
*
*
* @param tblprex 表格的扩展属性(table properties extension),在这里它用于定义表格行的额外属性
*/
public static void setTblPrEx(CTTblPrEx tblprex) {
// Create object for tblBorders
// TblBorders tblborders2 = WML_OBJECT_FACTORY.createTblBorders();
// tblprex.setTblBorders(tblborders2);
// Create object for left
// CTBorder border7 = WML_OBJECT_FACTORY.createCTBorder();
// tblborders2.setLeft(border7);
// border7.setVal(STBorder.SINGLE);
// border7.setColor( "000000");
// border7.setSz( BigInteger.valueOf( 4) );
// border7.setSpace( BigInteger.valueOf( 0) );
// // Create object for right
// CTBorder border8 = WML_OBJECT_FACTORY.createCTBorder();
// tblborders2.setRight(border8);
// border8.setVal(STBorder.SINGLE);
// border8.setColor( "000000");
// border8.setSz( BigInteger.valueOf( 4) );
// border8.setSpace( BigInteger.valueOf( 0) );
// // Create object for top
// CTBorder border9 = WML_OBJECT_FACTORY.createCTBorder();
// tblborders2.setTop(border9);
// border9.setVal(STBorder.SINGLE);
// border9.setColor( "000000");
// border9.setSz( BigInteger.valueOf( 4) );
// border9.setSpace( BigInteger.valueOf( 0) );
// // Create object for bottom
// CTBorder border10 = WML_OBJECT_FACTORY.createCTBorder();
// tblborders2.setBottom(border10);
// border10.setVal(STBorder.SINGLE);
// border10.setColor( "000000");
// border10.setSz( BigInteger.valueOf( 4) );
// border10.setSpace( BigInteger.valueOf( 0) );
// // Create object for insideH
// CTBorder border11 = WML_OBJECT_FACTORY.createCTBorder();
// tblborders2.setInsideH(border11);
// border11.setVal(STBorder.SINGLE);
// border11.setColor( "000000");
// border11.setSz( BigInteger.valueOf( 4) );
// border11.setSpace( BigInteger.valueOf( 0) );
// Create object for insideV
// CTBorder border12 = WML_OBJECT_FACTORY.createCTBorder();
// tblborders2.setInsideV(border12);
// border12.setVal(STBorder.SINGLE);
// border12.setColor( "000000");
// border12.setSz( BigInteger.valueOf( 4) );
// border12.setSpace( BigInteger.valueOf( 0) );
// Create object for tblCellMar
CTTblCellMar tblcellmar2 = WML_OBJECT_FACTORY.createCTTblCellMar();
tblprex.setTblCellMar(tblcellmar2);
// Create object for left
TblWidth tblwidth6 = WML_OBJECT_FACTORY.createTblWidth();
tblcellmar2.setLeft(tblwidth6);
tblwidth6.setType( "dxa");
tblwidth6.setW( BigInteger.valueOf( 5) );
// Create object for right
TblWidth tblwidth7 = WML_OBJECT_FACTORY.createTblWidth();
tblcellmar2.setRight(tblwidth7);
tblwidth7.setType( "dxa");
tblwidth7.setW( BigInteger.valueOf( 10) );
// Create object for top
TblWidth tblwidth8 = WML_OBJECT_FACTORY.createTblWidth();
tblcellmar2.setTop(tblwidth8);
tblwidth8.setType( "dxa");
tblwidth8.setW( BigInteger.valueOf( 51) );
// Create object for bottom
TblWidth tblwidth9 = WML_OBJECT_FACTORY.createTblWidth();
tblcellmar2.setBottom(tblwidth9);
tblwidth9.setType( "dxa");
tblwidth9.setW( BigInteger.valueOf( 0) );
}
/**
*设置表格属性
* <w:tblW>
* 作用:设置表格的宽度。
* w:w="7508":宽度值,单位为 twips(twentieths of a point,磅的二十分之一)。7508 twips 约等于 375.4 points(磅),大约是 5.2 英寸(13.2 厘米)。
* w:type="dxa":指定宽度单位为 twips。
* <w:jc>
* 作用:设置表格的对齐方式(table justification)。
* w:val="center":将表格水平居中对齐。可选值还有 "left"(左对齐)、"right"(右对齐)、"both"(两端对齐)。
* <w:tblCellSpacing>
* 作用:设置表格单元格之间的间距。
* w:w="0":单元格间距为 0 twips,即单元格之间没有间距。
* w:type="dxa":指定单位为 twips。
* <w:tblLayout>
* 作用:定义表格的布局方式(table layout)。
* w:type="autofit":表格自动调整布局,以适应内容。"autofit" 表示表格的列宽会根据内容自动调整。
*<w:tblLook>
* 作用:定义表格的视觉样式,通常与样式表相关联,用于指定特定的表格外观。
* w:val="04A0":指定表格的视觉样式为 04A0,通常用于更加丰富多彩的表格布局。
* <w:tblCellMar>
* 作用:定义单元格的内边距(cell margins),即单元格内容与单元格边框之间的距离
*<w:tblBorders>
* 作用:定义表格的边框样式,包括表格外部边框和内部单元格之间的边框
*
* @param tblpr 定义表格的属性(table properties),如宽度、对齐方式、单元格间距等。
*/
public static void setTblPr(TblPr tblpr) {
if (tblpr == null) {
tblpr = WML_OBJECT_FACTORY.createTblPr();
}
TblWidth tblWidth = WML_OBJECT_FACTORY.createTblWidth();
tblWidth.setType( "dxa");
tblWidth.setW( BigInteger.valueOf( 0) );
tblpr.setTblCellSpacing(tblWidth);
CTTblLook tbllook = WML_OBJECT_FACTORY.createCTTblLook();
tblpr.setTblLook(tbllook);
tbllook.setVal( "04A0");
// Create object for jc
Jc jc = WML_OBJECT_FACTORY.createJc();
tblpr.setJc(jc);
jc.setVal(JcEnumeration.CENTER);
// Create object for tblStyle
// CTTblPrBase.TblStyle tblprbasetblstyle = WML_OBJECT_FACTORY.createCTTblPrBaseTblStyle();
// tblpr.setTblStyle(tblprbasetblstyle);
// tblprbasetblstyle.setVal( "TableGrid");
/*
* TableNormal: 应用表格的默认样式,没有特殊的边框或背景色。
TableGrid: 应用网格线样式,表格中每个单元格都有实线边框。
ColorfulGrid: 多彩的网格样式,常用于更加丰富多彩的表格布局。
* */
// Create object for tblW
TblWidth tblwidth = WML_OBJECT_FACTORY.createTblWidth();
tblpr.setTblW(tblwidth);
tblwidth.setType( "dxa");
tblwidth.setW( BigInteger.valueOf( 7508) );
// Create object for tblBorders
TblBorders tblborders = WML_OBJECT_FACTORY.createTblBorders();
setTblBorders(tblborders);
tblpr.setTblBorders(tblborders);
CTTblLayoutType tbllayouttype = WML_OBJECT_FACTORY.createCTTblLayoutType();
tblpr.setTblLayout(tbllayouttype);
tbllayouttype.setType(STTblLayoutType.AUTOFIT);
// Create object for tblCellMar
CTTblCellMar tblcellmar = WML_OBJECT_FACTORY.createCTTblCellMar();
setTblCTTblCellMar(tblcellmar);
tblpr.setTblCellMar(tblcellmar);
}
/**
*在表格层级设置 单元格内容与单元格边框之间的距离
*<w:top w:w="51" w:type="dxa"/>
* 作用:设置单元格内容与单元格顶部边框之间的距离。
* <w:left w:w="5" w:type="dxa"/>
* 作用:设置单元格内容与单元格左侧边框之间的距离。
* <w:bottom w:w="0" w:type="dxa"/>
* 作用:设置单元格内容与单元格底部边框之间的距离。
* <w:right w:w="10" w:type="dxa"/>
* 作用:设置单元格内容与单元格右侧边框之间的距离。
*
* @param tblcellmar 定义单元格的内容与边框之间的内边距
*/
public static void setTblCTTblCellMar(CTTblCellMar tblcellmar) {
// Create object for left
TblWidth tblwidth2 = WML_OBJECT_FACTORY.createTblWidth();
tblcellmar.setLeft(tblwidth2);
tblwidth2.setType( "dxa");
tblwidth2.setW( BigInteger.valueOf( 5) );
// Create object for right
TblWidth tblwidth3 = WML_OBJECT_FACTORY.createTblWidth();
tblcellmar.setRight(tblwidth3);
tblwidth3.setType( "dxa");
tblwidth3.setW( BigInteger.valueOf( 10) );
// Create object for top
TblWidth tblwidth4 = WML_OBJECT_FACTORY.createTblWidth();
tblcellmar.setTop(tblwidth4);
tblwidth4.setType( "dxa");
tblwidth4.setW( BigInteger.valueOf( 51) );
// Create object for bottom
TblWidth tblwidth5 = WML_OBJECT_FACTORY.createTblWidth();
tblcellmar.setBottom(tblwidth5);
tblwidth5.setType( "dxa");
tblwidth5.setW( BigInteger.valueOf( 0) );
}
/**
* 设置表格边框属性
* 这里主要设置了: 表格的左、上、水平、垂直边框, 另外两个方向有单元格设置。
* insideH 定义表格内部水平边框(即行与行之间的水平线
* insideV 定义表格内部垂直边框(即列与列之间的垂直线
* w:val(Value):
* 指定边框的样式。常见的值包括:
* single:单线边框。
* double:双线边框。
* dotted:点状边框。
* dashed:虚线边框。
* none:无边框。
* w:color:
* 指定边框的颜色。auto 表示自动颜色,通常是黑色或基于文档主题的颜色。也可以使用十六进制颜色代码,如 w:color="FF0000" 表示红色。
* w:sz(Size):
* 定义边框的粗细,单位为 eights of a point(八分之一磅)。例如,w:sz="4" 表示 4/8 = 0.5 磅。
* w:space:
* 定义边框与内容之间的间距,单位为 eights of a point。w:space="0" 表示无间隙。
*
* @param tblborders 定义表格的边框样式,包括表格外部边框和内部单元格之间的边框。
*/
public static void setTblBorders(TblBorders tblborders) {
// Create object for left
CTBorder border = WML_OBJECT_FACTORY.createCTBorder();
tblborders.setLeft(border);
border.setVal(STBorder.SINGLE);
border.setColor( "000000");
border.setSz( BigInteger.valueOf( 4) );
border.setSpace( BigInteger.valueOf( 0) );
// // Create object for right
// CTBorder border2 = WML_OBJECT_FACTORY.createCTBorder();
// tblborders.setRight(border2);
// border2.setVal(STBorder.SINGLE);
// border2.setColor( "000000");
// border2.setSz( BigInteger.valueOf( 4) );
// border2.setSpace( BigInteger.valueOf( 0) );
// // Create object for top
CTBorder border3 = WML_OBJECT_FACTORY.createCTBorder();
tblborders.setTop(border3);
border3.setVal(STBorder.SINGLE);
border3.setColor( "000000");
border3.setSz( BigInteger.valueOf( 4) );
border3.setSpace( BigInteger.valueOf( 0) );
// // Create object for bottom
// CTBorder border4 = WML_OBJECT_FACTORY.createCTBorder();
// tblborders.setBottom(border4);
// border4.setVal(STBorder.SINGLE);
// border4.setColor( "000000");
// border4.setSz( BigInteger.valueOf( 4) );
// border4.setSpace( BigInteger.valueOf( 0) );
// Create object for insideH
// CTBorder border5 = WML_OBJECT_FACTORY.createCTBorder();
// tblborders.setInsideH(border5);
// border5.setVal(STBorder.SINGLE);
// border5.setColor( "000000");
// border5.setSz( BigInteger.valueOf( 4) );
// border5.setSpace( BigInteger.valueOf( 0) );
//// Create object for insideV
// CTBorder border6 = WML_OBJECT_FACTORY.createCTBorder();
// tblborders.setInsideV(border6);
// border6.setVal(STBorder.SINGLE);
// border6.setColor( "000000");
// border6.setSz( BigInteger.valueOf( 4) );
// border6.setSpace( BigInteger.valueOf( 0) );
}
}
标签:
docx4j
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具