POI 读取word模板,动态添加图表,添加表格,段落(全)_poi动态插入word 表格_小水牛OvO的博客-CSDN博客

第一个坑:读取docx的方式。

XWPFDocument document = null;document = new XWPFDocument(POIXMLDocument.openPackage(mdlepath));

 这种方法读取docx文档,修改后另存为另一个文档

FileOutputStream outputStream = new FileOutputStream(tempPath);document.write(outputStream);outputStream.close();

 然后这个文档就可以使用勒。是不是很简单,是不是很方便。但是,这个代码我是在网上找的,这个代码有个巨坑无比的地方。

我在操作一个word的时候,调用了一个copyTable方法。这个方法的作用就是复制某一个表格到指定位置。中间使用了一个document.setTable(pos,table)方法。这个方法有个巨坑的点,其中table是我需要复制的表格。再执行完这个代码之后,doc.getTable()这个函数的返回值正确,没有问题,逐行遍历表格也没有问题。但是在操作这个表格的时候发现了问题。使用逐行操作表格会无效。究其原因我猜测是因为引用问题。POI在操作table的时候并不能像List一样。new 一个对象就新分配一个空间。POI在操作很多东西的时候并不能新分配一个对象,而没有引用。所以就导致我的setTable方法传入参数的table,永远是同一个table。我是怎么知道的呢,是因为我每次把这个table的某一个单元格setText("i="+i)会发现复制的几个表格里,最后一个表格输出了很多个i=.......在逐个遍历表格赋值的时候,会造成每次修改的表格都是同一个。并不能修改到复制出来的表格。解决办法就是必须把这个文件另存为,再打开。这是背景。

那么我就需要调用两次上面的代码。而且第二次调用的docx文件是第一次的输出文件。

这个东西我是要挂载在服务器上的,我肯定是要删除掉的。那么坑就来了。

我第一次生成的文件叫temp1,第二次生成的文件叫temp2.

我执行这一段代码:

out1.getFD().valid();out2.getFD().valid();

输出结果为false和false。然后我删除文件。输出删除结果,均为true。然后我打开文件夹,发现temp

,删除了temp2没删除。我心态崩掉了。然后我file(temp1).exists();发现结果为false。就是说我删除成功而且检查删除后文件已经不存在了。然后我debug,发现删除那句话并没有执行,却返回true。没删除掉exists却返回false。然后我怀疑是文件占用或者是别的原因,我就怀疑是这个封装方法出了问题。

解决办法:

try (FileInputStream argIS = new FileInputStream(mdlepath);XWPFDocument document = new XWPFDocument(argIS)){//这里面的代码就是操作整个document的具体操作了。//不需要关闭 FileInputStream 会自动关闭}

 我换了一种方法读取docx文件,而且写在try()中间.就不会出现占用或者流未关闭的问题了。

解决办法是看的官方例程http://svn.apache.org/repos/asf/poi/trunk/src/examples/src/org/apache/poi/xwpf/usermodel/examples/

第二个坑:setTable()需要重新打开后生效

public static void copyTable(XWPFDocument doc, Integer mdlIndex, Integer startPos, Integer copysiz, List<String> titlelist,XWPFParagraph sourse) throws Exception {         if (mdlIndex == null || mdlIndex >= doc.getTables().size() || mdlIndex < 0) {            return;        }        XWPFTable table = doc.getTables().get(mdlIndex);          // Copying a existing table        CTTbl ctTbl = CTTbl.Factory.newInstance(); // Create a new CTTbl for the new table        ctTbl.set(table.getCTTbl()); // Copy the template table's CTTbl         // Create a new table using the CTTbl upon.0        XWPFTable table2 = new XWPFTable(ctTbl, doc);//这个table2是个引用类型,放到循环里也不会改变他引用的对象是他的模板table,这是个坑;        for (int i = 0; i < copysiz; i++) {            //创建表之前先创建头            XWPFParagraph paragraph = doc.createParagraph();            paragraph.getCTP().setPPr(sourse.getCTP().getPPr());//            paragraph.setPageBreak(true);//            paragraph.setAlignment(ParagraphAlignment.CENTER);            XWPFRun xwpfRun = paragraph.createRun();            xwpfRun.setFontSize(18);//设置字体大小            xwpfRun.setBold(true);            xwpfRun.setText("表-" + titlelist.get(i+1));            paragraph.setPageBreak(true);//分页符            //创建表并且修改表            doc.createTable(); // Create a empty table in the document            // 这里有一个坑,必须重新打开该文件这个这个替换掉的table才能修改。不然改不了。或者在创建table2的时候就把数据加上            doc.setTable(doc.getTables().size() - 1, table2);        }    }

 第三个坑:操作POIword图表

首先有例程http://svn.apache.org/repos/asf/poi/trunk/src/examples/src/org/apache/poi/xwpf/usermodel/examples/BarChartExample.java

这个例程有两个坑爹的地方:

1.图表不能设置的东西很多。比如:我想生成这样的图表:

 我不能设置没有表头,官方有个类似的方法没有用。不生效。我想设置是否标出数据大小,比如2,7,11,5啥的,没有。我想设置样式,也没有。

解决办法,,我创建模板压,创建完之后修改数据就完事了。把表头设置为空字符串,看起来就和没有差不多。

List<XWPFChart> chartList = document.getCharts();XWPFChart chart = chartList.get(0);String[] categories = (String[]) barChartMap.get("categories");Integer[] value = (Integer[]) barChartMap.get("value");setBarData(chart, categories, value);  private static void setBarData(XWPFChart chart, String[] categories, Integer[] values1) {        final List<XDDFChartData> data = chart.getChartSeries();        final XDDFBarChartData bar = (XDDFBarChartData) data.get(0);         final int numOfPoints = categories.length;        final String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0));        final String valuesDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 1, 1));        final String valuesDataRange2 = chart.formatRange(new CellRangeAddress(1, numOfPoints, 2, 2));        final XDDFDataSource<?> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, 0);        final XDDFNumericalDataSource<? extends Number> valuesData = XDDFDataSourcesFactory.fromArray(values1, valuesDataRange, 1);         XDDFChartData.Series series1 = bar.getSeries().get(0);        series1.replaceData(categoriesData, valuesData);        series1.setTitle("123", chart.setSheetTitle("123", 0));         bar.setBarDirection(BarDirection.COL);        chart.plot(bar);        solidFillSeries(bar, 0, PresetColor.GRAY);        chart.setTitleText(""); // https://stackoverflow.com/questions/30532612        chart.setAutoTitleDeleted(true);        chart.setTitleOverlay(false);        //改变颜色     } private static void solidFillSeries(XDDFChartData data, int index, PresetColor color) {        //改变柱状图的第index的颜色        XDDFSolidFillProperties fill = new XDDFSolidFillProperties(XDDFColor.from(color));        XDDFChartData.Series series = data.getSeries().get(index);        XDDFShapeProperties properties = series.getShapeProperties();        if (properties == null) {            properties = new XDDFShapeProperties();        }        properties.setFillProperties(fill);        series.setShapeProperties(properties);    } 

第四个坑:word插入特殊字符

类似√×这样的特殊字符。有的甚至要输出一些奇奇怪怪的东西。

思路有两个:

1.直接在java里打出来,然后添加到word里面

2.在word里生成特殊字符。

方法1,我试过是可以的。

方法2 这里附上解决办法和思路:poi插入word 2007 Wingdings字符。可行,可能以后会出现版本问题。那篇帖子挺老的了。

总结:一些基础的代码我就不贴上来了,我把我用到的一些工具方法贴上来供大家参考。其中一些方法是从官方文档里弄过来的,可能不全面,但是一定有用。

还有一点心得:如果你的POI版本比较新,比如说我使用的是POI 4.1.0版本的,百度上面差到的资料是很少的,而且百度辣鸡,用谷歌能查到一些,最好的地方是去官方文档里去寻找答案。或者到国外的开发者论坛:https://stackoverflow.com/经常是可以搜到的。

下面是一些用到的代码:

/**     * 替换段落文本     *     * @param document docx解析对象     * @param textMap  需要替换的信息集合     */    public static void changeText(XWPFDocument document, Map<String, Object> textMap) {        //获取段落集合        List<XWPFParagraph> paragraphs = document.getParagraphs();         for (XWPFParagraph paragraph : paragraphs) {            //判断此段落时候需要进行替换            String text = paragraph.getText();            if (checkText(text)) {                List<XWPFRun> runs = paragraph.getRuns();                for (XWPFRun run : runs) {                    //替换模板原来位置                    Object ob = changeValue(run.toString(), textMap);                    //System.out.println("段落:" + run.toString());                    if (ob instanceof String) {                        if(textMap.containsKey(run.toString())){                            run.setText((String) ob, 0);                        }                    }                }            }        }    }    public static void changePic(XWPFDocument document, Map<String, Object> textMap) throws Exception{        //获取段落集合        List<XWPFParagraph> paragraphs = document.getParagraphs();         for (XWPFParagraph paragraph : paragraphs) {            //判断此段落时候需要进行替换            String text = paragraph.getText();            if (checkText(text)) {                List<XWPFRun> runs = paragraph.getRuns();                for (XWPFRun run : runs) {                    //替换模板原来位置                    Object ob = changeValue(run.toString(), textMap);                    //System.out.println("段落:" + run.toString());                    if (ob instanceof String) {                        if(textMap.containsKey(run.toString())){                            run.setText("", 0);                            try(FileInputStream is=new FileInputStream((String)ob)){                                run.addPicture(is,XWPFDocument.PICTURE_TYPE_PNG,(String)ob, Units.toEMU(50),Units.toEMU(50));                            }                        }                    }                }            }        }    }     public static boolean checkText(String text) {        boolean check = false;        if (text.indexOf("$") != -1) {            check = true;        }        return check;    }     public static void changeTableText(XWPFDocument document, Map<String, Object> data) {        List<XWPFTable> tableList = document.getTables();         //循环所有需要进行替换的文本,进行替换        for (int i = 0; i < tableList.size(); i++) {            XWPFTable table = tableList.get(i);            if (checkText(table.getText())) {                List<XWPFTableRow> rows = table.getRows();                System.out.println("简单表格替换:" + rows);                //遍历表格,并替换模板                eachTable(document, rows, data);            }        }    }    public static void changeTablePic(XWPFDocument document, Map<String, Object> pic) throws Exception{        List<XWPFTable> tableList = document.getTables();         //循环所有需要进行替换的文本,进行替换        for (int i = 0; i < tableList.size(); i++) {            XWPFTable table = tableList.get(i);            if (checkText(table.getText())) {                List<XWPFTableRow> rows = table.getRows();                System.out.println("简单表格替换:" + rows);                //遍历表格,并替换模板                eachTablePic(document, rows, pic);            }        }    }    public static void eachTablePic(XWPFDocument document, List<XWPFTableRow> rows, Map<String, Object> pic) throws Exception{        for (XWPFTableRow row : rows) {            List<XWPFTableCell> cells = row.getTableCells();            for (XWPFTableCell cell : cells) {                //判断单元格是否需要替换                if (checkText(cell.getText())) {                    //System.out.println("cell:" + cell.getText());                    List<XWPFParagraph> paragraphs = cell.getParagraphs();                    for (XWPFParagraph paragraph : paragraphs) {                        List<XWPFRun> runs = paragraph.getRuns();                        for (XWPFRun run : runs) {                            Object ob = changeValue(run.toString(), pic);                            if (ob instanceof String) {                                System.out.println("run:"+"'"+run.toString()+"'");                                if(pic.containsKey(run.toString())){                                    System.out.println("run:"+run.toString()+"替换为"+(String)ob);                                    run.setText("", 0);                                    try(FileInputStream is=new FileInputStream((String)ob)){                                        run.addPicture(is,XWPFDocument.PICTURE_TYPE_PNG,(String)ob,Units.toEMU(50),Units.toEMU(100));                                    }                                }                                else{                                    System.out.println("'"+run.toString()+"'不匹配");                                }                            }                        }                    }                }            }        }    }     public static Object changeValue(String value, Map<String, Object> textMap) {        Set<Map.Entry<String, Object>> textSets = textMap.entrySet();        Object valu = "";        for (Map.Entry<String, Object> textSet : textSets) {            //匹配模板与替换值 格式${key}            String key = textSet.getKey();            if (value.indexOf(key) != -1) {                valu = textSet.getValue();            }        }        return valu;    }     public static void eachTable(XWPFDocument document, List<XWPFTableRow> rows, Map<String, Object> textMap) {        for (XWPFTableRow row : rows) {            List<XWPFTableCell> cells = row.getTableCells();            for (XWPFTableCell cell : cells) {                //判断单元格是否需要替换                if (checkText(cell.getText())) {                    //System.out.println("cell:" + cell.getText());                    List<XWPFParagraph> paragraphs = cell.getParagraphs();                    for (XWPFParagraph paragraph : paragraphs) {                        List<XWPFRun> runs = paragraph.getRuns();                        for (XWPFRun run : runs) {                             Object ob = changeValue(run.toString(), textMap);                            if (ob instanceof String) {                                 System.out.println("run:"+"'"+run.toString()+"'");                                if(textMap.containsKey(run.toString())){                                    System.out.println("run:"+run.toString()+"替换为"+(String)ob);                                    run.setText((String) ob, 0);                                }                                else{                                    System.out.println("'"+run.toString()+"'不匹配");                                }                             }                        }                    }                }            }        }    }     public static void insertTable(XWPFTable table, List<String> tableList, List<String[]> daList, Integer type) {        if (2 == type) {            //创建行和创建需要的列            for (int i = 0; i < daList.size() - 1; i++) {                //添加一个新行//                XWPFTableRow row = table.insertNewTableRow(1 + i);                XWPFTableRow row = table.getRow(1);                copy(table, row, i + 1);//                for (int k = 0; k < daList.get(i).length; k++) {//                    row.createCell();//                }            }            System.out.println("插入表格数据");            //创建行,根据需要插入的数据添加新行,不处理表头            for (int i = 0; i < daList.size(); i++) {                List<XWPFTableCell> cells = table.getRow(i + 1).getTableCells();                for (int j = 0; j < cells.size(); j++) {                    XWPFTableCell cell02 = cells.get(j);                    cell02.setText(daList.get(i)[j]);                }            }        } else if (4 == type) {            //插入表头下面第一行的数据            for (int i = 0; i < tableList.size(); i++) {                XWPFTableRow row = table.createRow();                List<XWPFTableCell> cells = row.getTableCells();                cells.get(0).setText(tableList.get(i));            }        }    }     /**     * 复制两行     *     * @param table     * @param sourceRow     * @param rowIndex     */    public static void copy(XWPFTable table, XWPFTableRow sourceRow, int rowIndex) {        //在表格指定位置新增一行        XWPFTableRow targetRow = table.insertNewTableRow(rowIndex);        //复制行属性        targetRow.getCtRow().setTrPr(sourceRow.getCtRow().getTrPr());        List<XWPFTableCell> cellList = sourceRow.getTableCells();        if (null == cellList) {            return;        }        //复制列及其属性和内容        XWPFTableCell targetCell = null;        for (XWPFTableCell sourceCell : cellList) {            targetCell = targetRow.addNewTableCell();            //列属性            targetCell.getCTTc().setTcPr(sourceCell.getCTTc().getTcPr());            //段落属性            if (sourceCell.getParagraphs() != null && sourceCell.getParagraphs().size() > 0) {                targetCell.getParagraphs().get(0).getCTP().setPPr(sourceCell.getParagraphs().get(0).getCTP().getPPr());                if (sourceCell.getParagraphs().get(0).getRuns() != null && sourceCell.getParagraphs().get(0).getRuns().size() > 0) {                    XWPFRun cellR = targetCell.getParagraphs().get(0).createRun();                    cellR.setText(sourceCell.getText());                    cellR.setBold(sourceCell.getParagraphs().get(0).getRuns().get(0).isBold());                } else {                    targetCell.setText(sourceCell.getText());                }            } else {                targetCell.setText(sourceCell.getText());            }        }    }     /**     * 合并行     * @param table     * @param col     * @param fromRow     * @param toRow     */    public static void mergeCellVertically(XWPFTable table, int col, int fromRow, int toRow) {        for (int rowIndex = fromRow; rowIndex <= toRow; rowIndex++) {            CTVMerge vmerge = CTVMerge.Factory.newInstance();            if (rowIndex == fromRow) {                vmerge.setVal(STMerge.RESTART);            } else {                vmerge.setVal(STMerge.CONTINUE);            }            XWPFTableCell cell = table.getRow(rowIndex).getCell(col);            CTTcPr tcPr = cell.getCTTc().getTcPr();            if (tcPr != null) {                tcPr.setVMerge(vmerge);            } else {                tcPr = CTTcPr.Factory.newInstance();                tcPr.setVMerge(vmerge);                cell.getCTTc().setTcPr(tcPr);            }        }    }    /**     * 合并列     *     * @param table     * @param row     * @param fromCell     * @param toCell     */    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);                //cellCount为表格总列数                int cellCount = table.getRow(row).getTableCells().size();                Integer width = (toCell - fromCell + 1) / cellCount * table.getCTTbl().getTblPr().getTblW().getW().intValue();                cell.getCTTc().getTcPr().addNewTcW().setW(BigInteger.valueOf(width));            } else {                // Cells which join (merge) the first one, are set with CONTINUE                cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);            }        }    }

原网址: 访问
创建于: 2023-05-06 18:23:24
目录: default
标签: 无

请先后发表评论
  • 最新评论
  • 总共0条评论