POI 操作word

2022-12-15 15:02:43 浏览数 (1)

关于POI 操作word的基础知识在这个博客(http://elim.iteye.com/blog/2049110)中有非常清晰的解释,在这里我就不多解释了 

本文研究的内容就是 

XWPFParagraph:代表一个段落

XWPFRun:代表具有相同属性的一段文本

大家都知道在设计模式中有个构造器模式,用于那些拥有很多属性但是有些属性可选设置的对象的生成。笔者觉得段落和文本的构建能很好运用此种模式。

首先是段落构建器

代码语言:javascript复制
//段落构建器
    public class XWPFParagraphBuilder {
        //常量,在文档中定义长度和高度的单位
        private static final int PER_LINE = 100;
        //每个字符的单位长度
        private static final int PER_CHART = 100;
        //1厘米≈567
        private static final int PER_CM = 567;
        //每一磅的单位长度
        private static final int PER_POUND = 20;
        //行距单位长度
        private static final int ONE_LINE = 240;

        private XWPFParagraph paragraph = null;
        private CTPPr pPr = null;
        //保存通用段落属性引用,方便复用
        private Map<String, CTPPr> savedPPr = null;
        //设定间距的对象
        private CTSpacing pSpacing = null;
        //设定缩进的对象
        private CTInd pInd = null;


        public XWPFParagraphBuilder init(XWPFDocument document) {
            return init(document.createParagraph());
        }

        public XWPFParagraphBuilder init(XWPFParagraph paragraph) {
            if (paragraph == null) {
                throw new IllegalArgumentException("the paragraph should not be null");
            }
            this.paragraph = paragraph;
            pPr = getPrOfParagraph(paragraph);
            return this;
        }

        //设置段落对齐方式
        public XWPFParagraphBuilder align(ParagraphAlignment pAlign, TextAlignment vAlign) {
            ensureInit();
            if (pAlign != null) {
                paragraph.setAlignment(pAlign);
            }
            if (vAlign != null) {
                paragraph.setVerticalAlignment(vAlign);
            }
            return this;
        }

        //初始化段落间距属性,在设置各段落间距前调用
        public XWPFParagraphBuilder initSpacing() {
            ensureInit();
            pSpacing = pPr.getSpacing() != null ? pPr.getSpacing() : pPr.addNewSpacing();
            return this;
        }

        //设置段前和段后间距,以磅为单位
        public XWPFParagraphBuilder spaceInPound(double before, double after) {
            ensureInit();
            if (pSpacing == null) {
                initSpacing();
            }
            pSpacing.setBefore(BigInteger.valueOf((long) (before * PER_POUND)));
            pSpacing.setAfter(BigInteger.valueOf((long) (after * PER_POUND)));
            return this;
        }

        //设置段前和段后间距,以行为单位
        public XWPFParagraphBuilder spaceInLine(double beforeLines, double afterLines) {
            ensureInit();
            if (pSpacing == null) {
                initSpacing();
            }
            pSpacing.setBeforeLines(BigInteger.valueOf((long) (beforeLines * PER_LINE)));
            pSpacing.setAfterLines(BigInteger.valueOf((long) (afterLines * PER_LINE)));
            return this;
        }

        //设置段落行距
        public XWPFParagraphBuilder lineSpace(double value, STLineSpacingRule.Enum spaceRule) {
            ensureInit();
            if (pSpacing == null) {
                initSpacing();
            }
            int unit;
            if (spaceRule == null) {
                spaceRule = STLineSpacingRule.AUTO;
            }
            if (spaceRule.intValue() == STLineSpacingRule.INT_AUTO) {
                //当行距规则为多倍行距时,单位为行,且最小为0.06行
                unit = ONE_LINE;
                if (value < 0.06) {
                    value = 0.06;
                }
            } else {
                //当行距规则为固定值或最小值时,单位为磅,且最小为0.7磅
                unit = PER_POUND;
                if (value < 0.7) {
                    value = 0.7;
                }
            }
            pSpacing.setLine(BigInteger.valueOf((long) (value * unit)));
            pSpacing.setLineRule(spaceRule);
            return this;
        }

        public XWPFParagraphBuilder initInd() {
            ensureInit();
            pInd = pPr.getInd() != null ? pPr.getInd() : pPr.addNewInd();
            return this;
        }

        //设置段落缩进,以厘米为单位; 悬挂缩进高于首行缩进;右侧缩进高于左侧缩进
        public XWPFParagraphBuilder indentInCM(double firstLine, double hanging, double right, double left) {
            ensureInit();
            if (pInd == null) {
                initInd();
            }
            if (firstLine != 0) {
                pInd.setFirstLine(BigInteger.valueOf((long) (firstLine * PER_CM)));
            }
            if (hanging != 0) {
                pInd.setHanging(BigInteger.valueOf((long) (hanging * PER_CM)));
            }
            if (right != 0) {
                pInd.setRight(BigInteger.valueOf((long) (right * PER_CM)));
            }
            if (left != 0) {
                pInd.setLeft(BigInteger.valueOf((long) (left * PER_CM)));
            }
            return this;
        }

        //设置段落缩进,以字符为单位; 悬挂缩进高于首行缩进;右侧缩进高于左侧缩进
        public XWPFParagraphBuilder indentInChart(int firstLine, int hanging, int left, int right) {
            ensureInit();
            if (pInd == null) {
                initInd();
            }
            if (firstLine != 0) {
                pInd.setFirstLineChars(BigInteger.valueOf((long) (firstLine * PER_CHART)));
            }
            if (hanging != 0) {
                pInd.setHangingChars(BigInteger.valueOf((long) (hanging * PER_CHART)));
            }
            if (right != 0) {
                pInd.setRightChars(BigInteger.valueOf((long) (right * PER_CHART)));
            }
            if (left != 0) {
                pInd.setLeftChars(BigInteger.valueOf((long) (left * PER_CHART)));
            }
            return this;
        }

        public XWPFParagraphBuilder savePr(String pPrName) {
            ensureInit();
            if (savedPPr == null) {
                savedPPr = new HashedMap<String, CTPPr>();
            }

            savedPPr.put(pPrName, pPr);

            return this;
        }

        public XWPFParagraphBuilder samePrOf(String pPrName) {
            ensureInit();

            if (savedPPr != null && savedPPr.containsKey(pPrName)) {
                return samePrOf(savedPPr.get(pPrName));
            }

            return this;
        }

        public XWPFParagraphBuilder samePrOf(CTPPr pPr) {
            ensureInit();
            if (pPr != null) {
                paragraph.getCTP().setPPr(pPr);
            }
            return this;
        }

        public XWPFParagraphBuilder samePrOf(XWPFParagraph otherPra) {
            ensureInit();
            paragraph.getCTP().setPPr(getPrOfParagraph(otherPra));
            return this;
        }

        public XWPFParagraph build() {
            return paragraph;
        }

        //确保init方法是第一个调用的,避免出现空指针异常
        private void ensureInit() {
            if (this.paragraph == null) {
                throw new IllegalStateException("the init method must be invoked firstly");
            }
        }
    }

构建器的优点在于能够链式调用 

示例:

代码语言:javascript复制
 //新增一个段前2倍行距段后3倍行距,文本2倍行距的段落
        XWPFParagraph firstPar = paragraphBuilder.init(document).initSpacing().spaceInLine(2, 3)
                    .lineSpace(2, null).build();

如果有一段段落的属性与之前段落相同,你可以在链尾调用savePr(String pPrName),来为保存该属性,并制定名称,当有其他段落要用到次属性时就可以在调用samePrOf(String pPrName)来设定属性避免重复操作。

其中有一点需要注意的是:init方法一定是第一个调用的,不然会出现空指针异常

接下来是文本构建器(思想与段落相同)

代码语言:javascript复制
//文本构建器
    public class XWPFRunBuilder {
        private XWPFRun run = null;
        private Map<String, CTRPr> savedRPr;

        public XWPFRunBuilder init(XWPFParagraph paragraph) {
            return init(paragraph, false);
        }

        public XWPFRunBuilder init(XWPFParagraph paragraph, boolean newLine) {
            this.run = paragraph.createRun();
            if (newLine) {
                run.addBreak();
            }
            return this;
        }

        /**
         * insert a new Run in RunArray
         *
         * @param pos The position at which the new run should be added.
         */
        public XWPFRunBuilder init(XWPFParagraph paragraph, int pos) {
            this.run = paragraph.insertNewRun(pos);
            if (this.run == null) {
                return init(paragraph, false);
            }
            return this;
        }

        public XWPFRunBuilder init(XWPFRun run) {
            if (run == null) {
                throw new IllegalArgumentException("the run should not be null");
            }
            this.run = run;
            return this;
        }

        public XWPFRunBuilder content(String content) {
            ensureInit();
            if (StringUtils.isNotBlank(content)) {
                // pRun.setText(content);
                if (content.contains("n")) {// System.properties("line.separator")
                    String[] lines = content.split("n");
                    run.setText(lines[0], 0); // set first line into XWPFRun
                    for (int i = 1; i < lines.length; i  ) {
                        // add break and insert new text
                        run.addBreak();
                        run.setText(lines[i]);
                    }
                } else {
                    run.setText(content, 0);
                }
            }
            return this;
        }

        //加粗
        public XWPFRunBuilder bold(boolean bold) {
            ensureInit();
            run.setBold(bold);
            return this;
        }

        //斜体
        public XWPFRunBuilder italic(boolean italic) {
            ensureInit();
            run.setItalic(italic);
            return this;
        }

        //删除线
        public XWPFRunBuilder strike(boolean strike) {
            ensureInit();
            run.setStrike(strike);
            return this;
        }

        //字体设置,中文字体、英文字体、字号
        public XWPFRunBuilder font(String cnFontFamily, String enFontFamily, String fontSize) {
            ensureInit();
            CTRPr rPr = getPrOfRun(run);
            // 设置字体
            CTFonts fonts = rPr.isSetRFonts() ? rPr.getRFonts() : rPr.addNewRFonts();
            if (StringUtils.isNotBlank(enFontFamily)) {
                fonts.setAscii(enFontFamily);
                fonts.setHAnsi(enFontFamily);
            }
            if (StringUtils.isNotBlank(cnFontFamily)) {
                fonts.setEastAsia(cnFontFamily);
                fonts.setHint(STHint.EAST_ASIA);
            }
            // 设置字体大小
            CTHpsMeasure sz = rPr.isSetSz() ? rPr.getSz() : rPr.addNewSz();
            sz.setVal(new BigInteger(fontSize));

            CTHpsMeasure szCs = rPr.isSetSzCs() ? rPr.getSzCs() : rPr
                    .addNewSzCs();
            szCs.setVal(new BigInteger(fontSize));
            return this;
        }

        //底纹
        public XWPFRunBuilder shade(STShd.Enum shdStyle, String shdColor) {
            ensureInit();
            CTRPr rPr = getPrOfRun(run);
            // 设置底纹
            CTShd shd = rPr.isSetShd() ? rPr.getShd() : rPr.addNewShd();
            if (shdStyle != null) {
                shd.setVal(shdStyle);
            }
            if (shdColor != null) {
                shd.setColor(shdColor);
                shd.setFill(shdColor);
            }
            return this;
        }

        /**
         * @param position 字符垂直方向上间距位置; >0:提升; <0:降低;=磅值*2
         * @return
         */
        public XWPFRunBuilder position(int position) {
            ensureInit();
            if (position != 0) {
                run.setTextPosition(position);
            }
            return this;
        }

        //字符间距
        public XWPFRunBuilder space(int spacingValue) {
            ensureInit();
            if (spacingValue > 0) {
                CTRPr rPr = getPrOfRun(run);
                CTSignedTwipsMeasure measure = rPr.isSetSpacing() ? rPr.getSpacing() : rPr.addNewSpacing();
                measure.setVal(new BigInteger(String.valueOf(spacingValue)));
            }
            return this;
        }

        /**
         * @param verticalAlign SUPERSCRIPT:上标;SUBSCRIPT:下标
         * @return
         */
        public XWPFRunBuilder verticalAlign(VerticalAlign verticalAlign) {
            ensureInit();
            if (verticalAlign != null) {
                run.setSubscript(verticalAlign);
            }
            return this;
        }

        //下划线
        public XWPFRunBuilder underLine(STUnderline.Enum underStyle, String underLineColor) {
            ensureInit();
            CTRPr rPr = getPrOfRun(run);
            CTUnderline udLine = rPr.addNewU();
            udLine.setVal(underStyle);
            udLine.setColor(underLineColor);
            return this;
        }

        //高亮
        public XWPFRunBuilder highLight(STHighlightColor.Enum highStyle) {
            ensureInit();
            CTRPr rPr = getPrOfRun(run);
            if (highStyle != null) {
                CTHighlight highLight = rPr.isSetHighlight() ? rPr.getHighlight() : rPr.addNewHighlight();
                highLight.setVal(highStyle);
            }
            return this;
        }

        public XWPFRunBuilder savePr(String rPrName) {
            ensureInit();
            if (savedRPr == null) {
                savedRPr = new HashedMap<String, CTRPr>();
            }
            savedRPr.put(rPrName, getPrOfRun(run));
            return this;
        }

        public XWPFRunBuilder samePrOf(String rPrName) {
            ensureInit();
            if (savedRPr != null && savedRPr.containsKey(rPrName)) {
                return samePrOf(savedRPr.get(rPrName));
            }
            return this;
        }

        public XWPFRunBuilder samePrOf(CTRPr rPr) {
            ensureInit();
            if (rPr != null) {
                run.getCTR().setRPr(rPr);
            }
            return this;
        }

        public XWPFRunBuilder samePrOf(XWPFRun otherRun) {
            ensureInit();
            run.getCTR().setRPr(getPrOfRun(otherRun));
            return this;
        }

        public XWPFRun build() {
            return run;
        }

        private void ensureInit() {
            if (this.run == null) {
                throw new IllegalStateException("the init method must be invoked firstly");
            }
        }
    }
代码语言:javascript复制
public static CTPPr getPrOfParagraph(XWPFParagraph p) {
   CTPPr pPr = null;
   if (p.getCTP() != null) {
      if (p.getCTP().getPPr() != null) {
         pPr = p.getCTP().getPPr();
      } else {
         pPr = p.getCTP().addNewPPr();
      }
   }
   return pPr;
}

文本构建器大体上与段落构建器类似,基本上能满足大多数操作。

以后有时间会研究操作table,这个是重点。加油! 

测试结果

备注:因为只是贴出部分代码,其中有两个工具方法未给出,全部代码在github可以看到(https://github.com/jadezhang123/learning/blob/master/apple/src/main/java/own/jadezhang/learning/apple/utils/WordHolder.java)

0 人点赞