POI 读取word模板,动态添加图表,添加表格,段落(全)

第一个坑:读取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 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.图表不能设置的东西很多。比如:我想生成这样的图表:

POI 读取word模板,动态添加图表,添加表格,段落(全)_第1张图片

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

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

List 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 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 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 textMap) {
        //获取段落集合
        List paragraphs = document.getParagraphs();

        for (XWPFParagraph paragraph : paragraphs) {
            //判断此段落时候需要进行替换
            String text = paragraph.getText();
            if (checkText(text)) {
                List 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 textMap) throws Exception{
        //获取段落集合
        List paragraphs = document.getParagraphs();

        for (XWPFParagraph paragraph : paragraphs) {
            //判断此段落时候需要进行替换
            String text = paragraph.getText();
            if (checkText(text)) {
                List 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 data) {
        List tableList = document.getTables();

        //循环所有需要进行替换的文本,进行替换
        for (int i = 0; i < tableList.size(); i++) {
            XWPFTable table = tableList.get(i);
            if (checkText(table.getText())) {
                List rows = table.getRows();
                System.out.println("简单表格替换:" + rows);
                //遍历表格,并替换模板
                eachTable(document, rows, data);
            }
        }
    }
    public static void changeTablePic(XWPFDocument document, Map pic) throws Exception{
        List tableList = document.getTables();

        //循环所有需要进行替换的文本,进行替换
        for (int i = 0; i < tableList.size(); i++) {
            XWPFTable table = tableList.get(i);
            if (checkText(table.getText())) {
                List rows = table.getRows();
                System.out.println("简单表格替换:" + rows);
                //遍历表格,并替换模板
                eachTablePic(document, rows, pic);
            }
        }
    }
    public static void eachTablePic(XWPFDocument document, List rows, Map pic) throws Exception{
        for (XWPFTableRow row : rows) {
            List cells = row.getTableCells();
            for (XWPFTableCell cell : cells) {
                //判断单元格是否需要替换
                if (checkText(cell.getText())) {
                    //System.out.println("cell:" + cell.getText());
                    List paragraphs = cell.getParagraphs();
                    for (XWPFParagraph paragraph : paragraphs) {
                        List 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 textMap) {
        Set> textSets = textMap.entrySet();
        Object valu = "";
        for (Map.Entry textSet : textSets) {
            //匹配模板与替换值 格式${key}
            String key = textSet.getKey();
            if (value.indexOf(key) != -1) {
                valu = textSet.getValue();
            }
        }
        return valu;
    }

    public static void eachTable(XWPFDocument document, List rows, Map textMap) {
        for (XWPFTableRow row : rows) {
            List cells = row.getTableCells();
            for (XWPFTableCell cell : cells) {
                //判断单元格是否需要替换
                if (checkText(cell.getText())) {
                    //System.out.println("cell:" + cell.getText());
                    List paragraphs = cell.getParagraphs();
                    for (XWPFParagraph paragraph : paragraphs) {
                        List 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 tableList, List 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 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 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 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);
            }
        }
    }

 

 

你可能感兴趣的:(Java,POI)