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

2 篇文章 0 订阅

第一个坑:读取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);
            }
        }
    }

 

 

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
### 回答1: 要使用Java动态获取数据库信息生成Word文档(包含表格和柱状图),并且实现下载功能,可以按照以下步骤进行: 1. 连接数据库:使用Java的JDBC连接数据库,可以使用相关的驱动程序来实现。通过建立数据库连接,可以执行SQL查询语句来获取需要的数据。 2. 生成Word文档:使用Java的Apache POI库来创建和编辑Word文档。通过POI库提供的API,可以创建一个新的Word文档,并添加所需的内容,包括表格图表。 3. 添加表格:使用POI库提供的API,可以创建表格对象并设置表格的行数和列数。然后,通过遍历数据库查询结果,将数据逐行填充到表格中。 4. 添加柱状图:使用POI库提供的API,可以创建柱状图对象,并设置图表的标题、数据源以及数据系列。通过遍历数据库查询结果,将需要的数据添加图表的数据系列中。 5. 下载生成的Word文档:可以使用Java的Servlet或Spring MVC等Web框架,在用户请求下载时生成Word文档,并将生成的文档通过HTTP响应返回给用户。可以设置适当的HTTP响应头,以使浏览器将响应内容作为文件下载。 总结: 通过JDBC连接数据库获取数据,使用Apache POI库生成Word文档,并根据数据库信息生成表格和柱状图。最后通过Web框架下载生成的文档。这种方法可以实现动态生成和下载数据库信息的Word文档,方便用户查看和使用。 ### 回答2: 在Java中,可以使用Apache POI库来生成Word文档,并使用JFreeChart库来生成柱状图。下面是一个大致的步骤来实现动态获取数据库信息生成Word文档(包含表格和柱状图)并下载: 1. 首先,需要在Java项目中引入Apache POI以及JFreeChart的相关依赖。 2. 获取数据库中的数据,可以使用JDBC连接数据库,并执行SQL语句,将查询结果保存在一个数据集中。 3. 使用Apache POI的XWPFDocument类创建一个新的Word文档。 4. 在Word文档中创建一个表格,根据查询结果的行数和列数创建对应大小的表格。可以使用Apache POI的XWPFTable类来实现表格的创建,以及设置表格的样式和内容。 5. 将查询结果填充到表格中,使用Apache POI的XWPFTableCell类来设置表格中每个单元格的内容和样式。 6. 使用JFreeChart来生成柱状图,并将其插入到Word文档中。可以使用JFreeChart的相关类来创建柱状图,设置图表的样式和标题,并将图表导出为一个图片文件。 7. 使用Apache POI的XWPFParagraph类创建一个段落,并将生成的柱状图的图片插入到段落中。 8. 将段落添加Word文档中。 9. 将生成的Word文档保存到服务器的指定目录下,可以使用Apache POI的XWPFDocument类的write方法将文档写入到硬盘上的一个文件中。 10. 将生成的Word文档提供给用户下载,可以使用Java的文件下载功能,将生成的Word文档以文件流的形式返回给用户。 以上是动态获取数据库信息生成Word文档(包含表格和柱状图)并下载的大致步骤,具体的实现需要根据项目的需求进行适当的调整和完善。 ### 回答3: 要实现动态获取数据库信息生成Word并下载,可以按照以下步骤进行操作: 1. 导入所需的Java库,如Apache POI(用于操作Word文档)和JFreeChart(用于生成柱状图)。 2. 连接数据库并查询需要的数据。使用Java的数据库连接库(如JDBC)连接到数据库,并编写SQL查询语句。 3. 使用Apache POI创建Word文档,并插入表格。使用POI的API逐行读取数据库查询结果,并将数据插入到Word表格中。 4. 使用JFreeChart生成柱状图。根据从数据库中查询到的数据,使用JFreeChart库生成相应的柱状图。 5. 将表格和柱状图插入到Word文档中。使用POI的API将表格和柱状图插入到创建的Word文档中。 6. 设置下载功能。将生成的Word文档保存到服务器上的指定路径。 7. 提供下载链接。将生成的Word文档路径返回给前端,前端通过点击链接即可下载。 8. 设置下载文件的内容类型和文件名。在响应给前端的HTTP头中设置Content-Type为"application/msword",并设置Content-Disposition的attachment属性,指定下载的文件名。 通过以上步骤,可以实现动态获取数据库信息并生成Word文档(包含表格和柱状图),并提供下载功能。用户可以通过点击链接下载生成的Word文件。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值