1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > poi 操作word文档 poi 向word插入图片 poi 向word入表格 XWPFParagraph 分段

poi 操作word文档 poi 向word插入图片 poi 向word入表格 XWPFParagraph 分段

时间:2018-10-01 17:56:13

相关推荐

poi 操作word文档 poi 向word插入图片 poi 向word入表格 XWPFParagraph 分段

前言

因为工作任务填充word的模板,之前用的最多的是excel。 第一次操作word,面向百度开发,遇到了很多问题,也找了很多bolg。 百度有很多标题与内容不符的blog, 找的有点心累,现在做一个总结。版本:5.0.0在线Api: /apidocs/5.0/

问题总结

XWPFRun 分段问题在指定位置填充表格在表格里面插入表格插入图片单元格合并

未解决的问题:在word里面插入附件

解决问题

XWPFRun 分段问题

例如我要替换word里面的${name}${year}

在poi分段的时候可能会分成这样的段落

${name}${year}

解决方法:

网上的解决方案是 在text里面写标记然后在复制粘贴到word

这种方法太麻烦用一个临时变量存储标记

XWPFDocument document = new XWPFDocument(in);List<XWPFParagraph> pars = document.getParagraphs();StringBuilder builder;for (XWPFParagraph pg : pars) {if (pg.getText().contains("$")) {builder = new StringBuilder();// 获取分词List<XWPFRun> runs = pg.getRuns();boolean start = false;String text;for (XWPFRun run : runs) {text = run.text();if (text.startsWith("$")) {start = true;}if (start) {builder.append(text);// 清除标记run.setText("", 0);}if (text.endsWith("}")) {start = false;// 获取到完整标记 // TODO 业务逻辑System.out.println(builder.toString());}}}}

在指定位置插入一个表格

我在word里面打了一个${table}标记,要在这个地方插入一个表格

··· 找到该段落// 首先获取段落游标XmlCursor cursor = pg.getCTP().newCursor();// 跳到下一行cursor.toNextSibling();// 然后根据游标插入一个表格XWPFTable table = document.insertNewTbl(cursor);// 创建行XWPFTableRow row = table.createRow();// 创建单元格XWPFTableCell cell = row.createCell();

新插入的表格只有一行一列,也就是只有一个单元格。并且创建第一行填充多少格,后续行就是多少格,不用再创建单元格了

在表格里面插入表格

XmlCursor cursor = pg.getCTP().newCursor();cursor.toNextSibling();XWPFTable table = document.insertNewTbl(cursor);// document 插入的表格只有一行一格XWPFTableCell cell = table.getRow(0).getCell(0);// 添加段落XWPFParagraph cellPg = cell.addParagraph();// 创建一个文本区域XWPFRun cellRun = cellPg.createRun();cellRun.setText("天青色等烟雨");// 获取游标XmlCursor c = cell.addParagraph().getCTP().newCursor();// 游标下移c.toNextSibling();// 插入表格XWPFTable cellTable = cell.insertNewTbl(c);// 这个表格第一行不能使用,删除掉cellTable.removeRow(0);// 填充内容cellTable.createRow().createCell().setText("而我在等你");

结果:

这里只是做一个演示,表格里面插入的表格没有边框,需要手动设置边框属性。

private static void setBorders(XWPFTable table) {table.getRows().forEach(row -> {row.getTableCells().forEach(cell -> {// 自动宽度cell.setWidthType(TableWidthType.AUTO);CTTcBorders borders = null;if (cell.getCTTc().addNewTcPr().getTcBorders() == null) {borders = cell.getCTTc().addNewTcPr().addNewTcBorders();}// 上下左右setBorder(borders.addNewTop());setBorder(borders.addNewBottom());setBorder(borders.addNewLeft());setBorder(borders.addNewRight());});});}private static void setBorder(CTBorder border) {// 设置单实线border.setVal(STBorder.SINGLE);// 宽度border.setSz(BigInteger.valueOf(2));border.setColor("000000");}

效果:

注意 :如果在多行里面插入多格, 需要填充空值进去,不然导出表格后会有表格属于错误的异常

插入图片

XWPFDocument 有两个插入图片的方法

一个是插入单张图片

一个是插入多张图片

这个是直接添加到word末尾.

要插入到指定位置就使用XWPFRun#addPicture 方法

这个方法有5个参数

从左到右:图片输入流,图片类型,图片名,宽度,高度

try(FileInputStream pic = new FileInputStream("..\图片1.png")){run.addPicture(pic, Document.PICTURE_TYPE_PNG,"图片", Units.toEMU(100),Units.toEMU(100));}

效果:

表格合并

表格合并有两种方式

一个是跨行,如果是表格已经建好的,会把该表格后面单元格"挤"出去.

// XWPFTableCellcell.getCTTc().addNewTcPr().addNewGridSpan().setVal(BigInteger.valueOf(2));

设置表格属性

这两个方法

/questions/24907541/row-span-with-xwpftable

// word跨列合并单元格public void mergeCellsHorizontal(XWPFTable table, int row, int fromCell, int toCell) {for (int cellIndex = fromCell; cellIndex <= toCell; cellIndex++) {XWPFTableCell cell = table.getRow(row).getCell(cellIndex); if ( cellIndex == fromCell ) {// The first merged cell is set with RESTART merge value cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART); } else {// Cells which join (merge) the first one, are set with CONTINUE cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE); } } } // word跨行并单元格public void mergeCellsVertically(XWPFTable table, int col, int fromRow, int toRow) {for (int rowIndex = fromRow; rowIndex <= toRow; rowIndex++) {XWPFTableCell cell = table.getRow(rowIndex).getCell(col); if ( rowIndex == fromRow ) {// The first merged cell is set with RESTART merge value cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART); } else {// Cells which join (merge) the first one, are set with CONTINUE cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE); } } }

完整代码

package org.example;import mons.lang3.StringUtils;import org.apache.poi.util.Units;import org.apache.poi.xwpf.usermodel.*;import org.openxmlformats.schemas.wordprocessingml.x.main.CTBorder;import org.openxmlformats.schemas.wordprocessingml.x.main.CTTcBorders;import org.openxmlformats.schemas.wordprocessingml.x.main.CTTcPr;import org.openxmlformats.schemas.wordprocessingml.x.main.STBorder;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.lang.reflect.Field;import java.math.BigInteger;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;public class WordUtils {private WordUtils() {}/*** @param input word模板输入流* @param outPut 输出流* @param object 数据对象* @throws IllegalAccessException*/public static void export(InputStream input, OutputStream outPut, Object object) throws IllegalAccessException {Map<String, Object> parameters = new HashMap<>();getParameters(object, object.getClass(), parameters);export(input, outPut, parameters);}/*** @param inputword模板输入流* @param outPut输出流* @param parameters 填充数据Map*/public static void export(InputStream input, OutputStream outPut, Map<String, Object> parameters) {try (XWPFDocument document = new XWPFDocument(input)) {// 填充text或者图片或者其他fillWord(document.getParagraphs(), parameters);// 填充表格fillTable(document, parameters);document.write(outPut);} catch (IOException e) {e.printStackTrace();}}/*** 把对象解析成Map,如果是持有其他对象也会解析到map.* 1,如果去持有的对象有相同名称的filed,会被后面的覆盖.* 2,如果是持有其他对象的集合,现在只处理了数组,List,Map类型的没有进行处理* @param object 数据对象* @param clazz 数据对象的class* @param parameters 解析的结果* @throws IllegalAccessException*/private static void getParameters(Object object, Class<?> clazz, Map<String, Object> parameters) throws IllegalAccessException {Field[] fields = clazz.getDeclaredFields();Object value;for (Field field : fields) {field.setAccessible(true);value = getValue(field, object);if (field.getType().isArray()) {parsingCollection(field, object, parameters);} else if (isCustomObject(field.getType())) {parameters.put("${" + field.getName() + "}", value);} else {getParameters(value, field.getType(), parameters);}}}private static boolean isCustomObject(Class<?> clazz) {return clazz.isPrimitive() || clazz.getName().startsWith("java");}private static Object getValue(Field field, Object object) throws IllegalAccessException {return object == null || object == "" ? "" : field.get(object);}private static void parsingCollection(Field field, Object object, Map<String, Object> parameters) throws IllegalAccessException {Object value = getValue(field, object);List<Object> result = new ArrayList<>();if (value != null && value != "") {for (Object ob : (Object[]) value) {if (isCustomObject(ob.getClass())) {result.add(ob);} else {Map<String, Object> map = new HashMap<>();Field[] fs = ob.getClass().getDeclaredFields();for (Field f : fs) {f.setAccessible(true);if (f.getType().isArray()) {parsingCollection(f, ob, map);} else {map.put("${" + f.getName() + "}", getValue(f, ob));}}result.add(map);}}}parameters.put("${" + field.getName() + "}", result);}private static void fillWord(List<XWPFParagraph> paragraphs, Map<String, Object> parameters) {List<XWPFRun> runs;StringBuilder builder;Object value;for (XWPFParagraph paragraph : paragraphs) {runs = paragraph.getRuns();boolean start = false;builder = new StringBuilder();for (XWPFRun run : runs) {String text = run.text();if (text.startsWith("$")) {start = true;}if (start) {// 把标记去掉run.setText("", 0);builder.append(text);}if (text.endsWith("}")) {start = false;String key = builder.toString();builder = new StringBuilder();value = parameters.get(key);if (value != null) {// FIXME 自定义图片标记if (key.equals("图片标记")) {fillPicture(run, value.toString());} else if (value instanceof List) {// FIXME 数据通过逗号连接,或者分段run.setText(StringUtils.join(value, ","));} else if (key.equals("特殊处理")) {// TODO 根据业务需求处理} else {run.setText(parameters.get(key).toString());}}}}}}/*** 填充图片.** @param run 段落标记* @param path 文件路径*/private static void fillPicture(XWPFRun run, String path) {// FIXME 图片输入流从网络读取try (InputStream inputStream = new FileInputStream(path)) {run.addPicture(inputStream, Document.PICTURE_TYPE_PNG, "pictureName", Units.toEMU(100), Units.toEMU(10));} catch (Exception e) {e.printStackTrace();}}/*** 填充表格** @param document* @param parameters*/@SuppressWarnings("all")private static void fillTable(XWPFDocument document, Map<String, Object> parameters) {List<XWPFTable> tables = document.getTables();Object values;for (XWPFTable table : tables) {if (isFillTable(table)) {// 标记行只有一格values = parameters.get(table.getRow(1).getTableCells().get(1).getText());List<String> keys = getTableKeys(table);if (values != null && values != "") {List<Object> obs = (List<Object>) values;int cellSize = table.getRow(0).getTableCells().size();XWPFTableRow row;List<XWPFTableCell> cells;String str;for (Object ob : obs) {row = table.createRow();cells = row.getTableCells();// 如果是list,表示只有一列,直接进行填充if (ob instanceof List) {List<String> strs = (List<String>) ob;for (int i = 0; i < cellSize; i++) {str = i < strs.size() ? strs.get(i) : "";cells.get(i).setText(str);}}// 如果是map,表示有多列,根据表进行填充if (ob instanceof Map) {Map<String, Object> maps = (Map<String, Object>) ob;for (int i = 0; i < cellSize; i++) {str = i < keys.size() ?maps.get(keys.get(i)) == null ? "" : maps.get(keys.get(i)).toString() : "";cells.get(i).setText(str);}}if (ob instanceof String) {for (int i = 0; i < cellSize; i++) {cells.get(i).setText(ob == null ? "" : ((String) ob).toLowerCase());}}}}setTableCellBorders(table);} else {//替换表格中的标记数据table.getRows().forEach(row -> {row.getTableCells().forEach(cell -> fillWord(cell.getParagraphs(), parameters));});}}}/*** 判断是否需要增加表格.* 如果表格有多行,且第一行是需要填充的标记行,则需要增加填充表格** @param table table* @return*/private static boolean isFillTable(XWPFTable table) {if (table.getRows().size() < 2) {return false;}List<XWPFTableCell> cells = table.getRows().get(1).getTableCells();return cells.size() == 1 && cells.get(0).getText().startsWith("$");}private static List<String> getTableKeys(XWPFTable table) {List<String> keys = new ArrayList<>();List<XWPFTableRow> rows = table.getRows();XWPFTableRow row = rows.size() > 2 ? rows.get(2) : rows.get(1);List<XWPFTableCell> cells = row.getTableCells();for (XWPFTableCell cell : cells) {keys.add(cell.getText());}if (table.getRows().size() > 2) {table.removeRow(2);}table.removeRow(1);return keys;}/*** 设置单元格格式.* @param table 表格*/private static void setTableCellBorders(XWPFTable table){table.getRows().forEach(row->{row.getTableCells().forEach(WordUtils::setBorders);});}private static void setBorders(XWPFTableCell cell){cell.setWidthType(TableWidthType.AUTO);CTTcPr tcPr = cell.getCTTc().getTcPr();if(tcPr == null){tcPr= cell.getCTTc().addNewTcPr();}CTTcBorders borders = tcPr.getTcBorders();if(borders == null){borders = tcPr.addNewTcBorders();}setBorder(borders.addNewTop());setBorder(borders.addNewBottom());setBorder(borders.addNewLeft());setBorder(borders.addNewRight());}private static void setBorder(CTBorder boder){boder.setVal(STBorder.SINGLE);boder.setSz(BigInteger.valueOf(2));boder.setColor("000000");}}

poi 操作word文档 poi 向word插入图片 poi 向word入表格 XWPFParagraph 分段 XWPFDocument单元格合并 XWPFDocument 操作word

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。