【Andoird】Apache POI 实现Word模板生成文档的办法

这是一个帮朋友写的一个小软件,顺便锻炼自己工程代码的能力QAQ,源码在后面有连接。

软件的需求就是根据自己的需要往一个固定格式的word表格模板中添加文字或者图片,然后按照自己的需要生成新的word文档并查看。

上网找了很多关于在android环境下如何解析office文档的博客,发现一些比较好的例如POI Docx4j IText 或者是收费的AsPose.Word等等,看起来都不错。不过用起来都是蛮坑的。

目录

一.环境配置

二.文档的显示与打开

三.模板的添加

四.模板数据编写和预览。

五.模板生成

六.源码连接



一.环境配置

       几点吐槽

首先是Apache POI,最先我用的也是它,但是之前我下的是比较新的版本,载入解析.docx文档(Word2007以上)的包一直都有点问题,貌似是包里有什么类被重写了,就一直build报错。

 随后我上网看了很多人的解决办法也没有解决,遂只好以.doc文档(Word2003)来解析模板。但是当我完成界面的工程代码的时候,又有了一个新问题,就是解析.doc的时候是可以替换文档中的文字的。但是HWPFDocument这个类解析出来的word没办法添加图片,stackoverflow上某大佬直接就说这个包不能向.doc文件中添加图片,要想添加图片还是要导入解析.docx的一系列的包。没办法,试了很多次,每次都buld失败,不是缺类,就是重复多类,遂想放弃。

 在网上听别人说Docx4j 是开源的,并且解析docx不错,例子也多。遂准备抛弃之前的想法学习新的包。但是这个东西有几个大坑:首先,你解析的速度也太慢了吧,我一个单表格模板要二三十秒,要是以后文档大一点,还不等死?其次,为了用这个包,要安装一堆的其他的包,还要考虑版本的问题;这个包在github上有很多很好的例子,但是,你的例子都是Eclipse工程啊,让我用AS的情何以堪。不过这些都不是大问题,最大的问题是,插入图片的方法我解决了,但是它在别的地方搞事情,替换模板文字的时候说xml解析错误。。。。。逛了一圈论坛说jdk1.8下的xml有自己的解析方式,所以要降jdk版本到1.7.写了小软件还要我自己降jdk版本。。。既然你这么麻烦,那就江湖再见吧。。。

随后我考虑了java下的itext包,这个东西虽然不能写doc ,但是人家能写pdf,还能往pdf中插入图片,最重要的一点是它同Java2word Jacob 之类的包不一样的是它不需要dll文件,也能移植到安卓上,遂拿来用,但是其写中文能力贼差,所以我考虑将之前成型的doc文件转换成pdf再实现插图片的功能不就完事了。但是用POI转pdf要先转html..工程量太大还慢,遂放弃,找了AsPose.Word这个收费的来转,但是人家要钱,不给钱就在你的文档首页插红字,还去不掉,有点小恶心。

绕了一圈,还是回到原点,也不知道怎么回事,我将POI的版本降到3.10.所有的包就能成功安装上了,并且还是一键安装的,但是之前我也做过类似的尝试,都失败了,看来配置环境也是一门玄学。不过不管怎样,成功了就好。

     正篇

  其实配置环境很简单,在app:build 的 dependencies{}下添加一行依赖就行了:
compile 'fr.opensagres.xdocreport:org.apache.poi.xwpf.converter.xhtml:1.0.5'

说实话我之前就看了某博客大佬介绍了这样做,但之前都是build失败的,后来无心插柳成功了,可能我绕了一圈编译器自己不忍心给我过了吧。玩笑归玩笑,配置的是POI3.10版本,不过最好的话在andorid下排除这一坨文件,这个是之前我自己导包按照指示加的,可能有点用吧:

packagingOptions {
        exclude 'META-INF/DEPENDENCIES.txt'
        exclude 'META-INF/LICENSE.txt'
        exclude 'META-INF/NOTICE.txt'
        exclude 'META-INF/NOTICE'
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/DEPENDENCIES'
        exclude 'META-INF/notice.txt'
        exclude 'META-INF/license.txt'
        exclude 'META-INF/dependencies.txt'
        exclude 'META-INF/LGPL2.1'
        exclude 'readme.html'
        exclude 'license.html'
        exclude 'META-INF/eclipse.inf'
    }

其次是扩大内存,这个有点必要的:

dexOptions {
        incremental true
        preDexLibraries = false
        jumboMode = false
        javaMaxHeapSize "2048M"
    }

好了,如果编译成功了,就可以在代码中用它解析docx并为所欲为了。


二.文档的显示与打开

首先是打开文档列表,这个要重载BaseAdapter类,好像每次弄类似列表的东西的时候都要这么写,然后在ViewHolder中重载Layout布局。我觉得这个还是比较难写的,不看以前的代码根本写不出来。实现的界面如下所示:

【Andoird】Apache POI 实现Word模板生成文档的办法_第1张图片

其中的各种属性是读取手机上目录中的文件获得的,对每一个List点后面三个点的图片可以显示隐藏控件,删除或者打开文件,写得比较丑,也没考虑动画,就这样将就下。1.docx是我放在assets中,安装的时候自动写进去的,做一个示例。

然后就是打开word文档,最开始用POI写的时候看别人博客是将.doc文件转成html文件,再用WebView显示。但是不得不说HWPFDocument这个类属实弟弟,解析的慢就算了,代码还一坨一坨的,还要一张一张地将word中的文档解析出来保存到本地,然后再显示,还要考虑WebView显示不全的样子。

后来我发现,用第三方应用打开不需要手机上装WPS,只要你手机上有UC浏览器或者QQ浏览器(可能还有其他,但是我目前用了两个),就能自己加载插件显示文档了。这里推荐QQ浏览器,因为UC的插件经常出问题,有时候我的路径对了告诉我文件不存在,害的我调试了半天的bug,一度以为自己代码出问题了。

【Andoird】Apache POI 实现Word模板生成文档的办法_第2张图片

如上是QQ浏览器插件打开的效果,比POI加WebView自己写的效果好多了。所以即使是后来用了.docx文档的包,即使那个转Html简单,我还是放弃了WebView用法。加上我之前想当然的以为鹅厂有API可以将手机上的文件通过第三方软件转到QQ上发出去,后来发现我还是太天真,人家只能发图片和文本,文档就算了。但是将文档用QQ浏览器打开就能保存到云端,也就能发到电脑上了,一举两得,岂不美哉QAQ。

这里有个坑就是Android6.0(SDK>24)以上URI有点问题,第三方不能直接对文件加载URI。这个我在后来的拍照添加图片中也遇到过。解决办法是这样:

1.在Mainfest.xml中添加:

android:authorities="包名.wordgenerate.fileprovider"

2.然后新建一个xml,设置外部存储的地址:



    

3.在需要调用uri的地方,当SDK<24,就用:

Uri uri = Uri.fromFile(tempFile);

当SDK>24,就用:

Uri uri  = FileProvider.getUriForFile(this, "包名.wordgenerate.fileprovider", tempFile);

不过现在很少见android6.0以下的手机了吧,自动忽略。。


三.模板的添加

这里考虑到我的模板要加数据库的原因,所就直接写在了手机里面,根据/mode/下的文件夹个数来判断模板个数,目前只有帮我朋友写的需求的一个模板,后续可以添加(比如添加我们学校的请假条模板),并且我做了防止删除的措施,当/mode/下的模板缺少时会自动补充(很像流氓软件吧),但是有好事者在里面新建文件夹我还没处理,后续判断会处理一下。

这部分也是继承BaseAdapter写的列表:

【Andoird】Apache POI 实现Word模板生成文档的办法_第3张图片

目前只有一个,先完成需求嘛。。。


四.模板数据编写和预览。

这个只要写一个界面类就行了,很无耻地,我很多View都是用github上别人写的轮子的,比如时间选择器,图片添加功能等等。compile中加一行代码就行了,或者整段搬运。

毕竟自己写工程量有点大,可能还不好看。最后的界面如图:

【Andoird】Apache POI 实现Word模板生成文档的办法_第4张图片

将该写的数据写好,并将要替换模板中的文本保存到HashMap里面,对于图片路径和要在模板中写的非替换类文本保存在List中。

这里我本来打算写个预览加载word的,但是看起来不清楚,所以就改用了TableView显示(这个TableView也是compile github上的。。。)

【Andoird】Apache POI 实现Word模板生成文档的办法_第5张图片

这里要说明一下,为了契合需求,我对出现的公司名做了个小数据库,可以随时选择,添加,删除。


五.模板生成

首先准备模板,然后在该替换的文本的地方用${}做标记,比如${公司名}。按照stackoverflow上的提示,这个替换符号要一气呵成写好,不能先写${}再在里面添加文字,不然解析出来是分开的,就不能替换了。或者将word转成xml文件解析也行。

如何替换文本和在表格中添加文字以及添加图片,可以去看我在github上的源码,或者查询相关的博客和论坛。这里有个坑就是POI解析的word,表格内和表格外是不一样的,所以对于带表格的模板,需要替换两次,一次是段落中的内容,一次是表格中的内容。

对于图片,POI中只要有图片在手机上的路径可以插入到文档中了,就是新建一个段落,然后插入图片。

最后在TableView下开一个线程生成文档,生成后返回主界面。这个我觉得没多少自由,什么模板就做什么模板的生成界面, 然后获得输入数据,最后调用模板生成,都是定死的,玩不了花。下面可以看到成功地根据模板生成并查看docx文档:

【Andoird】Apache POI 实现Word模板生成文档的办法_第6张图片

【Andoird】Apache POI 实现Word模板生成文档的办法_第7张图片


六.源码连接

         github源码连接:https://github.com/Emmonss/WordGenerate

你可能感兴趣的:(android)