需求:Android端根据数据,生成word保存到本地.
查了一些资料好像android 没什么正式的word操作库,基本都是用Java API,Apache POI实现的,但是这个版本比较多android这边兼容不太好,坑比较多…
这边本来是需要word操作雷达图,折线图,柱状图这个些的,需要POI4.x版本,各种姿势依赖,好像都问题,编译或者运行各种不行(可能本人太菜…),没办法只能用3.x版本,图表再说吧…

1.gradle 依赖POI

app目录build.gradle,添加完整依赖:


dependencies {...implementation group: 'org.apache.poi', name: 'poi-ooxml', version: '3.17'implementation group: 'org.apache.xmlbeans', name: 'xmlbeans', version: '3.1.0'implementation 'javax.xml.stream:stax-api:1.0'implementation 'com.fasterxml:aalto-xml:1.2.2'...}
2.新增段落
     /*** 添加段落内容** @param document   word文档对象 XWPFDocument document = new XWPFDocument()* @param fontSize   字体大小* @param fontFamily 字体类型* @param text       标题*/public static void addParagraph(XWPFDocument document, int fontSize, String fontFamily, String text) {//创建空白word文档//XWPFDocument document = new XWPFDocument()XWPFParagraph paragraph = document.createParagraph();//内容左对齐paragraph.setAlignment(ParagraphAlignment.valueOf(STJc.INT_LEFT));XWPFRun run = paragraph.createRun();run.setFontSize(13);run.setFontFamily("黑体");run.addTab();run.setText(text);run.addBreak();}
3.新增表格
  • document.createTable(1, 2);
    创建1行 2列表格
    table.getRow(0).getCell(0).setText()
    table.getRow(0).getCell(1).setText()
  • document.createTable();
    默认创建1行1列
    table.getRow(0).getCell(0).setText()
    table.getRow(0).addNewTableCell().setText()
/*** 添加表格* XWPFDocument document = new XWPFDocument()** @param document word文档对象.*/public static void addTable(XWPFDocument document) {//创建表格 1行  list.size 列//XWPFTable table = document.createTable(1, 2);XWPFTable table = document.createTable();CTTbl tTbl = table.getCTTbl();CTTblPr tTblPr = tTbl.getTblPr() == null ? tTbl.addNewTblPr() : tTbl.getTblPr();CTTblWidth tblWidth = tTblPr.isSetTblW() ? tTblPr.getTblW() : tTblPr.addNewTblW();//设置表格宽度tblWidth.setType(STTblWidth.DXA);tblWidth.setW(new BigInteger("8000"));table.getRow(0).setHeight(1000);//第一列setCellStr(table.getRow(0).getCell(0), "主题一", 3000);//setCellStr(table.getRow(0).getCell(1), "孤勇者-陈奕迅", 5000);//第二列setCellStr(table.getRow(0).addNewTableCell(), "孤勇者-陈奕迅", 5000);XWPFTableRow row_1 = table.createRow();row_1.setHeight(1000);setCellStr(row_1.getCell(0), "主题二", 3000);setCellStr(row_1.getCell(1), "再回首-岩贵|再回首恍然如梦", 5000);XWPFTableRow row_2 = table.createRow();row_2.setHeight(1000);setCellStr(row_2.getCell(0), "主题三", 3000);setCellStr(row_2.getCell(1), "光辉岁月-黄家驹", 5000);}

设置单元格属性
注意水平居中:这个有点坑,差了好多,都是ctTc.getPList().get(0).addNewPPr().addNewJc().setVal(STJc.CENTER);,因为版本问题需要改成ctTc.getPArray()[0].addNewPPr().addNewJc().setVal(STJc.CENTER);,编译不报错,一运行就找不到方法,关键代码你点进去还有这个方法…

private static void setCellStr(XWPFTableCell cell, String str, int w) {CTTc ctTc = cell.getCTTc();CTTcPr ctTcPr = ctTc.addNewTcPr();ctTcPr.addNewTcW().setW(BigInteger.valueOf(w));//上下居中cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);//水平居中//ctTc.getPList().get(0).addNewPPr().addNewJc().setVal(STJc.CENTER);ctTc.getPArray()[0].addNewPPr().addNewJc().setVal(STJc.CENTER);cell.setText(str);}
4.根据模版生成新的word

模版我是放在assets目录,然后判断字段是是否包含$.然后替换成我们需要的内容.

4.1替换段落
/*** 替换段落文本** @param document docx解析对象* @param textMap  需要替换的信息集合*/public static void changeText(XWPFDocument document, Map<String, String> textMap) {//获取段落集合List<XWPFParagraph> paragraphs = document.getParagraphs();for (XWPFParagraph paragraph : paragraphs) {//判断此段落时候需要进行替换String text = paragraph.getText();Log.i(TAG, "changeText:行 " + text);if (text.contains("$")) {List<XWPFRun> runs = paragraph.getRuns();for (XWPFRun run : runs) {//替换模板原来位置Log.i(TAG, "changeText:行内 " + run.getText(run.getTextPosition()));run.setText(changeValue(run.toString(), textMap), 0);}}}}
4.2替换表格
  /*** 替换表格对象方法** @param document docx解析对象* @param textMap  需要替换的信息集合*/public static void changeTable(XWPFDocument document, Map<String, String> textMap) {//获取表格对象集合List<XWPFTable> tables = document.getTables();for (int i = 0; i < tables.size(); i++) {Log.i(TAG, "changeTable: 1" + tables.get(i).getText());//只处理行数大于等于2的表格,且不循环表头XWPFTable table = tables.get(i);if (table.getRows().size() > 1) {//判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入if (table.getText().contains("$")) {List<XWPFTableRow> rows = table.getRows();//遍历表格,并替换模板eachTable(rows, textMap);}}}}
5.完整工具代码
public class PoiWordUtils {private static final String TAG = "";/*** 添加段落标题** @param document   word文档对象 XWPFDocument document = new XWPFDocument()* @param fontSize   字体大小* @param fontFamily 字体类型* @param isBreak    是否换行* @param title      标题*/public static void addParagraphTitle(XWPFDocument document, int fontSize, String fontFamily, boolean isBreak, int gravity, String title) {XWPFParagraph paragraph = document.createParagraph();//设置段落居中 / STJc.INT_LEFT - STJc.INT_RIGHTparagraph.setAlignment(ParagraphAlignment.valueOf(gravity));//行间距//paragraph.setSpacingBefore(1);XWPFRun run = paragraph.createRun();run.setFontSize(fontSize);run.setFontFamily("宋体");run.setBold(true);run.setText(title);//换行if (isBreak)run.addBreak();run.addTab();}/*** 添加段落内容** @param document   word文档对象 XWPFDocument document = new XWPFDocument()* @param fontSize   字体大小* @param fontFamily 字体类型* @param text       标题*/public static void addParagraph(XWPFDocument document, int fontSize, String fontFamily, String text) {XWPFParagraph paragraph = document.createParagraph();//内容左对齐paragraph.setAlignment(ParagraphAlignment.valueOf(STJc.INT_LEFT));XWPFRun run = paragraph.createRun();run.setFontSize(13);run.setFontFamily("黑体");run.addTab();run.setText(text);run.addBreak();}/*** 添加表格* XWPFDocument document = new XWPFDocument()** @param document word文档对象.*/public static void addTable(XWPFDocument document) {//创建表格 1行  list.size 列//XWPFTable table = document.createTable(1, 2);XWPFTable table = document.createTable();CTTbl tTbl = table.getCTTbl();CTTblPr tTblPr = tTbl.getTblPr() == null ? tTbl.addNewTblPr() : tTbl.getTblPr();CTTblWidth tblWidth = tTblPr.isSetTblW() ? tTblPr.getTblW() : tTblPr.addNewTblW();//设置表格宽度tblWidth.setType(STTblWidth.DXA);tblWidth.setW(new BigInteger("8000"));table.getRow(0).setHeight(1000);//第一列setCellStr(table.getRow(0).getCell(0), "主题一", 3000);//第二列//setCellStr(table.getRow(0).getCell(1), "孤勇者-陈奕迅", 5000);setCellStr(table.getRow(0).addNewTableCell(), "孤勇者-陈奕迅", 5000);XWPFTableRow row_1 = table.createRow();row_1.setHeight(1000);setCellStr(row_1.getCell(0), "主题二", 3000);setCellStr(row_1.getCell(1), "再回首-岩贵|再回首恍然如梦", 5000);XWPFTableRow row_2 = table.createRow();row_2.setHeight(1000);setCellStr(row_2.getCell(0), "主题三", 3000);setCellStr(row_2.getCell(1), "光辉岁月-黄家驹", 5000);}private static void setCellStr(XWPFTableCell cell, String str, int w) {CTTc ctTc = cell.getCTTc();CTTcPr ctTcPr = ctTc.addNewTcPr();ctTcPr.addNewTcW().setW(BigInteger.valueOf(w));//上下居中cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);//水平居中//ctTc.getPList().get(0).addNewPPr().addNewJc().setVal(STJc.CENTER);ctTc.getPArray()[0].addNewPPr().addNewJc().setVal(STJc.CENTER);cell.setText(str);}/**-----------------------------------------模版相关---------------------------------------------**//*** 根据模板生成新word文档* 判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入** @param inputUrl  模板存放地址* @param outputUrl 新文档存放地址* @param textMap   需要替换的信息集合* @return 成功返回true, 失败返回false*/public static boolean changWord(String inputUrl, String outputUrl,Map<String, String> textMap) {//模板转换默认成功boolean changeFlag = true;try {//获取docx解析对象XWPFDocument document = new XWPFDocument(POIXMLDocument.openPackage(inputUrl));//解析替换文本段落对象changeText(document, textMap);//解析替换表格对象changeTable(document, textMap);//生成新的wordFile file = new File(outputUrl);FileOutputStream stream = new FileOutputStream(file);document.write(stream);stream.close();} catch (IOException e) {e.printStackTrace();changeFlag = false;}return changeFlag;}public static boolean changWord(InputStream is, String outputUrl,Map<String, String> textMap) {//模板转换默认成功boolean changeFlag = true;try {//获取docx解析对象XWPFDocument document = new XWPFDocument(is);//解析替换文本段落对象changeText(document, textMap);//解析替换表格对象changeTable(document, textMap);//生成新的wordFile file = new File(outputUrl);FileOutputStream stream = new FileOutputStream(file);document.write(stream);stream.close();} catch (IOException e) {e.printStackTrace();changeFlag = false;}return changeFlag;}/*** 替换段落文本** @param document docx解析对象* @param textMap  需要替换的信息集合*/public static void changeText(XWPFDocument document, Map<String, String> textMap) {//获取段落集合List<XWPFParagraph> paragraphs = document.getParagraphs();for (XWPFParagraph paragraph : paragraphs) {//判断此段落时候需要进行替换String text = paragraph.getText();Log.i(TAG, "changeText:行 " + text);if (text.contains("$")) {List<XWPFRun> runs = paragraph.getRuns();for (XWPFRun run : runs) {//替换模板原来位置Log.i(TAG, "changeText:行内 " + run.getText(run.getTextPosition()));run.setText(changeValue(run.toString(), textMap), 0);}}}}/*** 替换表格对象方法** @param document docx解析对象* @param textMap  需要替换的信息集合*/public static void changeTable(XWPFDocument document, Map<String, String> textMap) {//获取表格对象集合List<XWPFTable> tables = document.getTables();for (int i = 0; i < tables.size(); i++) {Log.i(TAG, "changeTable: 1" + tables.get(i).getText());//只处理行数大于等于2的表格,且不循环表头XWPFTable table = tables.get(i);if (table.getRows().size() > 1) {//判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入if (table.getText().contains("$")) {List<XWPFTableRow> rows = table.getRows();//遍历表格,并替换模板eachTable(rows, textMap);}}}}/*** 遍历表格** @param rows    表格行对象* @param textMap 需要替换的信息集合*/public static void eachTable(List<XWPFTableRow> rows, Map<String, String> textMap) {for (XWPFTableRow row : rows) {List<XWPFTableCell> cells = row.getTableCells();for (XWPFTableCell cell : cells) {Log.i(TAG, "eachTable: 2 " + cell.getText());//判断单元格是否需要替换if (cell.getText().contains("$")) {List<XWPFParagraph> paragraphs = cell.getParagraphs();for (XWPFParagraph paragraph : paragraphs) {Log.i(TAG, "eachTable: 3" + paragraph.getText());List<XWPFRun> runs = paragraph.getRuns();for (XWPFRun run : runs) {Log.i(TAG, "eachTable: 4 " + run.getText(run.getTextPosition()));run.setText(changeValue(run.toString(), textMap), 0);}}}}}}/*** 匹配传入信息集合与模板** @param value   模板需要替换的区域* @param textMap 传入信息集合* @return 模板需要替换区域信息集合对应值*/public static String changeValue(String value, Map<String, String> textMap) {Set<Map.Entry<String, String>> textSets = textMap.entrySet();for (Map.Entry<String, String> textSet : textSets) {//匹配模板与替换值 格式${key}String key = "${" + textSet.getKey() + "}";if (value.contains(key)) {value = textSet.getValue();}}//模板未匹配到区域替换为空if (value.contains("$")) {value = "";}return value;}
}
6.测试

创建空白word,写入标题 段落,表格

String path = FileUtils.getAppRootPth(this) + File.separator + "word"+ File.separator + "测试3.100.docx";try (XWPFDocument document = new XWPFDocument(); FileOutputStream fos = new FileOutputStream(path)) {//标题PoiWordUtils.addParagraphTitle(document, 20, null,true,STJc.INT_CENTER, "POI段落标题");//小标题PoiWordUtils.addParagraphTitle(document, 15, null,false,STJc.INT_LEFT, "一丶内容示例");//段落PoiWordUtils.addParagraph(document, -1, null, "POI是Apache软件" +"基金会用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程序对Microsoft" +" Office格式档案读和写的功能。POI为“Poor Obfuscation Implementation”的首字母缩写," +"意为“简洁版的模糊实现”。\n" +"所以POI的主要功能是可以用Java操作Microsoft Office的相关文件,但是一般我们都是用来操作" +"Excel相关文件。");PoiWordUtils.addParagraph(document, -1, null, "POI是Apache软件" +"基金会用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程序对Microsoft" +" Office格式档案读和写的功能。POI为“Poor Obfuscation Implementation”的首字母缩写," +"意为“简洁版的模糊实现”。\n" +"所以POI的主要功能是可以用Java操作Microsoft Office的相关文件,但是一般我们都是用来操作" +"Excel相关文件。");PoiWordUtils.addParagraphTitle(document, 15, null,false,STJc.INT_LEFT, "二丶内容示例");PoiWordUtils.addParagraph(document, -1, null, "POI是Apache软件" +"基金会用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程序对Microsoft" +" Office格式档案读和写的功能。POI为“Poor Obfuscation Implementation”的首字母缩写," +"意为“简洁版的模糊实现”。\n" +"所以POI的主要功能是可以用Java操作Microsoft Office的相关文件,但是一般我们都是用来操作" +"Excel相关文件。");PoiWordUtils.addTable(document);//写入本地document.write(fos);

运行结果.

根据模版生成新的word

Map<String, String> testMap = new HashMap<>();testMap.put("Title", "POI模版替换");testMap.put("FirstHeading", "规则说明");testMap.put("FirstHeadingContent", "1.玩家同一场景,以个人为单位进行战斗.\n2.可以对其他玩家进行攻击\n3.一场游戏时间为10分钟");testMap.put("SecondHeading", "奖励说明");testMap.put("A", "主题A");testMap.put("a", "主题A详情");testMap.put("B", "主题B");testMap.put("b", "主题B详情");testMap.put("C", "主题C");testMap.put("c", "主题C详情");try {InputStream is = getAssets().open("谈话结果主题摘要模板.docx");//InputStream is = getAssets().open("阶段性风险评估报告模版.docx");String path = FileUtils.getAppRootPth(this) + File.separator + "word" + File.separator + "测试24.docx";//boolean b = WordUtils.changWord(is, path, testMap, testList);boolean b = WordUtils.changWord(is, path, testMap);Log.i(TAG, "testWord: " + b);} catch (IOException e) {e.printStackTrace();}

模版:

替换之后:

Android word文档 poi 表格 段落使用记录相关推荐

  1. poi解析word文档(解析表格,emf,wmf,svg转jpg图片)

    POI解析word文档 poi解析word的表格:   提前先准备需要的jar包:   <!-- poi --><dependency><groupId>org.a ...

  2. Python3-word文档操作(十):利用docx库创建word文档,添加段落,添加表格,添加图片,设置文字粗体,斜体

    1 简介: 作为一个综合例子,本篇主要显示docx库的一些基本操作: 利用docx库创建word文档,添加段落,添加表格,添加图片,设置文字粗体,斜体. 2 举例: 对word文档进行属性的设置,以及 ...

  3. WORD文档里面表格下面太多空白怎么接起来

    WORD文档里面表格下面太多空白怎么接起来 方法一 方法二 参考地址 方法一 选中该表格后,右键点表格属性,勾选行那里的允许跨页断行. 方法二 可能是由于表格宽度不够引起的,内容被自动隐藏了.可以通过 ...

  4. word文档删除表格后的空白页

    word文档删除表格后的空白页 如果word文档是以表格结尾的话,有时候我们会发现最后的空白页无法删除.这时候可以在空白页上设置固定值为1磅.点击[段落]-[行距]选择固定值,改为1磅就可以删除空白页 ...

  5. python docx 设置表格字体和格式_python-docx修改已存在的Word文档的表格的字体格式方法...

    搞了好几天的表格字体格式,一直想找一种能直接一次性修改表格所有字体格式的方法(函数),但是无论用什么方法都无法修改表格字体的格式,原因应该是已存在的文档本身就具有某种格式限制,制约着里面表格里面字体格 ...

  6. spring使用freemarker生成word文档包含表格、图片(循环插入)

    spring使用freemarker生成word文档包含表格.图片(循环插入) 效果图 因为测试数据是重复的,所以显示都是重复的数据,替换导入map中的数据可以显示不重复的数据. 操作步骤 1,创建一 ...

  7. java 操作word中表格_Java 使用Spire.Cloud.Word给Word文档添加表格

    在编辑Word文档时,很多时候需要用到表格,以便能够清晰整洁地表达和归类数据.本文就将介绍如何使用Spire.Cloud.Word给Word文档添加表格.Spire.Cloud.Word提供了Tabl ...

  8. python docx 表格复制粘贴_python-docx修改已存在的Word文档的表格的字体格式方法

    搞了好几天的表格字体格式,一直想找一种能直接一次性修改表格所有字体格式的方法(函数),但是无论用什么方法都无法修改表格字体的格式,原因应该是已存在的文档本身就具有某种格式限制,制约着里面表格里面字体格 ...

  9. Word控件Spire.Doc 【段落处理】教程(十八):在 C# 中从 Word 文档中删除段落

    Spire.Doc 支持从 word 文档中删除特定段落以及所有段落.本文详细介绍了如何使用 Spire.Doc 和 C# 从 Word 文档中删除段落. 我们使用的示例 word 文档: Spire ...

最新文章

  1. 多级反馈队列调度算法描述
  2. pthread_create()之前的属性设置
  3. 分布式系统中的一致性协议之两阶段提交协议(2PC)
  4. 2台xenserver组成的资源池开启HA存在的问题
  5. mysql Decimal(M,D)解释
  6. java arrays方法_Java工具类Arrays中不得不知的常用方法
  7. 【Android】Activity生命周期
  8. 机器学习之 weka学习(三)
  9. Git提交失败之 Updates were rejected because the tip of your current branch is behind
  10. flex自定义preloader预加载进度条
  11. android gms测试,谷歌GMS认证需要测试哪些项目?
  12. 19、STM8单片机RS485串口通讯实验
  13. Python计算时间差天数
  14. LAMP系列文章之:泛泛而谈LAMP(一)
  15. python基础----文件处理
  16. 服务器登录 微信提醒,微信提示非常用设备登陆解决办法
  17. 实践丨分布式事务解决方案汇总:2PC、消息中间件、TCC、状态机+重试+幂等
  18. vue父组给子子组件传html,vue组件之间互相传值:父传子,子传父
  19. 基于springboot实现疫情上报系统
  20. 2018年Android源码下载记录

热门文章

  1. 携职教育:拿到一级造价工程师证书后,如何利用好它“赚大钱”
  2. 简通易证:一级造价师报考条件
  3. 前端常用几种设计模式
  4. Mysql导入数据库
  5. 踏遍青山情未老 —— 九山顶重游记(一)
  6. highcharts去掉右下角highchart.com和右上角的图标(三个小横杆)
  7. 用Springboot+netty实现基于Web的聊天室
  8. 循环神经网络原理及实现(二):循环神经网络复现
  9. Nor flash 驱动和移植
  10. 易维帮助台如何“重新定义客户服务”?