版权声明:本文为HaiyuKing原创文章,转载请注明出处!
前言
这个是《PoiDemo【Android将表单数据生成Word文档的方案之二(基于Poi4.0.0)】》的扩展,上一篇是根据doc模板生成doc文件,这个是根据docx模板生成docx文件。
注意:目前只能java生成,集成到Android项目中,运行报错【暂时未解决】:
Process: com.why.project.poidocxdemo, PID: 13762 java.lang.NoClassDefFoundError: Failed resolution of: Ljavax/xml/stream/XMLEventFactory; at org.apache.poi.openxml4j.opc.internal.marshallers.PackagePropertiesMarshaller.<clinit>(PackagePropertiesMarshaller.java:41) at org.apache.poi.openxml4j.opc.OPCPackage.<init>(OPCPackage.java:140) at org.apache.poi.openxml4j.opc.ZipPackage.<init>(ZipPackage.java:103) at org.apache.poi.openxml4j.opc.OPCPackage.open(OPCPackage.java:298) at org.apache.poi.ooxml.util.PackageHelper.open(PackageHelper.java:37) at org.apache.poi.xwpf.usermodel.XWPFDocument.<init>(XWPFDocument.java:142)
前期准备
参考《PoiDemo【Android将表单数据生成Word文档的方案之二(基于Poi4.0.0)】》
区别在于,模板的占位有所不用【docx模板文件不需要$符号】:
代码分析
参考《PoiDemo【Android将表单数据生成Word文档的方案之二(基于Poi4.0.0)】》
使用步骤
一、项目组织结构图
注意事项:
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文件》
注意:
解析docx文件,需要引用下面的jar文件:
- poi-4.0.0.jar
- poi-ooxml-4.0.0.jar
- poi-ooxml-schemas-4.0.0.jar
- ooxml-lib目录下的curvesapi-1.05.jar、xmlbeans-3.0.1.jar
- lib目录下的commons-collections4-4.2.jar
- 下载的commons-compress-1.18.jar
commons-compress-1.18.jar下载地址:http://commons.apache.org/proper/commons-compress/download_compress.cgi
2、将制作的模板文件复制到D:/temp目录下
3、将PoiUtils.java文件复制到项目中
package com.why.main; import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFParagraph; import org.apache.poi.xwpf.usermodel.XWPFRun; import org.apache.poi.xwpf.usermodel.XWPFTable; import org.apache.poi.xwpf.usermodel.XWPFTableCell; import org.apache.poi.xwpf.usermodel.XWPFTableRow; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; public class PoiUtils { //测试 public static void main(String[] args) { String templetDocPath = "D:/temp/请假单模板1.docx"; String targetDocPath = "D:/temp/请假单1.docx"; Map<String, Object> dataMap = new HashMap<String, Object>(); 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.writeToDocx(templetDocPath,targetDocPath,dataMap); try { PoiUtils.readDocx(targetDocPath); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 通过XWPFDocument对内容进行访问。对于XWPF文档而言,用这种方式进行读操作更佳。 * @throws Exception */ public static void readDocx(String templetDocPath) throws Exception { InputStream is = new FileInputStream(templetDocPath); XWPFDocument doc = new XWPFDocument(is); List<XWPFParagraph> paras = doc.getParagraphs(); for (XWPFParagraph para : paras) { //当前段落的属性 System.out.println("para=="+para.getText()); } //获取文档中所有的表格 List<XWPFTable> tables = doc.getTables(); List<XWPFTableRow> rows; List<XWPFTableCell> cells; for (XWPFTable table : tables) { //获取表格对应的行 rows = table.getRows(); for (XWPFTableRow row : rows) { //获取行对应的单元格 cells = row.getTableCells(); for (XWPFTableCell cell : cells) { System.out.println("cell=="+cell.getText());; } } } if (is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } /** * 生成一个docx文件 * @param templetDocPath 模板文件的完整路径 * @param targetDocPath 生成的目标文件的完整路径 * @param dataMap 替换的数据*/ public static void writeToDocx(String templetDocPath, String targetDocPath, Map<String,Object> dataMap){ try { //得到模板doc文件的HWPFDocument对象 InputStream in = new FileInputStream(templetDocPath); writeToDocx(in,targetDocPath,dataMap); } catch(IOException e) { e.printStackTrace(); } } /** * 生成一个docx文件,主要用于直接读取asset目录下的模板文件,不用先复制到sd卡中 * @param templetDocInStream 模板文件的InputStream * @param targetDocPath 生成的目标文件的完整路径 * @param dataMap 替换的数据*/ public static void writeToDocx(InputStream templetDocInStream, String targetDocPath, Map<String,Object> dataMap){ try { //得到模板doc文件的HWPFDocument对象 XWPFDocument HDocx = new XWPFDocument(templetDocInStream); //替换段落里面的变量 replaceInPara(HDocx, dataMap); //替换表格里面的变量 replaceInTable(HDocx, dataMap); //写到另一个文件中 OutputStream os = new FileOutputStream(targetDocPath); //把doc输出到输出流中 HDocx.write(os); os.close(); templetDocInStream.close(); } catch(IOException e) { e.printStackTrace(); } catch(Exception e) { e.printStackTrace(); } } /** * 替换段落里面的变量 * @param doc 要替换的文档 * @param params 参数 */ private static void replaceInPara(XWPFDocument doc, Map<String, Object> params) { Iterator<XWPFParagraph> iterator = doc.getParagraphsIterator(); XWPFParagraph para; while (iterator.hasNext()) { para = iterator.next(); replaceInPara(para, params); } } /** * 替换段落里面的变量 * @param para 要替换的段落 * @param params 参数 */ private static void replaceInPara(XWPFParagraph para, Map<String, Object> params) { List<XWPFRun> runs; System.out.println("para.getParagraphText()=="+para.getParagraphText()); runs = para.getRuns(); for (int i=0; i<runs.size(); i++) { XWPFRun run = runs.get(i); String runText = run.toString(); System.out.println("runText=="+runText); // 替换文本内容,将自定义的$xxx$替换成实际文本 for(Map.Entry<String, Object> entry : params.entrySet()) { runText = runText.replace(entry.getKey(), entry.getValue()+""); //直接调用XWPFRun的setText()方法设置文本时,在底层会重新创建一个XWPFRun,把文本附加在当前文本后面, //所以我们不能直接设值,需要先删除当前run,然后再自己手动插入一个新的run。 para.removeRun(i); para.insertNewRun(i).setText(runText); } } } /** * 替换表格里面的变量 * @param doc 要替换的文档 * @param params 参数 */ private static void replaceInTable(XWPFDocument doc, Map<String, Object> params) { Iterator<XWPFTable> iterator = doc.getTablesIterator(); XWPFTable table; List<XWPFTableRow> rows; List<XWPFTableCell> cells; List<XWPFParagraph> paras; while (iterator.hasNext()) { table = iterator.next(); rows = table.getRows(); for (XWPFTableRow row : rows) { cells = row.getTableCells(); for (XWPFTableCell cell : cells) { paras = cell.getParagraphs(); for (XWPFParagraph para : paras) { replaceInPara(para, params); } } } } } }
4、运行
5、效果【生成的docx文件有问题,之前的样式全失效了】
混淆配置
暂无
参考资料
Android使用ApachePOI组件读写Worddoc和docx文件
Java:封装POI实现word的docx文件的简单模板功能
项目demo下载地址
链接:https://pan.baidu.com/s/165hpn3kZssxVvHIF9RNtkQ 提取码:3mmj
PoiDocxDemo【Android将表单数据生成Word文档的方案之二(基于Poi4.0.0),目前只能java生成】