Android word文档 poi 表格 段落使用记录
需求: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 表格 段落使用记录相关推荐
- poi解析word文档(解析表格,emf,wmf,svg转jpg图片)
POI解析word文档 poi解析word的表格: 提前先准备需要的jar包: <!-- poi --><dependency><groupId>org.a ...
- Python3-word文档操作(十):利用docx库创建word文档,添加段落,添加表格,添加图片,设置文字粗体,斜体
1 简介: 作为一个综合例子,本篇主要显示docx库的一些基本操作: 利用docx库创建word文档,添加段落,添加表格,添加图片,设置文字粗体,斜体. 2 举例: 对word文档进行属性的设置,以及 ...
- WORD文档里面表格下面太多空白怎么接起来
WORD文档里面表格下面太多空白怎么接起来 方法一 方法二 参考地址 方法一 选中该表格后,右键点表格属性,勾选行那里的允许跨页断行. 方法二 可能是由于表格宽度不够引起的,内容被自动隐藏了.可以通过 ...
- word文档删除表格后的空白页
word文档删除表格后的空白页 如果word文档是以表格结尾的话,有时候我们会发现最后的空白页无法删除.这时候可以在空白页上设置固定值为1磅.点击[段落]-[行距]选择固定值,改为1磅就可以删除空白页 ...
- python docx 设置表格字体和格式_python-docx修改已存在的Word文档的表格的字体格式方法...
搞了好几天的表格字体格式,一直想找一种能直接一次性修改表格所有字体格式的方法(函数),但是无论用什么方法都无法修改表格字体的格式,原因应该是已存在的文档本身就具有某种格式限制,制约着里面表格里面字体格 ...
- spring使用freemarker生成word文档包含表格、图片(循环插入)
spring使用freemarker生成word文档包含表格.图片(循环插入) 效果图 因为测试数据是重复的,所以显示都是重复的数据,替换导入map中的数据可以显示不重复的数据. 操作步骤 1,创建一 ...
- java 操作word中表格_Java 使用Spire.Cloud.Word给Word文档添加表格
在编辑Word文档时,很多时候需要用到表格,以便能够清晰整洁地表达和归类数据.本文就将介绍如何使用Spire.Cloud.Word给Word文档添加表格.Spire.Cloud.Word提供了Tabl ...
- python docx 表格复制粘贴_python-docx修改已存在的Word文档的表格的字体格式方法
搞了好几天的表格字体格式,一直想找一种能直接一次性修改表格所有字体格式的方法(函数),但是无论用什么方法都无法修改表格字体的格式,原因应该是已存在的文档本身就具有某种格式限制,制约着里面表格里面字体格 ...
- Word控件Spire.Doc 【段落处理】教程(十八):在 C# 中从 Word 文档中删除段落
Spire.Doc 支持从 word 文档中删除特定段落以及所有段落.本文详细介绍了如何使用 Spire.Doc 和 C# 从 Word 文档中删除段落. 我们使用的示例 word 文档: Spire ...
最新文章
- 多级反馈队列调度算法描述
- pthread_create()之前的属性设置
- 分布式系统中的一致性协议之两阶段提交协议(2PC)
- 2台xenserver组成的资源池开启HA存在的问题
- mysql Decimal(M,D)解释
- java arrays方法_Java工具类Arrays中不得不知的常用方法
- 【Android】Activity生命周期
- 机器学习之 weka学习(三)
- Git提交失败之 Updates were rejected because the tip of your current branch is behind
- flex自定义preloader预加载进度条
- android gms测试,谷歌GMS认证需要测试哪些项目?
- 19、STM8单片机RS485串口通讯实验
- Python计算时间差天数
- LAMP系列文章之:泛泛而谈LAMP(一)
- python基础----文件处理
- 服务器登录 微信提醒,微信提示非常用设备登陆解决办法
- 实践丨分布式事务解决方案汇总:2PC、消息中间件、TCC、状态机+重试+幂等
- vue父组给子子组件传html,vue组件之间互相传值:父传子,子传父
- 基于springboot实现疫情上报系统
- 2018年Android源码下载记录