java 读写 word 文档和 Pdf 文档(POI,IText)

目录

需求

技术应用

框架

IText Pdf

IText Rtf

POI

设计

实现

 源代码


需求

客户要求根据报告模板写报告内容,

需求功能:

1.根据报告文件生成报告模板XML(报告文件包括 PDF ,WORD)

2.向模板XML文件中添加内容(文字,表格)(可在xml文件中添加,或在程序中动态添加)

3.根据配置的模板XML生成报告文件(生成文件 PDF,WORD)

技术应用

框架

IText Pdf

1.Itex Pdf 写 Pdf 文件

package com.spasvo.test;

import com.itextpdf.text.*;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import com.lowagie.text.pdf.PdfTable;
import com.spasvo.export.handle.impl.PdfExportHandle;
import com.spasvo.export.node.INode;

import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class TestPdfWriter {

    public static void main(String[] args) {
        Document doc = new Document(PageSize.A4);
        PdfWriter contentWriter = null;
        try {

            contentWriter = PdfWriter.getInstance(doc, new FileOutputStream("test.pdf"));
            Font  font = new Font( BaseFont.createFont("C:\\Windows\\Fonts\\simsun.ttc,0",
                    BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED), 12);
            doc.open();
            Paragraph paragraph = new Paragraph("第一章节",font);
            Section chapter = new Chapter(paragraph,1);
            chapter.add(new Paragraph("第一章节的内容",font));
            Paragraph paragraph1 = new Paragraph("第二章节",font);
            Section chapter1 = new Chapter(paragraph,2);
            PdfPTable table = new PdfPTable(2);
            table.addCell(new Paragraph("第一列",font));
            table.addCell(new Paragraph("第二列",font));

            table.addCell(new Paragraph("第一行第一列内容",font));
            table.addCell(new Paragraph("第一行第二列内容",font));

            chapter1.add(table);
            chapter1.addSection(new Paragraph("第一小节",font),1);

            doc.add(chapter);
            doc.add(chapter1);
            doc.close();
        } catch (DocumentException | FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }


    }
}

2.输出结果

IText Rtf

利用RTF 生成docx 文件

package com.spasvo.test;

import com.lowagie.text.*;
import com.lowagie.text.pdf.BaseFont;
import com.lowagie.text.rtf.RtfWriter2;
import com.spasvo.export.node.INode;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class Test5 {

    public static void main(String[] args) {
        Document doc = new Document(PageSize.A4);
        RtfWriter2 contentWriter = null;
        try {

            contentWriter = RtfWriter2.getInstance(doc, new FileOutputStream("test.docx"));
            Font font = new Font( BaseFont.createFont("C:\\Windows\\Fonts\\simsun.ttc,0",
                    BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED), 12);
            font.setStyle(Font.NORMAL|Font.BOLD);
            doc.open();
           Paragraph paragraph = new Paragraph("第一章节",font);
            Section chapter = new Chapter(paragraph,1);
            chapter.add(new Paragraph("第一章节的内容",font));
            Paragraph paragraph1 = new Paragraph("第二章节",font);
           Section chapter1 = new Chapter(paragraph1,2);
            Table table = new Table(2);
            table.addCell(new Paragraph("第一列",font));
            table.addCell(new Paragraph("第二列",font));

            table.addCell(new Paragraph("第一行第一列内容",font));
            table.addCell(new Paragraph("第一行第二列内容",font));

            chapter.add(table);

            Section section2 =  chapter1.addSection(new Paragraph("第一小节",font),2);

            Section section3 = section2.addSection(new Paragraph("第一小小节",font),3);

//            chapter1.add(section2);
            doc.add(chapter);
            doc.add(chapter1);
            doc.close();
        } catch (DocumentException | IOException e) {
            e.printStackTrace();
        }
    }
}

生成word 文件

POI

1.用到的类以及方法

类 XWPFDocument  这个是IBody 的实现类

java.util.List<IBodyElement> getBodyElements()

返回所有的内容

java.util.Iterator<IBodyElement>

getBodyElementsIterator() 

返回所有内容的迭代器

接口IBodyElement  实现类  XWPFParagraphXWPFSDTXWPFTable

IBody getBody() 
BodyElementType getElementType() 
POIXMLDocumentPart getPart() 
BodyType getPartType() 

接口 IBody  实现类 XWPFAbstractFootnoteEndnoteXWPFDocumentXWPFEndnoteXWPFFooterXWPFFootnoteXWPFHeaderXWPFHeaderFooterXWPFTableCell

java.util.List<IBodyElement> getBodyElements()

返回一个带有段落和表格的迭代器,按照它们在文本中出现的顺序。

XWPFParagraph getParagraph(org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP p)

如果在这个页眉或页脚的段落列表中,参数ctTable中有一个对应的XWPFParagraph,方法将返回这个段落。如果没有对应的XWPFParagraph,方法将返回null

XWPFParagraph getParagraphArray(int pos)

返回位置为pos的段落

java.util.List<XWPFParagraph> getParagraphs()

返回包含页眉或页脚文本的段落。

POIXMLDocumentPart getPart()

返回主体所属的Part,在向其他部分添加关系时需要该Part ,比如XWPFTableCell 

BodyType getPartType()

获取主体的PartType,例如DOCUMENT, HEADER, FOOTER, FOOTNOTE,

XWPFTable getTable(org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl ctTable)

如果在这个头的表列表中有参数ctTable对应的XWPFTable,方法将返回这个表,如果没有对应的XWPFTable,方法将返回null

XWPFTable getTableArray(int pos)

返回pos位置的表

XWPFTableCell getTableCell(org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc cell)

返回Table所属的TableCell

java.util.List<XWPFTable> getTables()

对于不使用段落的复杂情况,返回保存IBodyPart文本的表。

XWPFDocument getXWPFDocument()

Return XWPFDocument

XWPFParagraph insertNewParagraph(org.apache.xmlbeans.XmlCursor cursor)

在光标的位置插入新的段落

XWPFTable insertNewTbl(org.apache.xmlbeans.XmlCursor cursor)

在光标位置插入一个新的Table。

void insertTable(int pos, XWPFTable table)

在pos位置插入一个新表

类  XWPFParagraph 是 IBodyElement  的一个实现类

ParagraphAlignment getAlignment()

返回将应用于该段文本的段落对齐。

org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP

getCTP() 

OfficeOpenXML 的接口 

int getIndentationFirstLine()

指定附加的缩进,将应用于父段的第一行。首行缩进

int getIndentationLeft()

指定在从左到右的段落中,该段的左文本距与该段内容的左边缘之间,以及在从右到左的段落中,该段的右文本距与该段文本的右边缘之间的缩进(左对齐)

int getIndentationRight()

右对齐

java.util.List<XWPFRun> getRuns()  获取run 的list   

p - 一个段落。

r - 一段连续文本。

t - 一个文本范围。

java.lang.String getStyle()  返回Style  标识,可以用来判断是否为标题
java.lang.String getText()

返回段落的文本内容,包括来自图片的文本和其中的sdt元素。

类 XWPFRun 
void addBreak()

Specifies that a break shall be placed at the current location in the run content.

void addBreak(BreakClear clear)

Specifies that a break shall be placed at the current location in the run content.

void addBreak(BreakType type)

Specifies that a break shall be placed at the current location in the run content.

void addCarriageReturn()

Specifies that a carriage return shall be placed at the current location in the run content.

org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline addChart(java.lang.String chartRelId)

this method add chart template into document

XWPFPicture addPicture(java.io.InputStream pictureData, int pictureType, java.lang.String filename, int width, int height)

Adds a picture to the run.

void addTab()

指定在运行内容的当前位置放置一个选项卡。

int getCharacterSpacing() 
java.lang.String getColor()

Get text color.

org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR getCTR()

Get the currently used CTR object,获取Run节点的 OpenXML 节点

XWPFDocument getDocument() 
java.util.List<XWPFPicture> getEmbeddedPictures()

返回运行的嵌入图片。

org.openxmlformats.schemas.wordprocessingml.x2006.main.STEm.Enum getEmphasisMark()

获取运行的重点标记值。

java.lang.String getFontFamily()

获取应使用要显示此运行的文本内容的字体。.

java.lang.String getFontFamily(XWPFRun.FontCharRange fcr)

Gets the font family for the specified font char range.

java.lang.String getFontName()

Alias for getFontFamily()

int getFontSize()

指定在显示此运行内容时应用于所有非复杂脚本字符的字体大小。

int getKerning() 
java.lang.String getLang()

Get the language tag associated with this run, if any.

XWPFParagraph getParagraph()Deprecated. 

use getParent() instead

IRunBody getParent()

Get the currently referenced paragraph/SDT object

java.lang.String getPhonetic() 
java.lang.String getPictureText()

Returns text embedded in pictures

protected org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRPr getRunProperties(boolean create)

Get the run properties for the run.

java.lang.String getStyle()

返回这次运行的样式ID。

VerticalAlign getSubscript()Deprecated. 

use XWPFRun.getVerticalAlignment

java.lang.String getText(int pos)

Return the string content of this text run

org.openxmlformats.schemas.wordprocessingml.x2006.main.STHighlightColor.Enum getTextHightlightColor()

Gets the highlight color for the run

int getTextPosition()

This element specifies the amount by which text shall be raised or lowered for this run in relation to the default baseline of the surrounding non-positioned text.

int getTextScale()

获取当前文本缩放值。

UnderlinePatterns getUnderline()

获取运行所需的下划线设置。

java.lang.String getUnderlineColor()

获取运行下划线的颜色(如果有的话)。

org.openxmlformats.schemas.wordprocessingml.x2006.main.STThemeColor.Enum getUnderlineThemeColor()

获取运行的下划线主题颜色(如果有的话)。

org.openxmlformats.schemas.wordprocessingml.x2006.main.STVerticalAlignRun.Enum getVerticalAlignment()

获取垂直对齐值

boolean isBold()

当在文档中显示时,粗体属性是否应用于本次运行的内容中的所有非复杂脚本字符

boolean isCapitalized() 
boolean isDoubleStrikeThrough()

Specifies that the contents of this run shall be displayed with a double horizontal line through the center of the line.

boolean isEmbossed() 
boolean isHighlighted() 
boolean isImprinted() 
boolean isItalic()

当在文档中显示时,斜体属性是否应应用于此运行的内容中的所有非复杂脚本字符。

boolean isShadowed() 
boolean isSmallCaps() 
boolean isStrike()

Deprecated. 

boolean isStrikeThrough()

Specifies that the contents of this run shall be displayed with a single horizontal line through the center of the line.

boolean isVanish()

Get the vanish (hidden text) value

void removeBreak() 
void removeCarriageReturn() 
void removeTab() 
void setBold(boolean value)

Whether the bold property shall be applied to all non-complex script characters in the contents of this run when displayed in a document.

void setCapitalized(boolean value) 
void setCharacterSpacing(int twips) 
void setColor(java.lang.String rgbStr)

Set text color.

void setDoubleStrikethrough(boolean value)

Specifies that the contents of this run shall be displayed with a double horizontal line through the center of the line.

void setEmbossed(boolean value) 
void setEmphasisMark(java.lang.String markType)

Set the emphasis mark for the run.

void setFontFamily(java.lang.String fontFamily)

Specifies the fonts which shall be used to display the text contents of this run.

void setFontFamily(java.lang.String fontFamily, XWPFRun.FontCharRange fcr)

Specifies the fonts which shall be used to display the text contents of this run.

void setFontSize(int size)

Specifies the font size which shall be applied to all non complex script characters in the contents of this run when displayed.

void setImprinted(boolean value) 
void setItalic(boolean value)

Whether the bold property shall be applied to all non-complex script characters in the contents of this run when displayed in a document

void setKerning(int kern) 
void setLang(java.lang.String lang)

Set the language tag associated with this run.

void setShadow(boolean value) 
void setSmallCaps(boolean value) 
void setStrike(boolean value)

Deprecated. 

void setStrikeThrough(boolean value)

Specifies that the contents of this run shall be displayed with a single horizontal line through the center of the line.

void setStyle(java.lang.String styleId)

Set the style ID for the run.

void setSubscript(VerticalAlign valign)

Specifies the alignment which shall be applied to the contents of this run in relation to the default appearance of the run's text.

void setText(java.lang.String value)

Sets the text of this text run

void setText(java.lang.String value, int pos)

Sets the text of this text run in the

void setTextHighlightColor(java.lang.String colorName)

Set the highlight color for the run.

void setTextPosition(int val)

This element specifies the amount by which text shall be raised or lowered for this run in relation to the default baseline of the surrounding non-positioned text.

void setTextScale(int percentage)

Set the text expand/collapse scale value.

void setUnderline(UnderlinePatterns value)

Specifies that the contents of this run should be displayed along with an underline appearing directly below the character height.

void setUnderlineColor(java.lang.String color)

Set the underline color for the run's underline, if any.

void setUnderlineThemeColor(java.lang.String themeColor)

Set the underline theme color for the run's underline, if any.

void setVanish(boolean value)

The vanish (hidden text) property for the run.

void setVerticalAlignment(java.lang.String verticalAlignment)

Set the vertical alignment of the run.

java.lang.String text()

Returns the string version of the text, with tabs and carriage returns in place of their xml equivalents.

java.lang.String toString()

Returns the string version of the text and the phonetic string

2.word 文档的格式 


docx格式的word文件实际上是一个压缩包,通过修改后缀名为rar后可用winrar打开,里面实际上是xml文件

这是因为docx文件遵循了OfficeOpenXML规范,该规范内容很多,有兴趣的同学可以自行下载翻阅。打开上图的word文件夹

这里我们需要关注的是document.xml和numbering.xml

其中document.xml包含了文档的主要结构与主要文本内容,其形式有点像HTML语言

而numbering.xml与自动序号有关,由于非常复杂,文本暂不讨论,主要原因是自动序号实际上是在渲染时进行实时计算的,并且需要有不同的层次。

在开始使用Apache POI解析之前,我们需要了解一些关于docx文件结构的基本概念

整个文档是一个document,document的子元素为Paragraph(段落)和Table(表格)这和我们日常使用word的经验基本相符,Paragraph的子元素为Run,代表一段连续的相同样式的文本,一般来说,没有改过样式的一段纯中文或者纯英文就在一个Run内,而一旦对其中一个字改变了字号、颜色、粗细等样式,那么其本身及前后必然会被不同的Run分割。

在实际使用Apache POI中,又分为High Level和Low Level两种API,一般以XWPF作为前缀的是High Level API,以CT为前缀的是Low Level,High Level API使用更简单,比较容易理解,但是目前只有比较常见的元素有,例如XWPFParagraph、XWPFRun。Low Level API实际上是对xml文件中标签的简单封装,需要你对OfficeOpenXML规范有足够的了解,例如CTP(Paragraph)、CTR(Run)。当然,Low Level API也不一定能满足你的全部需求,这个时候你只能对着OfficeOpenXML文档自行解析XML了。High Level API可以获取到对应的Low Level API,例如,XWPFParagraph.getCTP()。

上图是High Level API的类的主要关系图,其中蓝色的是class,绿色的是interface

List<XWPFParagraph> paragraphs = document.getParagraphs();
for(XWPFParagraph paragraph:paragraphs){
    List<XWPFRun> runs= paragraph.getRuns();
    for(XWPFRun run:runs){
        List<XWPFPicture> pictures=run.getEmbeddedPictures();
        String text=run.text();
  }

此部分摘自:https://blog.csdn.net/fatesunlove/article/details/107020537


3.demo 测试

测试Word 文档 (摘自 需求规格说明书模板部分内容)

测试代码

package com.spasvo.test;

import org.apache.poi.xwpf.usermodel.*;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import java.io.FileInputStream;
import java.util.List;


public class TestMain {

    public static void main(String[] args) throws Exception {
        XWPFDocument document = new XWPFDocument(new FileInputStream("zheng.docx")).getXWPFDocument();
        XWPFStyles styles = document.getStyles();
        List<IBodyElement> elements = document.getBodyElements();
        for (IBodyElement element : elements) {
           if (element instanceof XWPFParagraph) {
                XWPFParagraph pf = (XWPFParagraph) element;
                List<XWPFRun> runList = pf.getRuns();
                System.out.println("对齐方式 :" + pf.getAlignment().getValue());
                System.out.println("左间距 :" + pf.getIndentationLeft());
                System.out.println("右间距 :" + pf.getIndentationRight());
                System.out.println("首行缩进 :"  + pf.getFirstLineIndent());
                String paStyle = pf.getStyle();
                if (styles.getStyle(paStyle) == null) {
                    System.out.println("文字格式 :" + "null");
                } else {
                    System.out.println("文字格式 :" + styles.getStyle(paStyle).getCTStyle().getName().getVal());
                }
                System.out.println("run size " + runList.size());
                if (runList.size() == 1) {
                    XWPFRun run = runList.get(0);
                    String FontFamily = run.getFontFamily(XWPFRun.FontCharRange.hAnsi);//字体
                    System.out.println("FontName :" + FontFamily);
                    System.out.println("fontSize :" + run.getFontSize());//字体大小

                    String str = run.getCTR().toString();
                  //  System.out.println(str);
                    //将 Run  的 xml 转化为 dom4j  字符串处理
                    Document doc = DocumentHelper.parseText(str);
                    Element rootElement = doc.getRootElement();
                    List<Element> elements1 = rootElement.elements();
                    for (Element e1 : elements1) {
                        //System.out.println(e1.getName());
                        if (e1.getName().equals("t")) {
                            System.out.println("文字内容 :" + e1.getText().trim());
                        }else if(e1.getName().equals("drawing")){
                            System.out.println("图片 :");
                        }
                    }
                }

        }else if (element instanceof XWPFTable) {
               System.out.println("表格................");
               XWPFTable table = (XWPFTable) element;
               List<XWPFTableRow> listRow = table.getRows();

               for (XWPFTableRow row : listRow) {
                   System.out.println("---------------------------------------------------------------");
                   List<XWPFTableCell> cellList = row.getTableCells();
                   for (XWPFTableCell cell : cellList) {
                       //单元格里面的内容
                       List<XWPFParagraph> cellParagraphList = cell.getParagraphs();
                       for (XWPFParagraph phCell : cellParagraphList) {
                           System.out.print("" + phCell.getText() + "_Cell|");
                       }
                       System.out.println("..");
                   }
               }

           }
            System.out.println("------------------------------一个Element-------------------------------------");
        }



    }
}

运行结果

对齐方式 :1
左间距 :420
右间距 :-1
首行缩进 :-1
文字格式 :heading 1
run size 1
FontName :null
fontSize :15
文字内容 :概述
------------------------------一个Element-------------------------------------
对齐方式 :1
左间距 :-1
右间距 :-1
首行缩进 :-1
文字格式 :heading 2
run size 1
FontName :null
fontSize :14
文字内容 :编写目的
------------------------------一个Element-------------------------------------
对齐方式 :1
左间距 :-1
右间距 :-1
首行缩进 :480
文字格式 :null
run size 1
FontName :Verdana
fontSize :12
文字内容 :编写本文档的目的是为了对薪酬管理系统建设项目进行明确的定义,详细说明应用系统的外部行为,包括业务功能需求、非功能性需求、接口细节、设计约束以及影响系统的其他因素。
------------------------------一个Element-------------------------------------
对齐方式 :1
左间距 :-1
右间距 :-1
首行缩进 :480
文字格式 :样式 样式 样式 段前: 0.5 行 段后: 0.5 行 + 左侧:  2 字符 段前: 0.5 行 段后: 0.5 行 + 段...
run size 1
FontName :null
fontSize :-1
文字内容 :本需求说明书主要适合以下读者:
------------------------------一个Element-------------------------------------
对齐方式 :1
左间距 :-1
右间距 :-1
首行缩进 :-1
文字格式 :样式 样式 样式 段前: 0.5 行 段后: 0.5 行 + 左侧:  2 字符 段前: 0.5 行 段后: 0.5 行 + 段...
run size 1
FontName :null
fontSize :-1
文字内容 :用户
------------------------------一个Element-------------------------------------
对齐方式 :1
左间距 :-1
右间距 :-1
首行缩进 :-1
文字格式 :heading 2
run size 1
FontName :null
fontSize :14
文字内容 :适用范围
------------------------------一个Element-------------------------------------
对齐方式 :4
左间距 :-1
右间距 :-1
首行缩进 :480
文字格式 :l居中
run size 1
FontName :null
fontSize :12
文字内容 :需求规格说明书是适用于薪酬管理系统项目的过程。
------------------------------一个Element-------------------------------------
对齐方式 :1
左间距 :-1
右间距 :-1
首行缩进 :425
文字格式 :null
run size 0
------------------------------一个Element-------------------------------------
对齐方式 :1
左间距 :-1
右间距 :-1
首行缩进 :425
文字格式 :null
run size 1
FontName :null
fontSize :-1
文字内容 :被调研人列表
------------------------------一个Element-------------------------------------
表格................
---------------------------------------------------------------
部门_Cell|..
职位_Cell|..
需求确认范围_Cell|..
_Cell|..
---------------------------------------------------------------
客服部_Cell|..
大区经理,客服经理,客服主管,客服专员_Cell|..
税率,薪资项目,薪资模板,薪资计算_Cell|..
_Cell|..
------------------------------一个Element-------------------------------------
对齐方式 :1
左间距 :-1
右间距 :-1
首行缩进 :425
文字格式 :null
run size 0
------------------------------一个Element-------------------------------------
对齐方式 :1
左间距 :-1
右间距 :-1
首行缩进 :425
文字格式 :null
run size 1
FontName :null
fontSize :-1
文字内容 :用户列表
------------------------------一个Element-------------------------------------
表格................
---------------------------------------------------------------
部门_Cell|..
职位_Cell|..
_Cell|..
_Cell|..
---------------------------------------------------------------
客服部_Cell|..
客服经理,客服主管,客服专员_Cell|..
_Cell|..
_Cell|..
------------------------------一个Element-------------------------------------
对齐方式 :1
左间距 :-1
右间距 :-1
首行缩进 :-1
文字格式 :null
run size 0
------------------------------一个Element-------------------------------------
对齐方式 :1
左间距 :-1
右间距 :-1
首行缩进 :-1
文字格式 :heading 2
run size 1
FontName :null
fontSize :14
文字内容 :名词解释
------------------------------一个Element-------------------------------------
对齐方式 :1
左间距 :426
右间距 :-1
首行缩进 :0
文字格式 :样式 infoblue + 小五 左侧:  0 厘米 段后: 0 磅 行距: 单倍行距
run size 1
FontName :null
fontSize :12
文字内容 :《XX系统设计说明书编制规范V1.1》
------------------------------一个Element-------------------------------------
对齐方式 :1
左间距 :420
右间距 :-1
首行缩进 :-1
文字格式 :heading 1
run size 1
FontName :null
fontSize :15
文字内容 :系统综述
------------------------------一个Element-------------------------------------
对齐方式 :1
左间距 :-1
右间距 :-1
首行缩进 :-1
文字格式 :heading 2
run size 1
FontName :null
fontSize :14
文字内容 :系统介绍
------------------------------一个Element-------------------------------------
对齐方式 :1
左间距 :-1
右间距 :-1
首行缩进 :-1
文字格式 :null
run size 1
FontName :null
fontSize :-1
文字内容 :薪酬管理系统用来支持企业薪酬管理,包括组织结构定义、员工信息管理、薪酬模板管理、薪酬发放管理、薪酬报表。
------------------------------一个Element-------------------------------------
对齐方式 :1
左间距 :-1
右间距 :-1
首行缩进 :-1
文字格式 :null
run size 1
FontName :null
fontSize :-1
文字内容 :薪酬管理系统是一个web应用形式,能够经过互联网进行访问。
------------------------------一个Element-------------------------------------
对齐方式 :1
左间距 :-1
右间距 :-1
首行缩进 :-1
文字格式 :null
run size 0
------------------------------一个Element-------------------------------------
对齐方式 :1
左间距 :-1
右间距 :-1
首行缩进 :-1
文字格式 :null
run size 1
FontName :null
fontSize :14
文字内容 :系统总体结构:
------------------------------一个Element-------------------------------------
对齐方式 :4
左间距 :-1
右间距 :-1
首行缩进 :-1
文字格式 :正文编号
run size 1
FontName :null
fontSize :12
图片 :
------------------------------一个Element-------------------------------------
对齐方式 :1
左间距 :-1
右间距 :-1
首行缩进 :-1
文字格式 :null
run size 0
------------------------------一个Element-------------------------------------

Process finished with exit code 0

设计

 其中 Node 节点,xml 文件,word文件的章节节点 可以互相转化

Handle 类来处理Node 节点,向节点添加删除数据,添加删除节点,

ContentService 根据不同的需求生成不同的报告内容,并存入本地文件

实现

第一步:word节点 文件转化为 xml 配置文件

Word 中的节点结构

  public static void main(String[] args) {
        IExportHandle handle = new WordExportHandle();
        handle.loadDocx("需求规格说明书");
        handle.saveAsTemplateConfig(0,"需求规格说明书.xml");
    }
public void loadDocx(String docxPath) {
        //只读文字不读图片
        try {
            XWPFDocument document = new XWPFDocument(new FileInputStream(docxPath)).getXWPFDocument();
            XWPFStyles styles = document.getStyles();
            HashMap<String ,String> map = new HashMap<>();
            List<IBodyElement> elements = document.getBodyElements();
            for (IBodyElement element : elements) {
                if (element instanceof XWPFParagraph) {
                    XWPFParagraph pf = (XWPFParagraph) element;
//                    List<XWPFRun> runList = pf.getRuns();
                    String paStyle = pf.getStyle();
                    if(paStyle == null){
                        System.out.println("TODO");
                    }else {
                        String styleVal = styles.getStyle(paStyle).getCTStyle().getName().getVal();
                        switch (styleVal) {
                            case "heading 1": {
                                INode node = new WordNode();
                                node.setName("chapter");
                                node.setFontSize(14f);
                                node.setTitle(pf.getText().trim());
                                node.setTitleFont("宋体");
                                node.setFontStyle("0,1");
                                rootNode.addChild(node);
                                map.put("heading 1", pf.getText().trim());
                                break;
                            }
                            case "heading 2": {
                                INode node2 = new WordNode();
                                node2.setName("chapter");
                                node2.setFontSize(12f);
                                node2.setTitle(pf.getText().trim());
                                node2.setTitleFont("宋体");
                                node2.setFontStyle("0,1");
                                addNodeByNodePath(map.get("heading 1"),node2);
                                map.put("heading 2", pf.getText().trim());
                                break;
                            }
                            case "heading 3": {
                                INode node3 = new WordNode();
                                node3.setName("chapter");
                                node3.setFontSize(10.5f);
                                node3.setTitle(pf.getText().trim());
                                node3.setTitleFont("宋体");
                                node3.setFontStyle("0,1");
                                addNodeByNodePath(map.get("heading 1") + "|" + map.get("heading 2"),node3);
                                map.put("heading 3", pf.getText().trim());
                                break;
                            }
                            case "heading 4": {
                                INode node4 = new WordNode();
                                node4.setName("chapter");
                                node4.setFontSize(10.5f);
                                node4.setTitle(pf.getText().trim());
                                node4.setTitleFont("宋体");
                                node4.setFontStyle("0,1");
                                addNodeByNodePath(map.get("heading 1") + "|" + map.get("heading 2") + "|" + map.get("heading 3"),node4);
                                map.put("heading 4", pf.getText().trim());
                                break;
                            }
                        }
                    }
                } else if (element instanceof XWPFTable) {
                   // System.out.println("表格................");
                    XWPFTable table = (XWPFTable) element;
                    List<XWPFTableRow> listRow = table.getRows();

                    for (XWPFTableRow row : listRow) {

                        List<XWPFTableCell> cellList = row.getTableCells();
                        for (XWPFTableCell cell : cellList) {
                            //单元格里面的内容
                            List<XWPFParagraph> cellParagraphList = cell.getParagraphs();
                            for (XWPFParagraph phCell : cellParagraphList) {
                               // System.out.print("" + phCell.getText() + "_Cell|");
                            }
                            //System.out.println("..");
                        }
                    }

                }

            }

            System.out.println("结束");
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
    public void saveAsTemplateConfig(int saveType,String configPath) {
        //保存node 节点
        org.dom4j.Document document = DocumentHelper.createDocument();// 建立document对象,用来操作xml文件
        org.dom4j.Element rootElement = document.addElement("root");// 建立根节点
        saveBfs(rootNode,rootElement);

        try {
            XMLWriter writer = new XMLWriter(new FileWriter(configPath));
            writer.write(document);
            writer.flush();
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

生成xml结构

<?xml version="1.0" encoding="utf-8"?>

<root>
  <chapter title="概述" font="宋体" fontsize="14.0" fontstyle="0,1">
    <chapter title="编写目的" font="宋体" fontsize="12.0" fontstyle="0,1"/>
    <chapter title="适用范围" font="宋体" fontsize="12.0" fontstyle="0,1"/>
    <chapter title="名词解释" font="宋体" fontsize="12.0" fontstyle="0,1"/>
    <chapter title="参考资料" font="宋体" fontsize="12.0" fontstyle="0,1"/>
  </chapter>
  <chapter title="系统综述" font="宋体" fontsize="14.0" fontstyle="0,1">
    <chapter title="系统介绍" font="宋体" fontsize="12.0" fontstyle="0,1">
      <chapter title="关键业务流程" font="宋体" fontsize="10.5" fontstyle="0,1"/>
    </chapter>
    <chapter title="主要特征" font="宋体" fontsize="12.0" fontstyle="0,1"/>
    <chapter title="产品/项目中的用户角色" font="宋体" fontsize="12.0" fontstyle="0,1"/>
  </chapter>
  <chapter title="功能性需求描述" font="宋体" fontsize="14.0" fontstyle="0,1"/>
  <chapter title="需求功能列表" font="宋体" fontsize="14.0" fontstyle="0,1"/>
  <chapter title="系统接口需求" font="宋体" fontsize="14.0" fontstyle="0,1">
    <chapter title="外部接口" font="宋体" fontsize="12.0" fontstyle="0,1"/>
    <chapter title="内部接口" font="宋体" fontsize="12.0" fontstyle="0,1"/>
  </chapter>
  <chapter title="系统的非功能性需求" font="宋体" fontsize="14.0" fontstyle="0,1">
    <chapter title="稳定性" font="宋体" fontsize="12.0" fontstyle="0,1"/>
    <chapter title="安全性" font="宋体" fontsize="12.0" fontstyle="0,1"/>
    <chapter title="用户界面需求" font="宋体" fontsize="12.0" fontstyle="0,1">
      <chapter title="操作简捷" font="宋体" fontsize="10.5" fontstyle="0,1"/>
      <chapter title="用户界面友好" font="宋体" fontsize="10.5" fontstyle="0,1"/>
      <chapter title="数据校验" font="宋体" fontsize="10.5" fontstyle="0,1"/>
    </chapter>
    <chapter title="运行需求" font="宋体" fontsize="12.0" fontstyle="0,1">
      <chapter title="数据库要求" font="宋体" fontsize="10.5" fontstyle="0,1"/>
      <chapter title="应用服务器要求" font="宋体" fontsize="10.5" fontstyle="0,1"/>
      <chapter title="故障处理" font="宋体" fontsize="10.5" fontstyle="0,1"/>
      <chapter title="用户文档" font="宋体" fontsize="10.5" fontstyle="0,1"/>
    </chapter>
    <chapter title="其它需求" font="宋体" fontsize="12.0" fontstyle="0,1">
      <chapter title="支持软件环境" font="宋体" fontsize="10.5" fontstyle="0,1"/>
    </chapter>
  </chapter>
  <chapter title="双方确认" font="宋体" fontsize="14.0" fontstyle="0,1"/>
</root>

第二步:向XML配置文件加入内容,或者通过Service类动态添加内容,内容包括文字和表格

1.修改XML文件生成pdf 或word 文件,向适用范围中添加段落和表格

<?xml version="1.0" encoding="utf-8"?>


<!--...fontstyle  0 标准,1 加粗, 2 斜体, 3 又粗又斜 ,4 带有下划线 ,8 带有删除线 ,多选,单选 -->
<!--...textstyle 0 靠左,1 居中,2 靠右 非必填 默认靠左-->
<!--...cell_text_style 单元格文字风格,0靠左,1居中,2靠右 非必填,默认居中 row_span.横向单元格跨度,col_span 垂直单元格跨度,默认1-->
<!--...title font fontsize 章节,段落,必填属性,firstLineIndent(首行缩进) indentationLeft(左侧对齐间距) indentationRight(右侧对齐间距) 非必填,默认为0 -->
<!--...表格与上一个段落的空白宽度 10f -->


<root>
    <chapter title="概述" font="宋体" fontsize="14.0" fontstyle="0,1">
        <chapter title="编写目的" font="宋体" fontsize="12.0" fontstyle="0,1"/>
        <chapter title="适用范围" font="宋体" fontsize="12.0" fontstyle="0,1">
            <paragraph font="宋体" fontsize="12" fontstyle="0,1" firstLineIndent="30" indentationLeft="20" indentationRight="20" textstyle="1">需求规格说明书是适用于薪酬管理系统项目的过程。</paragraph>
            <table widths="0.1,0.5,0.1,0.1,0.1,0.1">-->
                                <cell><paragraph font="宋体" fontsize="10.5" fontstyle="1">部门</paragraph></cell>
                                <cell><paragraph font="宋体" fontsize="10.5" fontstyle="1">职位</paragraph></cell>
                                <cell><paragraph font="宋体" fontsize="10.5" fontstyle="1">需求确认范围</paragraph></cell>


                                <cell><paragraph font="宋体" fontsize="10.5" fontstyle="0">客服部</paragraph></cell>
                                <cell><paragraph font="宋体" fontsize="10.5" fontstyle="0">大区经理,客服经理,客服主管,客服专员</paragraph></cell>
                                <cell><paragraph font="宋体" fontsize="10.5" fontstyle="0">税率,薪资项目,薪资模板,薪资计算</paragraph></cell>

            </table>
        </chapter>
        <chapter title="名词解释" font="宋体" fontsize="12.0" fontstyle="0,1"/>
        <chapter title="参考资料" font="宋体" fontsize="12.0" fontstyle="0,1"/>
    </chapter>
    <chapter title="系统综述" font="宋体" fontsize="14.0" fontstyle="0,1">
        <chapter title="系统介绍" font="宋体" fontsize="12.0" fontstyle="0,1">
            <chapter title="关键业务流程" font="宋体" fontsize="10.5" fontstyle="0,1"/>
        </chapter>
        <chapter title="主要特征" font="宋体" fontsize="12.0" fontstyle="0,1"/>
        <chapter title="产品/项目中的用户角色" font="宋体" fontsize="12.0" fontstyle="0,1"/>
    </chapter>
    <chapter title="功能性需求描述" font="宋体" fontsize="14.0" fontstyle="0,1"/>
    <chapter title="需求功能列表" font="宋体" fontsize="14.0" fontstyle="0,1"/>
    <chapter title="系统接口需求" font="宋体" fontsize="14.0" fontstyle="0,1">
        <chapter title="外部接口" font="宋体" fontsize="12.0" fontstyle="0,1"/>
        <chapter title="内部接口" font="宋体" fontsize="12.0" fontstyle="0,1"/>
    </chapter>
    <chapter title="系统的非功能性需求" font="宋体" fontsize="14.0" fontstyle="0,1">
        <chapter title="稳定性" font="宋体" fontsize="12.0" fontstyle="0,1"/>
        <chapter title="安全性" font="宋体" fontsize="12.0" fontstyle="0,1"/>
        <chapter title="用户界面需求" font="宋体" fontsize="12.0" fontstyle="0,1">
            <chapter title="操作简捷" font="宋体" fontsize="10.5" fontstyle="0,1"/>
            <chapter title="用户界面友好" font="宋体" fontsize="10.5" fontstyle="0,1"/>
            <chapter title="数据校验" font="宋体" fontsize="10.5" fontstyle="0,1"/>
        </chapter>
        <chapter title="运行需求" font="宋体" fontsize="12.0" fontstyle="0,1">
            <chapter title="数据库要求" font="宋体" fontsize="10.5" fontstyle="0,1"/>
            <chapter title="应用服务器要求" font="宋体" fontsize="10.5" fontstyle="0,1"/>
            <chapter title="故障处理" font="宋体" fontsize="10.5" fontstyle="0,1"/>
            <chapter title="用户文档" font="宋体" fontsize="10.5" fontstyle="0,1"/>
        </chapter>
        <chapter title="其它需求" font="宋体" fontsize="12.0" fontstyle="0,1">
            <chapter title="支持软件环境" font="宋体" fontsize="10.5" fontstyle="0,1"/>
        </chapter>
    </chapter>
    <chapter title="双方确认" font="宋体" fontsize="14.0" fontstyle="0,1"/>
</root>

 修改main方法

package com.spasvo.test;

import com.spasvo.export.handle.IExportHandle;
import com.spasvo.export.handle.impl.PdfExportHandle;

public class Test4 {

    public static void main(String[] args) {
        IExportHandle handle1 = new PdfExportHandle();
        handle1.loadConfig("需求规格说明书.xml");
        handle1.writeExport("需求规格说明书.pdf");
    }
}

 执行结果

第三步:动态加入内容

package com.spasvo.test;

import com.spasvo.export.handle.IExportHandle;
import com.spasvo.export.handle.impl.PdfExportHandle;
import com.spasvo.export.service.DemandContentService;
import com.spasvo.export.service.impl.DemandContentServiceImpl;

import java.io.File;


public class Test4 {

    public static void main(String[] args) {
        IExportHandle handle1 = new PdfExportHandle();
        handle1.loadConfig("需求规格说明书.xml");
        DemandContentService service = new DemandContentServiceImpl(handle1);

        //添加用户列表
        service.setUseRange();
        service.saveDemand("需求规格说明书.pdf");
    }
}

 动态添加内容 的方法

public void setUseRange() {
        String nodePath = "概述|适用范围";
        ContentConfigBean configBean = new ContentConfigBean();
        if(handle instanceof PdfExportHandle){
            com.itextpdf.text.Paragraph paragraph1 = new com.itextpdf.text.Paragraph("用户列表", PdfExportHandle.setFont(configBean.getParagraphFont(), configBean.getParagraphFontSize(), "0"));
            paragraph1.setFirstLineIndent(configBean.getParagraphFirstLineIndent());
            paragraph1.setIndentationLeft(configBean.getParagraphIndentationLeft());
            handle.addPdfSectionContent(nodePath,paragraph1);

            float [] widths = {0.5f,0.5f};
            configBean.setTableWidths(widths);
            ArrayList<String> tableHeaderList = new ArrayList<>(Arrays.asList("部门","职位"));
            PdfPTable table = new PdfPTable(configBean.getTableWidths());
            //表头
            for(String strHeader :tableHeaderList){
                Paragraph phHeader  = new Paragraph(strHeader, PdfExportHandle.setFont(configBean.getCellParagraphFont(), configBean.getCellParagraphFontSize(), "0"));
                PdfPCell cellHeader = new PdfPCell(phHeader);
                cellHeader.setRowspan(configBean.getCell_row_span());
                cellHeader.setColspan(configBean.getCell_col_span());
                cellHeader.setHorizontalAlignment(configBean.getCell_text_style());
                table.addCell(cellHeader);
            }
            class DemandUserListTable{
                public DemandUserListTable(String depart, String position){
                    this.depart = depart;
                    this.position = position;

                }
                public String depart;
                public String position;
            }

            ArrayList<DemandUserListTable> listuserTable = new ArrayList<>(Arrays.asList(new DemandUserListTable("客服部","客服经理,客服主管,客服专员")));
            //表格内容
            for(DemandUserListTable bean :listuserTable){
                ArrayList<String> listRow = new ArrayList<>();
                listRow.add(bean.depart);
                listRow.add(bean.position);

                for(String str : listRow){
                    Paragraph phCase  = new Paragraph(str, PdfExportHandle.setFont(configBean.getCellParagraphFont(), configBean.getCellParagraphFontSize(), configBean.getCellParagraphFontStyle()));
                    PdfPCell cellCase = new PdfPCell(phCase);
                    cellCase.setRowspan(configBean.getCell_row_span());
                    cellCase.setColspan(configBean.getCell_col_span());
                    cellCase.setHorizontalAlignment(configBean.getCell_text_style());
                    table.addCell(cellCase);
                }

            }
            handle.addPdfSectionContent(nodePath,table);
        }

    }

 生成结果

 


猜你喜欢

转载自blog.csdn.net/mp295345033/article/details/119055263