1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > [实用][更新中]Java Apache POI 打印Word文档工具(含文本替换 动态表格功能)

[实用][更新中]Java Apache POI 打印Word文档工具(含文本替换 动态表格功能)

时间:2021-05-12 12:21:56

相关推荐

[实用][更新中]Java Apache POI 打印Word文档工具(含文本替换 动态表格功能)

[实用]【更新中】Java Apache POI 打印Word文档工具(含文本替换,动态表格功能)

基于Apache POI对Word进行操作一、基于Apache POI封装的word文档工具V1.0介绍二、Apache POI 知识==apache poi官方文档:/==1. jar包(maven的,这个不多做解释了)2. poi的类3.常用的方法:三、工具使用教程(不需要了解基础知识,直接快速使用)1. 占位符的约定规则2. word模板编辑3. Java准备数据和导出word四、GIT-HUB 地址

基于Apache POI对Word进行操作

你好!这是由一个刚毕业的学生,由于项目所需,需要通过Java后台的方式打印Word文档,因此在对大量能操作word的Java API中,选择了Apache POI。以下将简单分享一下这个在学习和开发这个基于POI的word文档打印工具时,一些心得:

Apache POI在操作word上非常费劲,在选型的过程中还遇到过很多,如Freemarker,freemarker本人没有研究,但是大概知道是基于word保存为xml后,然后用占位符替换的方式,对xml中整段整段的内容进行文本替换,最终输出word文档,就能得到word文档。Freemarker的缺点(只是看别人总结的,自己没有求证)

1.freemark在进行文本替换的时候,很难保持原有的样式

2.在好不容易编辑好word模板后,转成xml的时候,还需要打开xml对里面的内容进行核对,听说会由于word文档一些字符串处理不好,倒是xml中 标签的缺失or错误,需要手动处理。如果word文档少还好,但是如果文档内容多,那就很麻烦(up主的项目所需打印的word文档就很多内容)Apache POI能很好的保持原来的样式,在理解底层接口原理后,还是挺好操作的,但是对于使用者来说,你们就不需要理解底层原理,因为我已经高度封装好了。

接下来,我将会对Apache POI进行讲解。以及我这套工具的一些底层原理,目的是为了和各位大牛交流,以及有人有定制需求的话,可以基于我这个工具进行改写,来适应不同的项目。如果你不想学原理,则只需要跳过本段内容,到最后一小节,我会用最黑盒的方式,来快速教大家上手使用我这套工具

(由于本人技术有限,而且公文写作能力一般,因此有口误的地方请大家指出,并且欢迎大家提出更好的解决建议)

(本工具现在是V1.0版本,代码方面也还没进行过多优化,性能暂时还OK,但还有很大优化空间 )

一、基于Apache POI封装的word文档工具V1.0介绍

已实现的功能

文本替换静态表格的文本替换动态表格(行的变化)动态表格(整个表格动态增减)动态表格(整个表格动态增减,与上面不同的是,这个表格会附带表格标题以及跟随文本图片插入

后期可能扩展的方向

富文本

本工具与网上其他POI打印工具类对比 特点

文本替换可以灵活的在word文档的任意位置,并且不会受到左右其他文字的影响(网上绝大部分,只是简单封装POI,实际上他们的文本替换需要占据一整行,这是极度不灵活的)文本替换功能,在编辑模板的时候,可以设置它的样式。文本替换的时候,会根据你给定的样式替换文本。表格内支持样式自定义,很多百度其他封装工具,都不支持样式自定义动态表格比较灵活,支持一整块的扩展。插入图片支持自定义大小

简单例子

(1)word模板

(2)通过apache poi打印后

二、Apache POI 知识

apache poi官方文档:/

1. jar包(maven的,这个不多做解释了)

<properties><java.poi.version>4.0.0</java.poi.version></properties><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>${java.poi.version}</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml-schemas</artifactId><version>${java.poi.version}</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>${java.poi.version}</version></dependency>

2. poi的类

XWPFDocument:一个word文档对应一个documentXWPFHeaderFooterPolicy:文档的页眉页脚(可以设置每一页的页眉页脚不同,也可以统一一个默认的页眉页脚作为全局,一般来说,后者用的比较多,因此我的工具里也是后者)XWPFTable:一个表格对应一个XWPFTable对象XWPFTableRow:一个表格的每一行对应一个XWPFTableRowXWPFTableCell:table中的每一个单元格对应一个XWPFTableCell(Cell特别特殊,他的里面相当于一个XWPFDocument,也就是说,一个单元格里面,可以进行插入文字,图片,表格等操作,类似于documentXWPFParagraph:一段文本对应一个XWPFParagraph(注意,是一段文本,后面会解释合为一段文本)XWPFRun:一处具有相同样式的文本(一个XWPFParagraph里面包含多个XWPFRun)

他们之间的关系结构如图所示(为了更方便大家的理解,用一个图表示)

因此:

一个Document包含多段Paragraph和多个Table。一个Paragraph包含多个Run(一个Paragraph也可能只有一个Run,需要参考这一段文字中是否有样式不同的文字)一个Run就一个text(一段文字中相同样式的一段文字)一个Table包含多个TableRow(也就是一个表格有多少行,就有多少个TableRow。注意:一个Table没有行,这个table还是存在,只不过不会显示,如果要让一个table完全消息,必须调用document的removeBodyElement(int index))一个TableRow包含多个TableCell(也就是一行中有很多个单元格)一个TableCell,就相当于一个小的document。(一般不会对单元格进行特殊的操作,都是一段文字,因此tableCell里面的Paragraph起显示文字的作用)附加:document里面维持一个bodyElement的数组,一个Paragraph或者一个Table对象就对应一个IBodyElement。由于document将段落和表格分开了两个List保存,因此我们无法知道,一个表格在两段文字中的位置或者一段文字在两个表格的位置。因此这一个bodyElement[]就起了能对word文档每个元素进行定位的功能。举了例子:文档结构:段落1,表格1,段落2。他的段落列表:段落1,段落2。他的表格列表:表格1我们无法通过两个数组,知道表格1在两段文字的哪里,因此借助document的bodyElement[]可以得到这样的关系,段落1,表格1,段落2在这里可以清晰的知道,表格1位于两段文字中间。而bodyElement也是非常重要的,能让你定位文档任何一个位置,操作文档内容

3.常用的方法:

获取XWPFDocument的段落列表

获取XWPFDocument的表格列表

读取整一个段落的所有文字内容

String text = paragraphs.get(0).getText();

4.设置段落的样式

//每一个XWPFParagraph可以设置对齐方式,边框,加粗等等,自己看里面的方法即可String text = paragraphs.get(0).setXXX();

5.获取段落的Run,并修改这段Run的文字

//获取段落的所有RunList<XWPFRun> runs = paragraph.getRuns();//删除某一个Runparagraph.removeRun(下标);//增加一个没有文字的Runparagraph.createRun();//修改文字(覆盖原文本,追加的话则不使用第二个参数)runs.get(0).setText("第二个参数表示从哪个下标开始修改字符串", 0);//一个Run里面又有很多样式可以选择,如加粗,斜体等等runs.get(0).setXXX();//如果需要将一整个段落都替换成一个新的文本while (paragraph.getRuns().isEmpty()){paragraph.removeRun(0);}paragraph.createRun().setText("新文本");//上面的代码会导致,原来的Run样式都没了,新的Run使用默认的样式。如果想保留原来Run的样式,可以删除的时候不要删掉全部Run,如while (paragraph.getRuns().size() > 1){paragraph.removeRun(1);}paragraph.getRuns().get(0).setText("新文本", 0);

由于要工作,暂没时间写完(后续更新)

三、工具使用教程(不需要了解基础知识,直接快速使用)

1. 占位符的约定规则

段落文本替换:@${t_*}@静态表格(文本替换): ${at_static_*} 静态文档里面需要文本替换的地方,使用@${t_*}@ 动态表格(行动态): ${at_row_*}动态表格(整个表格增减): ${at_max01_*}动态表格(整个表格增减,附带标题和跟随文本): ${at_max02_*}

其中:

不同表格类型的命名定义,需要放在每个表格的第一行第一列,任何表格除非不需要替换内容,否则都需要在原表格的上方增加一行,并在第一行第一列设置表格名(打印时,第一行会被去掉)普通文本:@${t_*}@是替换文本的内容,这几个字符都必须使用相同的样式,并且他的样式决定了打印后文本替换的样式。两边的@字符需要设置独立的样式,并且必须独占一个XWPFRun(也就是@与的相邻的字符,样式不一样,我的做法是给@加粗并且变为指数)静态表格(文本替换): ${at_static_*}。说明表格的行数列数固定,只是需要填充不同的文字内容。动态表格(行动态): ${at_row_*},表格的列是固定的,行数不固定。根据给定的List数组决定有多少行。动态表格(整个表格增减): ${at_max01_*}。表格的行,列是固定的。动态表格(整个表格增减,但会携带标题和随后文本): ${at_max02_*}。表格行列固定,但是不同的是,表格上方和下方会跟随一段文字在了解Apache POI后,是可以自己自定义各种各样的规则,上面的规则仅是针对我遇到的项目所需,大部分情况下,是已经够用了。可能会有人需要,动态增减整个表格,并且每个表格里面的行不固定,这些都是可以定制的。

2. word模板编辑

建议使用WPS编辑word模板,因为目前Apache Poi对office不太友好,在我约束的规则下,我发现一个 占位符无法对应一个XWPFRun,在处理上非常不方便

( * 表示通配符,可以是任意字符)

(1)文本替换,使用@${t_*}@的方式(其中两边的@,需要独占一种样式)

PS: 两边的@是必不可少的,并且需要使用一种与周围字符样式不同的样式。我的做法通常是,加粗+变为指数。在进行打印的过程中, ${xxx}的内容会被你指定的文本替换掉,两边的@也会被删掉。

(2)静态表格(文本替换)

表格上方多增加一行,在第一行第一列中指定静态表格${at_static_*}

表格内需要进行文本替换的地方,与普通文本替换的规则一样

(3)动态表格(行动态)

表格上方增加一行,指定动态表格(行动态)${at_row_*}-表格一定要有3行,第一行指定动态表格,第二行是表格头的标题,第三行则是允许你设置每一个单元格内容的样式,在后续动态生成的每一行,都与这一行对应单元格的样式一致

(4)动态表格(整个表格动态)

表格的行列固定,表格最上方新增一行指定动态表格规则${at_max01_*}目前只允许整个表格行列固定的形式动态增减表格,若有定制需求,可以在简单研究POI原理后,对工具代码进行定制。

(5)动态表格(携带标题和跟随文本)

表格的行列固定,表格上方新增一行指定规则${at_max02_*}请注意看,最外层有一层虚线,它是一个1行1列的Table,边框使用虚线,在打印时,虚线是不会被显示的(实际上这个不是虚线,是边框设置为none后的效果,它和真正的虚线边框是不同的)之所以要设计用一个一行一列的单元格包住整个 动态表格。是因为,POI的原理是 段落和表格 分开处理的,为了让整个表格更加方便的复制,因此用了一个 单元格包住整个内容进行动态增减。PS:标题文字紧挨着表格紧挨着跟随文本。表格样式,单元格样式以及文本样式都可以自定义。如果不需要标题跟随文本,在Java可以设空串。(如有定制需求,可以询问up或者自行研究源代码

3. Java准备数据和导出word

(1)封装好的工具简单介绍

PoiWordUtil 封装好的打印word工具,里面只有一个公共方法。PoiWordKeyMatchRule 这里设置了4种输出规则即对应上方的文本替换,静态表格,动态表格等。使用的是通配符匹配算法对 ${xxx} 进行规则的匹配。IPoiWordTable接口:所有Table表格的接口,里面简单的定义了 行,列,以及每个单元格内容的二维数组。PoiWordAutoTable实现类:这个对应动态表格(整个表格动态) at_max01_*PWATwithHeaderBottom实现类:这个对应动态表格(携带标题和跟随文本) at_max02_*

(2) Java对应word模板DEMO的示例

//word模板的路径String inputUrl = "F:\\poidemo\\TESTPOI.docx";//输出的位置(可以不存在文件)String outputUrl = "F:\\poidemo\\OUTPUT.docx";//文本替换MapMap<String, String> textMap = new HashMap<>();//动态表格MapMap<String, List<IPoiWordTable>> tableMap = new HashMap<>();//表格为空时,文本替换的Map(这个的用法是,如果某一个表格是不需要显示的,则把他规则的名字放进key里面,value如果设为null,则该表格不显示,如果是文本内容,则这个表格的位置,会被一段文字替换)Map<String, String> noneTableMap = new HashMap<>();//准备数据//文本替换 and 静态表格文本替换 都是放在textMap里textMap.put("t_author", "走在刀剑上的羊");textMap.put("t_email", "448241091@");textMap.put("t_year", "");textMap.put("t_month", "11");textMap.put("t_day", "30");textMap.put("t_poi_cool", "[我不会影响左右两边文字]";//动态表格都放入tableMap中//动态表格(行)PoiWordAutoTable rowTable = new PoiWordAutoTable(2, 3);//指定2行3列的动态行tablerowTable.setCell(0, 0, "row1col1");rowTable.setCell(0, 1, "row1col2");rowTable.setCell(0, 2, "row1col3");rowTable.setCell(1, 0, "row2col1");rowTable.setCell(1, 1, "row2col2");rowTable.setCell(1, 2, "row2col3");tableMap.put("at_row_autoRow", Arrays.asList(rowTable));//如果不需要显示这个表格。表格会隐藏,并在相应位置出现一段文字提示//noneTableMap.put("at_row_autoRow", "暂无数据");//动态表格01,使用PoiWordAutoTable,行列根据原表格固定PoiWordAutoTable data1 = new PoiWordAutoTable(2,2);data1.setCell(0, 0, "企业名称");data1.setCell(0, 1, "xxx");data1.setCell(1, 0, "注册号");data1.setCell(1, 1, "XXX123");PoiWordAutoTable data2 = new PoiWordAutoTable(2,2);data2.setCell(0, 0, "企业名称");data2.setCell(0, 1, "xxx");data2.setCell(1, 0, "注册号");data2.setCell(1, 1, "---x2---");tableMap.put("at_max01_auto", Arrays.asList(data1, data2));//动态表格02,使用PWATwithHeaderBottomPWATwithHeaderBottom pwat1 = new PWATwithHeaderBottom(3,2);//如果标题 或 跟随文本不需要显示内容,则用"" 或 null代替pwat1.setTitle("1.实际控制人:xxx(身份证号:441900XXXXXXX)查询日期:1995年11月23日");//pwat1.setTitle(null);pwat1.setBottom("底部跟随文本");pwat1.setCell(0, 1, "信用卡");pwat1.setCell(1, 0, "账户数");pwat1.setCell(1, 1, "2个");pwat1.setCell(2, 0, "未结清/未注销账户数");pwat1.setCell(2, 1, "2个");PWATwithHeaderBottom pwat2 = new PWATwithHeaderBottom(3,2);pwat2.setTitle("2.实际控制人:xxx(身份证号:xxx)查询日期:11月22日");pwat2.setBottom("底部跟随文本");pwat2.setCell(0, 1, "信用卡");pwat2.setCell(1, 0, "账户数");pwat2.setCell(1, 1, "255个");pwat2.setCell(2, 0, "未结清/未注销账户数");pwat2.setCell(2, 1, "255个");tableMap.put("at_max02_auto", Arrays.asList(pwat1, pwat2));//最后使用工具PoiWordUtil.changWord(inputUrl, outputUrl, textMap, tableMap, noneTableMap);

四、GIT-HUB 地址

再次强调:建议使用WPS编辑word模板,因为我发现如果用office编辑模板,一个占位符无法对应一个XWPFRun,如果各位发现office也能正常编辑 占位符,请留言

/YellowWinterSun/poiWordUtil

最近更新:

12月26日:更新了 图片替换功能

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。