POI 5.2.3中设置XWPF段落字体属性的代码编译错误问题
问题原因与解决方法
问题根源
Apache POI 5.x版本更新了OOXML Schema生成工具,底层的CTRPr(段落运行属性类)方法命名发生了变更:
- 原
isSetRFonts()→ 现isRFontsSet() - 原
isSetSz()→ 现isSzSet() - 原
isSetSzCs()→ 现isSzCsSet() - 同时
CTP的isSetPPr()改为isPPrSet(),CTPPr的isSetRPr()改为isRPrSet() - 调用
getRFonts()、getSz()、getSzCs()时,未设置属性会返回null,需先判断再创建
修改后的核心方法
将原setParagraphRunProperties方法替换为以下适配POI 5.2.3的代码:
static void setParagraphRunProperties(XWPFParagraph paragraph, String fontFamily, int fontSize) { if (!paragraph.getCTP().isPPrSet()) paragraph.getCTP().addNewPPr(); if (!paragraph.getCTP().getPPr().isRPrSet()) paragraph.getCTP().getPPr().addNewRPr(); org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRPr rPr = paragraph.getCTP().getPPr().getRPr(); // 设置字体 if (!rPr.isRFontsSet()) rPr.addNewRFonts(); rPr.getRFonts().setAscii(fontFamily); rPr.getRFonts().setHAnsi(fontFamily); // 设置字号(单位为半磅,需乘以2) if (!rPr.isSzSet()) rPr.addNewSz(); rPr.getSz().setVal(BigInteger.valueOf(fontSize * 2)); if (!rPr.isSzCsSet()) rPr.addNewSzCs(); rPr.getSzCs().setVal(BigInteger.valueOf(fontSize * 2)); }
完整可运行代码
import java.io.FileOutputStream; import org.apache.poi.xwpf.usermodel.*; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTAbstractNum; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTLvl; import org.openxmlformats.schemas.wordprocessingml.x2006.main.STNumberFormat; import java.math.BigInteger; public class CreateWordNumberingsFormatted { static BigInteger getNewDecimalNumberingId(XWPFDocument document, BigInteger abstractNumID) { CTAbstractNum cTAbstractNum = CTAbstractNum.Factory.newInstance(); cTAbstractNum.setAbstractNumId(abstractNumID); CTLvl cTLvl = cTAbstractNum.addNewLvl(); cTLvl.addNewNumFmt().setVal(STNumberFormat.DECIMAL); cTLvl.addNewLvlText().setVal("%1."); cTLvl.addNewStart().setVal(BigInteger.valueOf(1)); XWPFAbstractNum abstractNum = new XWPFAbstractNum(cTAbstractNum); XWPFNumbering numbering = document.createNumbering(); abstractNumID = numbering.addAbstractNum(abstractNum); BigInteger numID = numbering.addNum(abstractNumID); return numID; } static void setParagraphRunProperties(XWPFParagraph paragraph, String fontFamily, int fontSize) { if (!paragraph.getCTP().isPPrSet()) paragraph.getCTP().addNewPPr(); if (!paragraph.getCTP().getPPr().isRPrSet()) paragraph.getCTP().getPPr().addNewRPr(); org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRPr rPr = paragraph.getCTP().getPPr().getRPr(); if (!rPr.isRFontsSet()) rPr.addNewRFonts(); rPr.getRFonts().setAscii(fontFamily); rPr.getRFonts().setHAnsi(fontFamily); if (!rPr.isSzSet()) rPr.addNewSz(); rPr.getSz().setVal(BigInteger.valueOf(fontSize * 2)); if (!rPr.isSzCsSet()) rPr.addNewSzCs(); rPr.getSzCs().setVal(BigInteger.valueOf(fontSize * 2)); } public static void main(String[] args) throws Exception { XWPFDocument document = new XWPFDocument(); XWPFParagraph paragraph = document.createParagraph(); XWPFRun run = paragraph.createRun(); run.setText("编号列表前的段落:"); int abstractNumID = 0; // 获取第一个十进制编号的NumID BigInteger numID = getNewDecimalNumberingId(document, BigInteger.valueOf(abstractNumID++)); // 将NumID应用到第一个列表 String fontFamily = "Times New Roman"; int fontSize = 24; // 第一个段落 paragraph = document.createParagraph(); // 应用NumID paragraph.setNumID(numID); // 设置段落运行属性 setParagraphRunProperties(paragraph, fontFamily, fontSize); // 创建文本并格式化 run = paragraph.createRun(); run.setFontFamily(fontFamily); run.setFontSize(fontSize); run.setText("一"); // 后续编号段落 paragraph = document.createParagraph(); paragraph.setNumID(numID); setParagraphRunProperties(paragraph, fontFamily, fontSize); run = paragraph.createRun(); run.setFontFamily(fontFamily); run.setFontSize(fontSize); run.setText("二"); paragraph = document.createParagraph(); paragraph.setNumID(numID); setParagraphRunProperties(paragraph, fontFamily, fontSize); run = paragraph.createRun(); run.setFontFamily(fontFamily); run.setFontSize(fontSize); run.setText("三"); paragraph = document.createParagraph(); // 获取第二个十进制编号的NumID numID = getNewDecimalNumberingId(document, BigInteger.valueOf(abstractNumID++)); // 将NumID应用到第二个不同字体的列表 fontFamily = "Courier New"; fontSize = 32; paragraph = document.createParagraph(); paragraph.setNumID(numID); setParagraphRunProperties(paragraph, fontFamily, fontSize); run = paragraph.createRun(); run.setFontFamily(fontFamily); run.setFontSize(fontSize); run.setText("一"); paragraph = document.createParagraph(); paragraph.setNumID(numID); setParagraphRunProperties(paragraph, fontFamily, fontSize); run = paragraph.createRun(); run.setFontFamily(fontFamily); run.setFontSize(fontSize); run.setText("二"); paragraph = document.createParagraph(); paragraph.setNumID(numID); setParagraphRunProperties(paragraph, fontFamily, fontSize); run = paragraph.createRun(); run.setFontFamily(fontFamily); run.setFontSize(fontSize); run.setText("三"); paragraph = document.createParagraph(); FileOutputStream out = new FileOutputStream("CreateWordNumberingsFormatted.docx"); document.write(out); out.close(); document.close(); } }
说明
POI 5.x对OOXML底层类的方法命名做了统一规范,所有isSetXXX()形式的方法均改为isXXXSet(),这是适配新代码生成工具的调整,未在通用变更文档中单独标注,导致旧版本代码无法直接兼容。
内容的提问来源于stack exchange,提问作者Dmv
相关产品推荐
相关产品推荐

