前言
使用 Poi 实现 Android 中根据模板文件生成 Word 文档的功能. 这里的模板文件是 doc 文件. 如果模板文件是 docx 文件的话, 请阅读下一篇文章《PoiDocxDemo[Android 将表单数据生成 Word 文档的方案之二 (基于 Poi4.0.0), 目前只能 java 生成] 》
注意:
POI 4.0.0 is the first release to require Java 8 or newer.
前期准备
1, 下载 poi 相关 jar 包
官网下载地址: http://poi.apache.org/download.html
如果 Windows 系统, 则下载 zip 文件; 如果是 Linux 系统则选择. tar.gz.
将下载后的压缩包解压, 会得到以下文件.
文件(夹)名 | 作用 |
docs | 文档(包括 API 文档和如何使用及版本信息) |
lib | doc 功能实现依赖的包 |
ooxml-lib | docx 功能实现依赖的包 |
LICENSE | |
NOTICE | |
poi-4.0.0.jar | 基础类 |
poi-examples-4.0.0.jar | 不明确,不知道什么作用 |
poi-excelant-4.0.0.jar | excel 功能实现 |
poi-ooxml-4.0.0.jar | docx 功能实现 |
poi-ooxml-schemas-4.0.0.jar | docx 功能实现相关类 |
poi-scratchpad-4.0.0.jar | doc 功能实现 |
2, 制作 docx 模板或者 doc 模板文件
代码分析
1, 可以看到 doc 和 docx 文件分别对应着组件 HWPF 和 XWPF, 而 HWPF 和 XWPF 则对应着 poi-scratchpad 和 poi-ooxml.
官网地址: http://poi.apache.org/components/index.html
使用步骤
一, 项目组织结构图
注意事项:
1, 导入类文件后需要 change 包名以及重新 import R 文件路径
2, Values 目录下的文件 (strings.xml,dimens.xml,colors.xml 等), 如果项目中存在, 则复制里面的内容, 不要整个覆盖
二, 导入步骤
1, 将 poi 相关 jar 文件导入项目中 (Demo 采用的是 module 方式)
引用 jar 文件参考《[Android Studio 安装部署系列] 十七, Android studio 引用第三方库, jar,so,arr 文件》
注意:
解析 doc 文件, 需要引用下面的 jar 文件:
- poi-4.0.0.jar
- poi-scratchpad-4.0.0.jar
libs 目录下的 commons-collections4-4.2.jar
2, 在 poilib 和 App 的 build.gradle 文件中添加以下代码
- poilib
- apply plugin: 'com.android.library'
- Android {
- compileSdkVersion 28
- defaultConfig {
- minSdkVersion 16
- targetSdkVersion 28
- versionCode 1
- versionName "1.0"
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
- }
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
- }
- //poi
- compileOptions {
- sourceCompatibility JavaVersion.VERSION_1_8
- targetCompatibility JavaVersion.VERSION_1_8
- }
- }
- dependencies {
- implementation fileTree(dir: 'libs', include: ['*.jar'])
- implementation 'com.android.support:appcompat-v7:28.0.0'
- testImplementation 'junit:junit:4.12'
- androidTestImplementation 'com.android.support.test:runner:1.0.2'
- androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
- //Poi=doc
- API files('libs/poi-4.0.0.jar')
- API files('libs/poi-scratchpad-4.0.0.jar')
- API files('libs/commons-collections4-4.2.jar')
- }
- App
- apply plugin: 'com.android.application'
- Android {
- compileSdkVersion 28
- defaultConfig {
- applicationId "com.why.project.poidemo"
- minSdkVersion 16
- targetSdkVersion 28
- versionCode 1
- versionName "1.0"
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
- }
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
- }
- //poi
- compileOptions {
- sourceCompatibility JavaVersion.VERSION_1_8
- targetCompatibility JavaVersion.VERSION_1_8
- }
- }
- dependencies {
- implementation fileTree(include: ['*.jar'], dir: 'libs')
- implementation 'com.android.support:appcompat-v7:28.0.0'
- implementation 'com.android.support.constraint:constraint-layout:1.1.3'
- testImplementation 'junit:junit:4.12'
- androidTestImplementation 'com.android.support.test:runner:1.0.2'
- androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
- //poi
- implementation project(':poilib')
- }
3, 在 poilib 这个 module 中添加 PoiUtils.java 文件
4, 将模板文件复制到项目的 assets 目录下
三, 使用方法
1, 根据 doc 模板生成 doc 文件的关键代码
MainActivity.java
- package com.why.project.poidemo;
- import Android.content.Context;
- import Android.os.Bundle;
- import Android.support.v7.App.AppCompatActivity;
- import Android.view.View;
- import com.why.project.poilib.PoiUtils;
- import java.io.File;
- import java.io.IOException;
- import java.io.InputStream;
- import java.util.HashMap;
- import java.util.Map;
- public class MainActivity extends AppCompatActivity {
- private Context mContext;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- mContext = this;
- // 利用 doc 模板生成 doc 文件
- findViewById(R.id.btn_poi_doc).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- try {
- InputStream templetDocStream = getAssets().open("请假单模板 2.doc");
- String targetDocPath = mContext.getExternalFilesDir("poi").getPath() + File.separator + "请假单 2.doc";// 这个目录, 不需要申请存储权限
- Map<String, String> dataMap = new HashMap<String, String>();
- dataMap.put("$writeDate$", "2018 年 10 月 14 日");
- dataMap.put("$name$", "HaiyuKing");
- dataMap.put("$dept$", "移动开发组");
- dataMap.put("$leaveType$", "倒休 √年假 事假 病假 婚假 产假 其他");
- dataMap.put("$leaveReason$", "倒休一天.");
- dataMap.put("$leaveStartDate$", "2018 年 10 月 14 日上午");
- dataMap.put("$leaveEndDate$", "2018 年 10 月 14 日下午");
- dataMap.put("$leaveDay$", "1");
- dataMap.put("$leaveLeader$", "同意");
- dataMap.put("$leaveDeptLeaderImg$", "同意!");
- PoiUtils.writeToDoc(templetDocStream,targetDocPath,dataMap);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- });
- }
- }
PoiUtils.java
- package com.why.project.poidemo.poi;
- import org.apache.poi.hwpf.HWPFDocument;
- import org.apache.poi.hwpf.usermodel.Range;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.util.Map;
- /**
- * Created by HaiyuKing
- * Used poi 工具类封装
- * 在使用 POI 写 Word doc 文件的时候我们必须要先有一个 doc 文件才行, 因为我们在写 doc 文件的时候是通过 HWPFDocument 来写的,
- * 而 HWPFDocument 是要依附于一个 doc 文件的. 所以通常的做法是我们先在硬盘上准备好一个内容空白的 doc 文件, 然后建立一个基于该空白文件的 HWPFDocument.
- * 之后我们就可以往 HWPFDocument 里面新增内容了, 然后再把它写入到另外一个 doc 文件中, 这样就相当于我们使用 POI 生成了 Word doc 文件.
- */
- public class PoiUtils {
- /**
- * 生成一个 doc 文件
- * @param templetDocPath 模板文件的完整路径
- * @param targetDocPath 生成的目标文件的完整路径
- * @param dataMap 替换的数据 */
- public static void writeToDoc(String templetDocPath, String targetDocPath, Map<String,String> dataMap){
- try
- {
- // 得到模板 doc 文件的 HWPFDocument 对象
- InputStream in = new FileInputStream(templetDocPath);
- writeToDoc(in,targetDocPath,dataMap);
- }
- catch(IOException e)
- {
- e.printStackTrace();
- }
- }
- /**
- * 生成一个 doc 文件, 主要用于直接读取 asset 目录下的模板文件, 不用先复制到 sd 卡中
- * @param templetDocInStream 模板文件的 InputStream
- * @param targetDocPath 生成的目标文件的完整路径
- * @param dataMap 替换的数据 */
- public static void writeToDoc(InputStream templetDocInStream, String targetDocPath, Map<String,String> dataMap){
- try
- {
- // 得到模板 doc 文件的 HWPFDocument 对象
- HWPFDocument HDoc = new HWPFDocument(templetDocInStream);
- // 获取 Word 文本内容, 整个文本
- Range range = HDoc.getRange();
- // 替换文本内容, 将自定义的 $xxx$ 替换成实际文本
- for(Map.Entry<String, String> entry : dataMap.entrySet())
- {
- range.replaceText(entry.getKey(), entry.getValue());
- }
- // 写到另一个文件中
- FileOutputStream out = new FileOutputStream(targetDocPath, true);
- // 把 doc 输出到输出流中
- HDoc.write(out);
- out.close();
- templetDocInStream.close();
- }
- catch(IOException e)
- {
- e.printStackTrace();
- }
- catch(Exception e)
- {
- e.printStackTrace();
- }
- }
- }
2, 效果
生成的文件路径: 内部存储 --Android--data--com.why.project.poidemo--files--poi-- 请假单 2.doc
混淆配置
无
参考资料
Android 使用 ApachePOI 组件读写 Worddoc 和 docx 文件 https://www.jianshu.com/p/8d23b7f54b8e
Poi 官网 http://poi.apache.org/download.html
Android 中使用 POI 加载与显示 Word 文档
poi 替换模板标签为图片 http://zyn010101.iteye.com/blog/1927081
POI 用 addPicture 插入图片到 Word 里面无法显示 http://www.it165.net/pro/html/201108/451.html
使用 POI 读写 Word doc 文件 http://elim.iteye.com/blog/2031335
Android 中使用 POI 加载与显示 Word 文档
项目 demo 下载地址
https://github.com/haiyuKing/PoiDemo
来源: https://www.cnblogs.com/whycxb/p/9789760.html