精华内容
下载资源
问答
  • 使用FreeMarker给word文档里生成柱状图 1制作ftl文件: 1.先创建个空白的word文档 然后插入柱状图 2.另存为xml文件 打开后是这样 3.百度搜索XML 在线格式化 转化格式为这样 4.把这些内容粘贴到文本里...

    学习目标:

    使用FreeMarker给word文档里生成柱状图


    1制作ftl文件:

       1.先创建个空白的word文档 然后插入柱状图

       

    2.另存为xml文件 打开后是这样

     

    3.百度搜索 XML 在线格式化 转化格式为这样

    4.把这些内容粘贴到文本里格式改为ftl 像这样


    生成word:

    自己到百度搜个生成word文档的方法

    wordutil

    /**
     * 生成word文件
     * @param dataMap word中需要展示的动态数据,用map集合来保存
     * @param templateName word模板名称,例如:test.ftl
     * @param filePath 文件生成的目标路径,例如:D:/wordFile/
     * @param fileName 生成的文件名称,例如:test.doc
     */
    @SuppressWarnings("unchecked")
    public static void createWord(Map dataMap,String templateName,String filePath,String fileName){
        Writer out = null;
        try {
            //创建配置实例
            Configuration configuration = new Configuration();
            //设置编码
            configuration.setDefaultEncoding("UTF-8");
            //ftl模板文件
            configuration.setClassForTemplateLoading(WordUtil.class,"/");
            //获取模板
            Template template = configuration.getTemplate(templateName);
            //输出文件
            File outFile = new File(filePath+File.separator+fileName);
            //如果输出目标文件夹不存在,则创建
            if (!outFile.getParentFile().exists()){
                outFile.getParentFile().mkdirs();
            }
            //将模板和数据模型合并生成文件
            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile),"UTF-8"));
            //生成文件
            template.process(dataMap, out);
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            if(out != null){
                try {
                    //关闭流
                    out.flush();
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    main方法里里生成出来

    // 生成word
    WordUtil.createWord(dataMap, "freeMark/testReportNew7.ftl", filePath, fileName);

     

     

    展示word:

    最后就成这个了

    当然 这些数据是静态的!如果需要动态的需要给ftl文件里加pkg标签

    展开全文
  • // 第二个-柱状图 POIXMLDocumentPart poixmlDocumentPart1 = chartsMap.get("/word/charts/chart2.xml"); new PoiWordTools().replaceBarCharts(poixmlDocumentPart1, titleArr, fldNameArr, listItemsByType); //...

    本文参考地址:https://blog.csdn.net/wangxiaoyingWXY/article/details/95377533
    在参考文章的基础上,增加了扩展。感谢被参考的妹子。另外该博客主要记录很多poi操作word中遇到的问题和解决方式,所以会一直维护下去。

    另外,我是在本地使用的wps,使用office的老哥(老姐)们可能在效果上有出入。

    本文只是简单示例,仅做代码参考,在实际运用中可自行根据业务封装。

    模板在示例代码中有的哈,在resource目录下面

    还有就是博主真的很菜.....(手动滑稽)

    关于示例代码:(码云地址)https://gitee.com/loverer/poi-demo

    另外如果遇到模板标签不完整的情况,请参考:https://blog.csdn.net/weixin_43770790/article/details/86672962

    说明:在poi3.x的版本中,没有对图表的支持,至少目前为止没有找到相应的文章介绍;在poi4.x的版本中加入了对图表的支持,所以需要引入poi4.x的依赖包,并且JDK最低版本要求8;

    2019-12-04:新增:动态刷新内置Excel数据

    2020-04-07:新增:更新插入的文本框内容(感谢博友:输过败过但不曾怕过啊)

    2020-04-10:新增:新增一个定位图表的方式(感谢博友:输过败过但不曾怕过啊)

    2020-04-11:新增:柱状图动态列,优化修改(兼容wps和office)(感谢:谈个长长的恋爱可好)

    2020-04-21:新增:表格进行合并单元格,横竖都行,两种方式(感谢刘老师)

    2020-04-23:解决问题:组合图页面显示的数据,跟第二列对应不上(感谢博友:吹古拉朽)

    2020-06-06:解决问题:图表设置系列标题方式错误导致office无法打开的问题(感谢博友: qq_18900373)

    // 设置标题
    CTSerTx tx = ser.getTx();
    tx.setV("阿里嘎痛");  // wps可以打开,office无法打开
    tx.getStrRef().getStrCache().getPtList().get(0).setV("阿里嘎痛"); // wps和office都能打开

    1.引入maven依赖包

    <dependency>
    	<groupId>org.apache.poi</groupId>
    	<artifactId>poi</artifactId>
    	<version>4.1.0</version>
    </dependency>
    <dependency>
    	<groupId>org.apache.poi</groupId>
    	<artifactId>poi-ooxml</artifactId>
    	<version>4.1.0</version>
    </dependency>

    完整pom.xml内容

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
       <modelVersion>4.0.0</modelVersion>
       <parent>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-parent</artifactId>
          <version>2.1.8.RELEASE</version>
          <relativePath/> <!-- lookup parent from repository -->
       </parent>
       <groupId>com.example</groupId>
       <artifactId>demo</artifactId>
       <version>0.0.1-SNAPSHOT</version>
       <name>demo</name>
       <description>Demo project for Spring Boot</description>
    
       <properties>
          <java.version>1.8</java.version>
       </properties>
    
       <dependencies>
          <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter</artifactId>
          </dependency>
    
          <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-devtools</artifactId>
             <scope>runtime</scope>
             <optional>true</optional>
          </dependency>
          <dependency>
             <groupId>org.projectlombok</groupId>
             <artifactId>lombok</artifactId>
             <optional>true</optional>
          </dependency>
          <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-test</artifactId>
             <scope>test</scope>
          </dependency>
    
          <dependency>
             <groupId>org.apache.poi</groupId>
             <artifactId>poi</artifactId>
             <version>4.1.0</version>
          </dependency>
          <dependency>
             <groupId>org.apache.poi</groupId>
             <artifactId>poi-ooxml</artifactId>
             <version>4.1.0</version>
          </dependency>
          <!--2.poi官网指出需要poi4.x.x版本抛弃了jdk1.7之前的版本,所以适应此版本需要将jdk升级,如果不想升级还有另一种办法就是,使用springBoot单独做一个服务为你的主项目提供一个接口,让主项目去调用生成word流让主项目去接收即可。-->
    
    
    
       </dependencies>
    
       <build>
          <plugins>
             <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
             </plugin>
          </plugins>
       </build>
    
    </project>

    2.准备word模板文件,注意后缀是docx,模板中的图表可以有数据,但是最终会被代码替换,所以不重要

    模板文件: 不知道怎么上传了,需要的私信吧,感谢;

    3.两个类

    类1:PoiDemoWordTable 

    package com.example.demo;
    
    import com.example.demo.util.PoiWordTools;
    
    import org.apache.poi.ooxml.POIXMLDocumentPart;
    import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
    import org.apache.poi.util.Units;
    import org.apache.poi.xwpf.usermodel.*;
    import org.apache.xmlbeans.XmlCursor;
    import org.springframework.util.StringUtils;
    
    import java.io.*;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    public class PoiDemoWordTable {
    
        public static void main(String[] args) throws Exception {
    
            final String returnurl = "D:\\youxi\\jx\\result.docx";  // 结果文件
    
            final String templateurl = "D:\\youxi\\jx\\test.docx";  // 模板文件
    
            InputStream is = new FileInputStream(new File(templateurl));
            XWPFDocument doc = new XWPFDocument(is);
    
            // 替换word模板数据
            replaceAll(doc);
    
            // 保存结果文件
            try {
                File file = new File(returnurl);
                if (file.exists()) {
                    file.delete();
                }
                FileOutputStream fos = new FileOutputStream(returnurl);
                doc.write(fos);
                fos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    
        /**
         * @Description: 替换段落和表格中
         */
        public static void replaceAll(XWPFDocument doc) throws InvalidFormatException, IOException {
            doParagraphs(doc); // 处理段落文字数据,包括文字和表格、图片
            doCharts(doc);  // 处理图表数据,柱状图、折线图、饼图啊之类的
        }
    
    
        /**
         * 处理段落文字
         *
         * @param doc
         * @throws InvalidFormatException
         * @throws FileNotFoundException
         * @throws IOException
         */
        public static void doParagraphs(XWPFDocument doc) throws InvalidFormatException, IOException {
    
            // 文本数据
            Map<String, String> textMap = new HashMap<String, String>();
            textMap.put("var", "我是被替换的文本内容");
    
            // 图片数据
            Map<String, String> imgMap = new HashMap<String, String>();
            imgMap.put("img", "D:/youxi/ddd.png");
    
    
            /**----------------------------处理段落------------------------------------**/
            List<XWPFParagraph> paragraphList = doc.getParagraphs();
            if (paragraphList != null && paragraphList.size() > 0) {
                for (XWPFParagraph paragraph : paragraphList) {
                    List<XWPFRun> runs = paragraph.getRuns();
                    for (XWPFRun run : runs) {
                        String text = run.getText(0);
                        if (text != null) {
    
                            // 替换文本信息
                            String tempText = text;
                            String key = tempText.replaceAll("\\{\\{", "").replaceAll("}}", "");
                            if (!StringUtils.isEmpty(textMap.get(key))) {
                                run.setText(textMap.get(key), 0);
                            }
    
                            // 替换图片内容 参考:https://blog.csdn.net/a909301740/article/details/84984445
                            String tempImgText = text;
                            String imgkey = tempImgText.replaceAll("\\{\\{@", "").replaceAll("}}", "");
                            if (!StringUtils.isEmpty(imgMap.get(imgkey))) {
                                String imgPath = imgMap.get(imgkey);
                                try {
                                    run.setText("", 0);
                                    run.addPicture(new FileInputStream(imgPath), Document.PICTURE_TYPE_PNG, "img.png", Units.toEMU(200), Units.toEMU(200));
    
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
    
                            // 动态表格
                            if (text.contains("${table1}")) {
                                run.setText("", 0);
                                XmlCursor cursor = paragraph.getCTP().newCursor();
                                XWPFTable tableOne = doc.insertNewTbl(cursor);// ---这个是关键
    
                                // 设置表格宽度,第一行宽度就可以了,这个值的单位,目前我也还不清楚,还没来得及研究
                                tableOne.setWidth(8500);
    
                                // 表格第一行,对于每个列,必须使用createCell(),而不是getCell(),因为第一行嘛,肯定是属于创建的,没有create哪里来的get呢
                                XWPFTableRow tableOneRowOne = tableOne.getRow(0);//行
                                new PoiWordTools().setWordCellSelfStyle(tableOneRowOne.getCell(0), "微软雅黑", "9", 0, "left", "top", "#000000", "#B4C6E7", "10%", "序号");
                                new PoiWordTools().setWordCellSelfStyle(tableOneRowOne.createCell(), "微软雅黑", "9", 0, "left", "top", "#000000", "#B4C6E7", "45%", "公司名称(英文)");
                                new PoiWordTools().setWordCellSelfStyle(tableOneRowOne.createCell(), "微软雅黑", "9", 0, "left", "top", "#000000", "#B4C6E7", "45%", "公司名称(中文)");
    
                                // 表格第二行
                                XWPFTableRow tableOneRowTwo = tableOne.createRow();//行
                                new PoiWordTools().setWordCellSelfStyle(tableOneRowTwo.getCell(0), "微软雅黑", "9", 0, "left", "top", "#000000", "#B4C6E7", "10%", "一行一列");
                                new PoiWordTools().setWordCellSelfStyle(tableOneRowTwo.getCell(1), "微软雅黑", "9", 0, "left", "top", "#000000", "#B4C6E7", "45%", "一行一列");
                                new PoiWordTools().setWordCellSelfStyle(tableOneRowTwo.getCell(2), "微软雅黑", "9", 0, "left", "top", "#000000", "#B4C6E7", "45%", "一行一列");
    
    
                                // ....... 可动态添加表格
                            }
                        }
                    }
                }
            }
        }
    
    
        /**
         * 处理图表
         *
         * @param doc
         * @throws FileNotFoundException
         */
        public static void doCharts(XWPFDocument doc) throws FileNotFoundException {
            /**----------------------------处理图表------------------------------------**/
    
            // 数据准备
            List<String> titleArr = new ArrayList<String>();// 标题
            titleArr.add("title");
            titleArr.add("金额");
    
            List<String> fldNameArr = new ArrayList<String>();// 字段名
            fldNameArr.add("item1");
            fldNameArr.add("item2");
    
            // 数据集合
            List<Map<String, String>> listItemsByType = new ArrayList<Map<String, String>>();
    
            // 第一行数据
            Map<String, String> base1 = new HashMap<String, String>();
            base1.put("item1", "材料费用");
            base1.put("item2", "500");
    
            // 第二行数据
            Map<String, String> base2 = new HashMap<String, String>();
            base2.put("item1", "出差费用");
            base2.put("item2", "300");
    
            // 第三行数据
            Map<String, String> base3 = new HashMap<String, String>();
            base3.put("item1", "住宿费用");
            base3.put("item2", "300");
    
            listItemsByType.add(base1);
            listItemsByType.add(base2);
            listItemsByType.add(base3);
    
    
            // 获取word模板中的所有图表元素,用map存放
            // 为什么不用list保存:查看doc.getRelations()的源码可知,源码中使用了hashMap读取文档图表元素,
            // 对relations变量进行打印后发现,图表顺序和文档中的顺序不一致,也就是说relations的图表顺序不是文档中从上到下的顺序
            Map<String, POIXMLDocumentPart> chartsMap = new HashMap<String, POIXMLDocumentPart>();
            //动态刷新图表
            List<POIXMLDocumentPart> relations = doc.getRelations();
            for (POIXMLDocumentPart poixmlDocumentPart : relations) {
                if (poixmlDocumentPart instanceof XWPFChart) {  // 如果是图表元素
                    String str = poixmlDocumentPart.toString();
                    System.out.println("str:" + str);
                    String key = str.replaceAll("Name: ", "")
                            .replaceAll(" - Content Type: application/vnd\\.openxmlformats-officedocument\\.drawingml\\.chart\\+xml", "").trim();
                    System.out.println("key:" + key);
    
                    chartsMap.put(key, poixmlDocumentPart);
                }
            }
    
            System.out.println("\n图表数量:" + chartsMap.size() + "\n");
    
    
            // 第一个图表-条形图
            POIXMLDocumentPart poixmlDocumentPart0 = chartsMap.get("/word/charts/chart1.xml");
            new PoiWordTools().replaceBarCharts(poixmlDocumentPart0, titleArr, fldNameArr, listItemsByType);
    
            // 第二个-柱状图
            POIXMLDocumentPart poixmlDocumentPart1 = chartsMap.get("/word/charts/chart2.xml");
            new PoiWordTools().replaceBarCharts(poixmlDocumentPart1, titleArr, fldNameArr, listItemsByType);
    
            // 第三个图表-多列柱状图
            doCharts3(chartsMap);
    
            // 第四个图表-折线图
            doCharts4(chartsMap);
    
            // 第五个图表-饼图
            POIXMLDocumentPart poixmlDocumentPart4 = chartsMap.get("/word/charts/chart5.xml");
            new PoiWordTools().replacePieCharts(poixmlDocumentPart4, titleArr, fldNameArr, listItemsByType);
    
    
            doCharts6(chartsMap);
        }
    
    
        public static void doCharts3(Map<String, POIXMLDocumentPart> chartsMap) {
            // 数据准备
            List<String> titleArr = new ArrayList<String>();// 标题
            titleArr.add("姓名");
            titleArr.add("欠款");
            titleArr.add("存款");
    
            List<String> fldNameArr = new ArrayList<String>();// 字段名
            fldNameArr.add("item1");
            fldNameArr.add("item2");
            fldNameArr.add("item3");
    
            // 数据集合
            List<Map<String, String>> listItemsByType = new ArrayList<Map<String, String>>();
    
            // 第一行数据
            Map<String, String> base1 = new HashMap<String, String>();
            base1.put("item1", "老张");
            base1.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base1.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            // 第二行数据
            Map<String, String> base2 = new HashMap<String, String>();
            base2.put("item1", "老李");
            base2.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base2.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            // 第三行数据
            Map<String, String> base3 = new HashMap<String, String>();
            base3.put("item1", "老刘");
            base3.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base3.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
    
            listItemsByType.add(base1);
            listItemsByType.add(base2);
            listItemsByType.add(base3);
    
            POIXMLDocumentPart poixmlDocumentPart2 = chartsMap.get("/word/charts/chart3.xml");
            new PoiWordTools().replaceBarCharts(poixmlDocumentPart2, titleArr, fldNameArr, listItemsByType);
        }
    
    
    
        public static void doCharts4(Map<String, POIXMLDocumentPart> chartsMap) {
            // 数据准备
            List<String> titleArr = new ArrayList<String>();// 标题
            titleArr.add("title");
            titleArr.add("占基金资产净值比例22222(%)");
            titleArr.add("额外的(%)");
            titleArr.add("额外的(%)");
    
            List<String> fldNameArr = new ArrayList<String>();// 字段名
            fldNameArr.add("item1");
            fldNameArr.add("item2");
            fldNameArr.add("item3");
            fldNameArr.add("item4");
    
            // 数据集合
            List<Map<String, String>> listItemsByType = new ArrayList<Map<String, String>>();
    
            // 第一行数据
            Map<String, String> base1 = new HashMap<String, String>();
            base1.put("item1", "材料费用");
            base1.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base1.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base1.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            // 第二行数据
            Map<String, String> base2 = new HashMap<String, String>();
            base2.put("item1", "出差费用");
            base2.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base2.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base2.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            // 第三行数据
            Map<String, String> base3 = new HashMap<String, String>();
            base3.put("item1", "住宿费用");
            base3.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base3.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base3.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
    
            listItemsByType.add(base1);
            listItemsByType.add(base2);
            listItemsByType.add(base3);
    
            POIXMLDocumentPart poixmlDocumentPart2 = chartsMap.get("/word/charts/chart4.xml");
            new PoiWordTools().replaceLineCharts(poixmlDocumentPart2, titleArr, fldNameArr, listItemsByType);
        }
    
    
        /**
         * 对应文档中的第6个图表(预处理—分公司情况)
         */
        public static void doCharts6(Map<String, POIXMLDocumentPart> chartsMap) {
            // 数据准备
            List<String> titleArr = new ArrayList<String>();// 标题
            titleArr.add("title");
            titleArr.add("投诉受理量(次)");
            titleArr.add("预处理拦截工单量(次)");
            titleArr.add("拦截率");
    
            List<String> fldNameArr = new ArrayList<String>();// 字段名
            fldNameArr.add("item1");
            fldNameArr.add("item2");
            fldNameArr.add("item3");
            fldNameArr.add("item4");
    
            // 数据集合
            List<Map<String, String>> listItemsByType = new ArrayList<Map<String, String>>();
    
            // 第一行数据
            Map<String, String> base1 = new HashMap<String, String>();
            base1.put("item1", "通辽");
            base1.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base1.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base1.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            // 第二行数据
            Map<String, String> base2 = new HashMap<String, String>();
            base2.put("item1", "呼和浩特");
            base2.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base2.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base2.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            // 第三行数据
            Map<String, String> base3 = new HashMap<String, String>();
            base3.put("item1", "锡林郭勒");
            base3.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base3.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base3.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            // 第四行数据
            Map<String, String> base4 = new HashMap<String, String>();
            base4.put("item1", "阿拉善");
            base4.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base4.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base4.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            // 第五行数据
            Map<String, String> base5 = new HashMap<String, String>();
            base5.put("item1", "巴彦淖尔");
            base5.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base5.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base5.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            // 第六行数据
            Map<String, String> base6 = new HashMap<String, String>();
            base6.put("item1", "兴安");
            base6.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base6.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base6.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            // 第七行数据
            Map<String, String> base7 = new HashMap<String, String>();
            base7.put("item1", "乌兰察布");
            base7.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base7.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base7.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            // 第八行数据
            Map<String, String> base8 = new HashMap<String, String>();
            base8.put("item1", "乌海");
            base8.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base8.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base8.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            // 第九行数据
            Map<String, String> base9 = new HashMap<String, String>();
            base9.put("item1", "赤峰");
            base9.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base9.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base9.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            // 第十行数据
            Map<String, String> base10 = new HashMap<String, String>();
            base10.put("item1", "包头");
            base10.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base10.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base10.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            // 第十一行数据
            Map<String, String> base11 = new HashMap<String, String>();
            base11.put("item1", "呼伦贝尔");
            base11.put("item2", (int)(int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base11.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base11.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            // 第十二行数据
            Map<String, String> base12 = new HashMap<String, String>();
            base12.put("item1", "鄂尔多斯");
            base12.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base12.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base12.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            listItemsByType.add(base1);
            listItemsByType.add(base2);
            listItemsByType.add(base3);
            listItemsByType.add(base4);
            listItemsByType.add(base5);
            listItemsByType.add(base6);
            listItemsByType.add(base7);
            listItemsByType.add(base8);
            listItemsByType.add(base9);
            listItemsByType.add(base10);
            listItemsByType.add(base11);
            listItemsByType.add(base12);
    
            // 下标0的图表-折线图
            POIXMLDocumentPart poixmlDocumentPart5 = chartsMap.get("/word/charts/chart6.xml");
            new PoiWordTools().replaceCombinationCharts(poixmlDocumentPart5, titleArr, fldNameArr, listItemsByType);
        }
    
    }
    
    
    

    类2:PoiWordTools

    package com.example.demo.util;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.math.BigDecimal;
    import java.math.BigInteger;
    import java.util.List;
    import java.util.Map;
    
    import org.apache.poi.ooxml.POIXMLDocumentPart;
    import org.apache.poi.ss.usermodel.*;
    import org.apache.poi.ss.util.CellRangeAddress;
    import org.apache.poi.xssf.usermodel.XSSFWorkbook;
    import org.apache.poi.xwpf.usermodel.XWPFChart;
    import org.apache.poi.xwpf.usermodel.XWPFTableCell;
    import org.openxmlformats.schemas.drawingml.x2006.chart.*;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTColor;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTFonts;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHpsMeasure;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTJc;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTOnOff;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPPr;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTParaRPr;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRPr;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTShd;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTText;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTVerticalJc;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.STJc;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.STOnOff;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.STVerticalJc;
    
    /**
     * poi生成word的工具类
     * 针对于模板中的图表是静态的,也就是模板中的图表长什么样子不会根据数据而改变
     */
    public class PoiWordTools {
    
        private static final BigDecimal bd2 = new BigDecimal("2");
    
    
        /**
         * 调用替换柱状图数据
         */
        public static void replaceBarCharts(POIXMLDocumentPart poixmlDocumentPart,
                                            List<String> titleArr, List<String> fldNameArr, List<Map<String, String>> listItemsByType) {
            XWPFChart chart = (XWPFChart) poixmlDocumentPart;
            chart.getCTChart();
    
            //根据属性第一列名称切换数据类型
            CTChart ctChart = chart.getCTChart();
            CTPlotArea plotArea = ctChart.getPlotArea();
    
            CTBarChart barChart = plotArea.getBarChartArray(0);
            List<CTBarSer> BarSerList = barChart.getSerList();  // 获取柱状图单位
    
            //刷新内置excel数据
            new PoiWordTools().refreshExcel(chart, listItemsByType, fldNameArr, titleArr);
            //刷新页面显示数据
            refreshBarStrGraphContent(barChart, BarSerList, listItemsByType, fldNameArr, 1);
        }
    
    
        /**
         * 调用替换折线图数据
         */
        public static void replaceLineCharts(POIXMLDocumentPart poixmlDocumentPart,
                                             List<String> titleArr, List<String> fldNameArr, List<Map<String, String>> listItemsByType) {
            XWPFChart chart = (XWPFChart) poixmlDocumentPart;
            chart.getCTChart();
    
            //根据属性第一列名称切换数据类型
            CTChart ctChart = chart.getCTChart();
            CTPlotArea plotArea = ctChart.getPlotArea();
    
            CTLineChart lineChart = plotArea.getLineChartArray(0);
            List<CTLineSer> lineSerList = lineChart.getSerList();   // 获取折线图单位
    
            //刷新内置excel数据
            new PoiWordTools().refreshExcel(chart, listItemsByType, fldNameArr, titleArr);
            //刷新页面显示数据
            new PoiWordTools().refreshLineStrGraphContent(lineChart, lineSerList, listItemsByType, fldNameArr, 1);
    
        }
    
    
        /**
         * 调用替换饼图数据
         */
        public static void replacePieCharts(POIXMLDocumentPart poixmlDocumentPart,
                                            List<String> titleArr, List<String> fldNameArr, List<Map<String, String>> listItemsByType) {
            XWPFChart chart = (XWPFChart) poixmlDocumentPart;
            chart.getCTChart();
    
            //根据属性第一列名称切换数据类型
            CTChart ctChart = chart.getCTChart();
            CTPlotArea plotArea = ctChart.getPlotArea();
    
            CTPieChart pieChart = plotArea.getPieChartArray(0);
            List<CTPieSer> pieSerList = pieChart.getSerList();  // 获取饼图单位
    
            //刷新内置excel数据
            new PoiWordTools().refreshExcel(chart, listItemsByType, fldNameArr, titleArr);
            //刷新页面显示数据
            new PoiWordTools().refreshPieStrGraphContent(pieChart, pieSerList, listItemsByType, fldNameArr, 1);
    
        }
    
    
        /**
         * 调用替换柱状图、折线图组合数据
         */
        public static void replaceCombinationCharts(POIXMLDocumentPart poixmlDocumentPart,
                                                    List<String> titleArr, List<String> fldNameArr, List<Map<String, String>> listItemsByType) {
            XWPFChart chart = (XWPFChart) poixmlDocumentPart;
            chart.getCTChart();
    
            //根据属性第一列名称切换数据类型
            CTChart ctChart = chart.getCTChart();
            CTPlotArea plotArea = ctChart.getPlotArea();
    
    
            CTBarChart barChart = plotArea.getBarChartArray(0);
            List<CTBarSer> barSerList = barChart.getSerList();  // 获取柱状图单位
            //刷新内置excel数据
            new PoiWordTools().refreshExcel(chart, listItemsByType, fldNameArr, titleArr);
            //刷新页面显示数据   数据中下标1开始的是柱状图数据,所以这个是1
            refreshBarStrGraphContent(barChart, barSerList, listItemsByType, fldNameArr, 1);
    
    
            CTLineChart lineChart = plotArea.getLineChartArray(0);
            List<CTLineSer> lineSerList = lineChart.getSerList();   // 获取折线图单位
            //刷新内置excel数据   有一个就可以了    有一个就可以了    有一个就可以了
            //new PoiWordTools().refreshExcel(chart, listItemsByType, fldNameArr, titleArr);
            //刷新页面显示数据   数据中下标3开始的是折线图的数据,所以这个是3
            new PoiWordTools().refreshLineStrGraphContent(lineChart, lineSerList, listItemsByType, fldNameArr, 3);
    
        }
    
    
        /**
         * 刷新折线图数据方法
         *
         * @param typeChart
         * @param serList
         * @param dataList
         * @param fldNameArr
         * @param position
         * @return
         */
        public static boolean refreshLineStrGraphContent(Object typeChart,
                                                         List<?> serList, List<Map<String, String>> dataList, List<String> fldNameArr, int position) {
    
            boolean result = true;
            //更新数据区域
            for (int i = 0; i < serList.size(); i++) {
                //CTSerTx tx=null;
                CTAxDataSource cat = null;
                CTNumDataSource val = null;
                CTLineSer ser = ((CTLineChart) typeChart).getSerArray(i);
                //tx= ser.getTx();
                // Category Axis Data
                cat = ser.getCat();
                // 获取图表的值
                val = ser.getVal();
                // strData.set
                CTStrData strData = cat.getStrRef().getStrCache();
                CTNumData numData = val.getNumRef().getNumCache();
                strData.setPtArray((CTStrVal[]) null); // unset old axis text
                numData.setPtArray((CTNumVal[]) null); // unset old values
    
                // set model
                long idx = 0;
                for (int j = 0; j < dataList.size(); j++) {
                    //判断获取的值是否为空
                    String value = "0";
                    if (new BigDecimal(dataList.get(j).get(fldNameArr.get(i + position))) != null) {
                        value = new BigDecimal(dataList.get(j).get(fldNameArr.get(i + position))).toString();
                    }
                    if (!"0".equals(value)) {
                        CTNumVal numVal = numData.addNewPt();//序列值
                        numVal.setIdx(idx);
                        numVal.setV(value);
                    }
                    CTStrVal sVal = strData.addNewPt();//序列名称
                    sVal.setIdx(idx);
                    sVal.setV(dataList.get(j).get(fldNameArr.get(0)));
                    idx++;
                }
                numData.getPtCount().setVal(idx);
                strData.getPtCount().setVal(idx);
    
    
                //赋值横坐标数据区域
                String axisDataRange = new CellRangeAddress(1, dataList.size(), 0, 0)
                        .formatAsString("Sheet1", false);
                cat.getStrRef().setF(axisDataRange);
    
                //数据区域
                String numDataRange = new CellRangeAddress(1, dataList.size(), i + position, i + position)
                        .formatAsString("Sheet1", false);
                val.getNumRef().setF(numDataRange);
    
                // 设置系列生成方向
    
    
            }
            return result;
        }
    
    
        /**
         * 刷新柱状图数据方法
         *
         * @param typeChart
         * @param serList
         * @param dataList
         * @param fldNameArr
         * @param position
         * @return
         */
        public  static boolean refreshBarStrGraphContent(Object typeChart,
                                                        List<?> serList, List<Map<String, String>> dataList, List<String> fldNameArr, int position) {
            boolean result = true;
            //更新数据区域
            for (int i = 0; i < serList.size(); i++) {
    //            CTSerTx tx=null;
                CTAxDataSource cat = null;
                CTNumDataSource val = null;
                CTBarSer ser = ((CTBarChart) typeChart).getSerArray(i);
    //            tx= ser.getTx();
    
                // Category Axis Data
                cat = ser.getCat();
                // 获取图表的值
                val = ser.getVal();
                // strData.set
                CTStrData strData = cat.getStrRef().getStrCache();
                CTNumData numData = val.getNumRef().getNumCache();
                strData.setPtArray((CTStrVal[]) null); // unset old axis text
                numData.setPtArray((CTNumVal[]) null); // unset old values
    
                // set model
                long idx = 0;
                for (int j = 0; j < dataList.size(); j++) {
                    //判断获取的值是否为空
                    String value = "0";
                    if (new BigDecimal(dataList.get(j).get(fldNameArr.get(i + position))) != null) {
                        value = new BigDecimal(dataList.get(j).get(fldNameArr.get(i + position))).toString();
                    }
                    if (!"0".equals(value)) {
                        CTNumVal numVal = numData.addNewPt();//序列值
                        numVal.setIdx(idx);
                        numVal.setV(value);
                    }
                    CTStrVal sVal = strData.addNewPt();//序列名称
                    sVal.setIdx(idx);
                    sVal.setV(dataList.get(j).get(fldNameArr.get(0)));
                    idx++;
                }
                numData.getPtCount().setVal(idx);
                strData.getPtCount().setVal(idx);
    
    
                //赋值横坐标数据区域
                String axisDataRange = new CellRangeAddress(1, dataList.size(), 0, 0)
                        .formatAsString("Sheet1", true);
                cat.getStrRef().setF(axisDataRange);
    
                //数据区域
                String numDataRange = new CellRangeAddress(1, dataList.size(), i + position, i + position)
                        .formatAsString("Sheet1", true);
                val.getNumRef().setF(numDataRange);
    
            }
            return result;
        }
    
    
    
        /**
         * 刷新饼图数据方法
         *
         * @param typeChart
         * @param serList
         * @param dataList
         * @param fldNameArr
         * @param position
         * @return
         */
        public static boolean refreshPieStrGraphContent(Object typeChart,
                                                        List<?> serList, List<Map<String, String>> dataList, List<String> fldNameArr, int position) {
    
            boolean result = true;
            //更新数据区域
            for (int i = 0; i < serList.size(); i++) {
                //CTSerTx tx=null;
                CTAxDataSource cat = null;
                CTNumDataSource val = null;
                CTPieSer ser = ((CTPieChart) typeChart).getSerArray(i);
    
                //tx= ser.getTx();
                // Category Axis Data
                cat = ser.getCat();
                // 获取图表的值
                val = ser.getVal();
                // strData.set
                CTStrData strData = cat.getStrRef().getStrCache();
                CTNumData numData = val.getNumRef().getNumCache();
                strData.setPtArray((CTStrVal[]) null); // unset old axis text
                numData.setPtArray((CTNumVal[]) null); // unset old values
    
                // set model
                long idx = 0;
                for (int j = 0; j < dataList.size(); j++) {
                    //判断获取的值是否为空
                    String value = "0";
                    if (new BigDecimal(dataList.get(j).get(fldNameArr.get(i + position))) != null) {
                        value = new BigDecimal(dataList.get(j).get(fldNameArr.get(i + position))).toString();
                    }
                    if (!"0".equals(value)) {
                        CTNumVal numVal = numData.addNewPt();//序列值
                        numVal.setIdx(idx);
                        numVal.setV(value);
                    }
                    CTStrVal sVal = strData.addNewPt();//序列名称
                    sVal.setIdx(idx);
                    sVal.setV(dataList.get(j).get(fldNameArr.get(0)));
                    idx++;
                }
                numData.getPtCount().setVal(idx);
                strData.getPtCount().setVal(idx);
    
    
                //赋值横坐标数据区域
                String axisDataRange = new CellRangeAddress(1, dataList.size(), 0, 0)
                        .formatAsString("Sheet1", true);
                cat.getStrRef().setF(axisDataRange);
    
                //数据区域
                String numDataRange = new CellRangeAddress(1, dataList.size(), i + position, i + position)
                        .formatAsString("Sheet1", true);
                val.getNumRef().setF(numDataRange);
            }
            return result;
        }
    
    
        /**
         * 刷新内置excel数据
         *
         * @param chart
         * @param dataList
         * @param fldNameArr
         * @param titleArr
         * @return
         */
        public static boolean refreshExcel(XWPFChart chart,
                                           List<Map<String, String>> dataList, List<String> fldNameArr, List<String> titleArr) {
            boolean result = true;
            Workbook wb = new XSSFWorkbook();
            Sheet sheet = wb.createSheet("Sheet1");
            //根据数据创建excel第一行标题行
            for (int i = 0; i < titleArr.size(); i++) {
                if (sheet.getRow(0) == null) {
                    sheet.createRow(0).createCell(i).setCellValue(titleArr.get(i) == null ? "" : titleArr.get(i));
                } else {
                    sheet.getRow(0).createCell(i).setCellValue(titleArr.get(i) == null ? "" : titleArr.get(i));
                }
            }
    
            //遍历数据行
            for (int i = 0; i < dataList.size(); i++) {
                Map<String, String> baseFormMap = dataList.get(i);//数据行
                //fldNameArr字段属性
                for (int j = 0; j < fldNameArr.size(); j++) {
                    if (sheet.getRow(i + 1) == null) {
                        if (j == 0) {
                            try {
                                sheet.createRow(i + 1).createCell(j).setCellValue(baseFormMap.get(fldNameArr.get(j)) == null ? "" : baseFormMap.get(fldNameArr.get(j)));
                            } catch (Exception e) {
                                if (baseFormMap.get(fldNameArr.get(j)) == null) {
                                    sheet.createRow(i + 1).createCell(j).setCellValue("");
                                } else {
                                    sheet.createRow(i + 1).createCell(j).setCellValue(baseFormMap.get(fldNameArr.get(j)));
                                }
                            }
                        }
                    } else {
                        BigDecimal b = new BigDecimal(baseFormMap.get(fldNameArr.get(j)));
                        double value = 0d;
                        if (b != null) {
                            value = b.doubleValue();
                        }
                        if (value == 0) {
                            sheet.getRow(i + 1).createCell(j);
                        } else {
                            sheet.getRow(i + 1).createCell(j).setCellValue(b.doubleValue());
                        }
                    }
                }
    
            }
            // 更新嵌入的workbook
            POIXMLDocumentPart xlsPart = chart.getRelations().get(0);
            OutputStream xlsOut = xlsPart.getPackagePart().getOutputStream();
    
            try {
                wb.write(xlsOut);
                xlsOut.close();
            } catch (IOException e) {
                e.printStackTrace();
                result = false;
            } finally {
                if (wb != null) {
                    try {
                        wb.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                        result = false;
                    }
                }
            }
            return result;
        }
    
    
        /**
         * 设置表格样式
         *
         * @param cell
         * @param fontName
         * @param fontSize
         * @param fontBlod
         * @param alignment
         * @param vertical
         * @param fontColor
         * @param bgColor
         * @param cellWidth
         * @param content
         */
        public static void setWordCellSelfStyle(XWPFTableCell cell, String fontName, String fontSize, int fontBlod,
                                                String alignment, String vertical, String fontColor,
                                                String bgColor, String cellWidth, String content) {
    
            //poi对字体大小设置特殊,不支持小数,但对原word字体大小做了乘2处理
            BigInteger bFontSize = new BigInteger("24");
            if (fontSize != null && !fontSize.equals("")) {
                //poi对字体大小设置特殊,不支持小数,但对原word字体大小做了乘2处理
                BigDecimal fontSizeBD = new BigDecimal(fontSize);
                fontSizeBD = bd2.multiply(fontSizeBD);
                fontSizeBD = fontSizeBD.setScale(0, BigDecimal.ROUND_HALF_UP);//这里取整
                bFontSize = new BigInteger(fontSizeBD.toString());// 字体大小
            }
    
            // 设置单元格宽度
            cell.setWidth(cellWidth);
    
            //=====获取单元格
            CTTc tc = cell.getCTTc();
            //====tcPr开始====》》》》
            CTTcPr tcPr = tc.getTcPr();//获取单元格里的<w:tcPr>
            if (tcPr == null) {//没有<w:tcPr>,创建
                tcPr = tc.addNewTcPr();
            }
    
            //  --vjc开始-->>
            CTVerticalJc vjc = tcPr.getVAlign();//获取<w:tcPr>  的<w:vAlign w:val="center"/>
            if (vjc == null) {//没有<w:w:vAlign/>,创建
                vjc = tcPr.addNewVAlign();
            }
            //设置单元格对齐方式
            vjc.setVal(vertical.equals("top") ? STVerticalJc.TOP : vertical.equals("bottom") ? STVerticalJc.BOTTOM : STVerticalJc.CENTER); //垂直对齐
    
            CTShd shd = tcPr.getShd();//获取<w:tcPr>里的<w:shd w:val="clear" w:color="auto" w:fill="C00000"/>
            if (shd == null) {//没有<w:shd>,创建
                shd = tcPr.addNewShd();
            }
            // 设置背景颜色
            shd.setFill(bgColor.substring(1));
            //《《《《====tcPr结束====
    
            //====p开始====》》》》
            CTP p = tc.getPList().get(0);//获取单元格里的<w:p w:rsidR="00C36068" w:rsidRPr="00B705A0" w:rsidRDefault="00C36068" w:rsidP="00C36068">
    
            //---ppr开始--->>>
            CTPPr ppr = p.getPPr();//获取<w:p>里的<w:pPr>
            if (ppr == null) {//没有<w:pPr>,创建
                ppr = p.addNewPPr();
            }
            //  --jc开始-->>
            CTJc jc = ppr.getJc();//获取<w:pPr>里的<w:jc w:val="left"/>
            if (jc == null) {//没有<w:jc/>,创建
                jc = ppr.addNewJc();
            }
            //设置单元格对齐方式
            jc.setVal(alignment.equals("left") ? STJc.LEFT : alignment.equals("right") ? STJc.RIGHT : STJc.CENTER); //水平对齐
            //  <<--jc结束--
            //  --pRpr开始-->>
            CTParaRPr pRpr = ppr.getRPr(); //获取<w:pPr>里的<w:rPr>
            if (pRpr == null) {//没有<w:rPr>,创建
                pRpr = ppr.addNewRPr();
            }
            CTFonts pfont = pRpr.getRFonts();//获取<w:rPr>里的<w:rFonts w:ascii="宋体" w:eastAsia="宋体" w:hAnsi="宋体"/>
            if (pfont == null) {//没有<w:rPr>,创建
                pfont = pRpr.addNewRFonts();
            }
            //设置字体
            pfont.setAscii(fontName);
            pfont.setEastAsia(fontName);
            pfont.setHAnsi(fontName);
    
            CTOnOff pb = pRpr.getB();//获取<w:rPr>里的<w:b/>
            if (pb == null) {//没有<w:b/>,创建
                pb = pRpr.addNewB();
            }
            //设置字体是否加粗
            pb.setVal(fontBlod == 1 ? STOnOff.ON : STOnOff.OFF);
    
            CTHpsMeasure psz = pRpr.getSz();//获取<w:rPr>里的<w:sz w:val="32"/>
            if (psz == null) {//没有<w:sz w:val="32"/>,创建
                psz = pRpr.addNewSz();
            }
            // 设置单元格字体大小
            psz.setVal(bFontSize);
            CTHpsMeasure pszCs = pRpr.getSzCs();//获取<w:rPr>里的<w:szCs w:val="32"/>
            if (pszCs == null) {//没有<w:szCs w:val="32"/>,创建
                pszCs = pRpr.addNewSzCs();
            }
            // 设置单元格字体大小
            pszCs.setVal(bFontSize);
            //  <<--pRpr结束--
            //<<<---ppr结束---
    
            //---r开始--->>>
            List<CTR> rlist = p.getRList(); //获取<w:p>里的<w:r w:rsidRPr="00B705A0">
            CTR r = null;
            if (rlist != null && rlist.size() > 0) {//获取第一个<w:r>
                r = rlist.get(0);
            } else {//没有<w:r>,创建
                r = p.addNewR();
            }
            //--rpr开始-->>
            CTRPr rpr = r.getRPr();//获取<w:r w:rsidRPr="00B705A0">里的<w:rPr>
            if (rpr == null) {//没有<w:rPr>,创建
                rpr = r.addNewRPr();
            }
            //->-
            CTFonts font = rpr.getRFonts();//获取<w:rPr>里的<w:rFonts w:ascii="宋体" w:eastAsia="宋体" w:hAnsi="宋体" w:hint="eastAsia"/>
            if (font == null) {//没有<w:rFonts>,创建
                font = rpr.addNewRFonts();
            }
            //设置字体
            font.setAscii(fontName);
            font.setEastAsia(fontName);
            font.setHAnsi(fontName);
    
            CTOnOff b = rpr.getB();//获取<w:rPr>里的<w:b/>
            if (b == null) {//没有<w:b/>,创建
                b = rpr.addNewB();
            }
            //设置字体是否加粗
            b.setVal(fontBlod == 1 ? STOnOff.ON : STOnOff.OFF);
            CTColor color = rpr.getColor();//获取<w:rPr>里的<w:color w:val="FFFFFF" w:themeColor="background1"/>
            if (color == null) {//没有<w:color>,创建
                color = rpr.addNewColor();
            }
            // 设置字体颜色
            if (content.contains("↓")) {
                color.setVal("43CD80");
            } else if (content.contains("↑")) {
                color.setVal("943634");
            } else {
                color.setVal(fontColor.substring(1));
            }
            CTHpsMeasure sz = rpr.getSz();
            if (sz == null) {
                sz = rpr.addNewSz();
            }
            sz.setVal(bFontSize);
            CTHpsMeasure szCs = rpr.getSzCs();
            if (szCs == null) {
                szCs = rpr.addNewSz();
            }
            szCs.setVal(bFontSize);
            //-<-
            //<<--rpr结束--
            List<CTText> tlist = r.getTList();
            CTText t = null;
            if (tlist != null && tlist.size() > 0) {//获取第一个<w:r>
                t = tlist.get(0);
            } else {//没有<w:r>,创建
                t = r.addNewT();
            }
            t.setStringValue(content);
            //<<<---r结束---
        }
    
    
        /**
         * 获取内置表格数据,拿到第一行第一列格子数据
         * 有时候模板设计太复杂,对于图表不能精准定位,可以通过设置图表表格数据的第一行第一列格子数据来区分,这个数据不影响图表显示,所以用来区分每个图表
         */
        public static String getZeroData(POIXMLDocumentPart poixmlDocumentPart){
            String text = "";
            try {
                XWPFChart chart = (XWPFChart) poixmlDocumentPart;
                chart.getCTChart();
    
                POIXMLDocumentPart xlsPart = chart.getRelations().get(0);
                InputStream xlsin = xlsPart.getPackagePart().getInputStream();
    
                Workbook workbook = new XSSFWorkbook(xlsin);
                // 获取第一个sheet
                Sheet sheet = workbook.getSheetAt(0);
                // 第一行
                Row row = sheet.getRow(0);
                // 第一列
                Cell cell = row.getCell(0);
    
                cell.setCellType(CellType.STRING);  // 设置一下格子类型为字符串,不然如果是数字或者时间的话,获取很麻烦
                text = cell.getStringCellValue();   // 获取格子内容
    
                System.out.println("(0,0)格子值:" + text);
    
                // 关闭流
                xlsin.close();
    
            } catch (Exception e) {
                e.printStackTrace();
            }
    
    
            return text;
        }
    
    
    }
    
    

    4.直接运行PoiDemoWordTable类中的main方法即可

    该示例中,实现了:文本替换、动态添加表格、柱状图、折线图、饼图、柱状+折线组合图,后续有其它的示例,会继续在此基础上扩展。代码都很简单。

    5.运行结果

    有个问题(已解决):运行代码之后查看生成的word结果,发现可能部分图表显示数据和实际代码中设置的数据不一致,这种情况都是word模板引起的。
    比方说在这个图中只显示了一条折线图,但是实际上代码数据中有3个折线图数据;这里我们右键该图表:点击编辑数据,然后会出来一个excel表格,这就是图表内置的数据,打开后我们可以看到一个蓝色的框框:,这个蓝色框框包含的数据,图表才会显示,这里是图表真正的数据源;对于这种情况,需要手动的把所有数据被蓝色框框包住才行,直接鼠标托就行。

    对于这个问题,word应该是有办法解决的,也就是图表的数据源能够动态更新,这个有需要的童鞋可以研究下。

     

    2019-12-04:新增:动态刷新内置Excel数据

    1:在原有模板的基础上,新加内置Excel表格文件,如图所示:图片看得清哈......

    说明:尝试过使用xlsx后缀的文件,但是代码报错了,报错大概意思是:你确定这是个excel文件?

    所以改成xls就好了,至于xlsx为什么不行,下来继续琢磨;

     

    2:一个类代码

    该类是在原有的demo代码里面写的,只有一个类,和之前的不冲突,但是用的word模板是同一个;

    看着不明白的地方,多瞅瞅,欢迎提出,我也是看的官网来着;

    /**
     * 代码参考了poi官网文档的api示例
     * poi官方api:http://poi.apache.org/components/document/quick-guide-xwpf.html
     * 官方示例源码:http://svn.apache.org/repos/asf/poi/trunk/src/examples/src/org/apache/poi/xwpf/usermodel/examples/UpdateEmbeddedDoc.java
     */
    package com.example.demo;
    
    
    import org.apache.poi.openxml4j.opc.PackagePart;
    import org.apache.poi.ss.usermodel.*;
    import org.apache.poi.xwpf.usermodel.XWPFDocument;
    
    import java.io.*;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     * 更新模板word中的内置Excel数据
     * 代码参考了poi官网文档的api示例
     * poi官方api:http://poi.apache.org/components/document/quick-guide-xwpf.html
     * 官方示例源码:http://svn.apache.org/repos/asf/poi/trunk/src/examples/src/org/apache/poi/xwpf/usermodel/examples/UpdateEmbeddedDoc.java
     */
    public class UpdateEmbeddedDoc {
    
        private static final String templateurl = "D:\\youxi\\jx\\test.docx";  // 模板文件
        private static final String returnurl = "D:\\youxi\\jx\\result.docx";  // 结果文件
        private XWPFDocument doc; // 模板文档对象
        private File docFile;
        private static final int SHEET_NUM = 0;   // xls中的sheet页数
        private static List<Map<String, String>> dataList = new ArrayList<Map<String, String>>();   // 模拟数据
    
        static {
            // 模拟数据
            for (int i = 0; i < 10; i++) {
                Map<String, String> map = new HashMap<String, String>();
                map.put("index-0", "老王吧" + i);
                map.put("index-1", "老李吧" + i);
                map.put("index-2", "老张吧" + i);
                map.put("index-3", "老刘吧" + i);
                map.put("index-4", "老杨吧" + i);
                map.put("index-5", "老乌龟吧" + i);
    
                dataList.add(map);
            }
        }
    
    
        public static void main(String[] args) throws Exception {
            UpdateEmbeddedDoc ued = new UpdateEmbeddedDoc(templateurl);
            ued.updateEmbeddedDoc();
        }
    
        /**
         * 构造函数,加载模板文档
         * @param filename
         * @throws IOException
         */
        public UpdateEmbeddedDoc(String filename) throws IOException {
            this.docFile = new File(filename);
            if (!this.docFile.exists()) {
                throw new FileNotFoundException("The Word document " + filename + " does not exist.");
            }
            try (FileInputStream fis = new FileInputStream(this.docFile)) {
                // Open the Word document file and instantiate the XWPFDocument class.
                this.doc = new XWPFDocument(fis);
            }
        }
    
    
        /**
         * 更新word文档中内置的Excel工作簿
         * Excel是事先已知的,并且在模板word中已经插入成功了的
         * @param filename
         * @throws IOException
         */
        public void updateEmbeddedDoc() throws Exception {
            // 获取模板文档中的内置部分,也就是获取到插入的Excel文档集合
            List<PackagePart> embeddedDocs = this.doc.getAllEmbeddedParts();
            for (PackagePart pPart : embeddedDocs) {
    
                // 这里打印出来文档中所有的内置对象,可以看到每个内置对象都有一个唯一标识,通过这个标识可以做相应的业务逻辑;
                // 这里打印的oleFlag可能因为机器环境原因有所不同,建议先打印出oleFlag的值,对比后再做if判断;
                // 反正这里输出的内容看一下,就明白了;
                String oleFlag = pPart.toString();
                System.out.println(oleFlag);
    
                // 记得if中的条件“oleObject1”要和上面的oleFlag对比一下,能够唯一标识就好,我不敢保证每台机器的值都是“oleObject1”
                // 第一个内置对象,
                if (oleFlag.indexOf("oleObject1") > 0) {
                    doXls1(pPart);
    
                } else if (oleFlag.indexOf("oleObject2") > 0) {
                    doXls2(pPart); // 第二个内置对象,
    
                } else if (oleFlag.indexOf("oleObject3") > 0) {
                    doXls3(pPart); // 第三个内置对象,
    
                }
    
                // TODO.......
    
            }
    
            if (!embeddedDocs.isEmpty()) {
                // Finally, write the newly modified Word document out to file.
                try (FileOutputStream fos = new FileOutputStream(returnurl)) {
                    File file = new File(returnurl);
                    if (file.exists()) {
                        file.delete();
                    }
                    this.doc.write(fos);
                    fos.close();
                }
            }
        }
    
    
        /**
         * 第一个内置对象,数据的话自己造吧,这里我懒,用了一个数据
         * @param pPart
         * @throws Exception
         */
        public void doXls1(PackagePart pPart) throws Exception {
            try (InputStream is = pPart.getInputStream();
                 Workbook workbook = WorkbookFactory.create(is);
                 OutputStream os = pPart.getOutputStream()) {
                Sheet sheet = workbook.getSheetAt(SHEET_NUM);
                int ROW_NUM = 1;
                // 设置内置xlsx文件的数据,这里示例代码写的很傻瓜,看明白就好了;
                for (int i = 0; i < dataList.size(); i++) {
                    Row row = sheet.createRow(ROW_NUM); // 创建行
    
                    Map<String, String> colMap = dataList.get(i);
                    Cell cell0 = row.createCell(0);
                    cell0.setCellValue(colMap.get("index-0")); // 第0列数据
    
                    Cell cell1 = row.createCell(1);
                    cell1.setCellValue(colMap.get("index-1")); // 第1列数据
    
                    Cell cell2 = row.createCell(2);
                    cell2.setCellValue(colMap.get("index-2")); // 第2列数据
    
                    Cell cell3 = row.createCell(3);
                    cell3.setCellValue(colMap.get("index-3")); // 第3列数据
    
                    Cell cell4 = row.createCell(4);
                    cell4.setCellValue(colMap.get("index-4")); // 第4列数据
    
                    Cell cell5 = row.createCell(5);
                    cell5.setCellValue(colMap.get("index-5")); // 第5列数据
    
    
                    ROW_NUM++;
                }
    
                workbook.write(os);
            }
        }
    
    
        /**
         * 第二个内置对象,数据的话自己造吧,这里我懒,用了一个数据
         * @param pPart
         * @throws Exception
         */
        public void doXls2(PackagePart pPart) throws Exception {
            try (InputStream is = pPart.getInputStream();
                 Workbook workbook = WorkbookFactory.create(is);
                 OutputStream os = pPart.getOutputStream()) {
                Sheet sheet = workbook.getSheetAt(SHEET_NUM);
                int ROW_NUM = 1;
                // 设置内置xlsx文件的数据,这里示例代码写的很傻瓜,看明白就好了;
                for (int i = 0; i < dataList.size(); i++) {
                    Row row = sheet.createRow(ROW_NUM); // 创建行
    
                    Map<String, String> colMap = dataList.get(i);
                    Cell cell0 = row.createCell(0);
                    cell0.setCellValue(colMap.get("index-0")); // 第0列数据
    
                    Cell cell1 = row.createCell(1);
                    cell1.setCellValue(colMap.get("index-1")); // 第1列数据
    
                    Cell cell2 = row.createCell(2);
                    cell2.setCellValue(colMap.get("index-2")); // 第2列数据
    
                    Cell cell3 = row.createCell(3);
                    cell3.setCellValue(colMap.get("index-3")); // 第3列数据
    
                    Cell cell4 = row.createCell(4);
                    cell4.setCellValue(colMap.get("index-4")); // 第4列数据
    
                    Cell cell5 = row.createCell(5);
                    cell5.setCellValue(colMap.get("index-5")); // 第5列数据
    
    
                    ROW_NUM++;
                }
    
                workbook.write(os);
            }
        }
    
    
        /**
         * 第三个内置对象,数据的话自己造吧,这里我懒,用了一个数据
         * @param pPart
         * @throws Exception
         */
        public void doXls3(PackagePart pPart) throws Exception {
            try (InputStream is = pPart.getInputStream();
                 Workbook workbook = WorkbookFactory.create(is);
                 OutputStream os = pPart.getOutputStream()) {
                Sheet sheet = workbook.getSheetAt(SHEET_NUM);
                int ROW_NUM = 1;
                // 设置内置xlsx文件的数据,这里示例代码写的很傻瓜,看明白就好了;
                for (int i = 0; i < dataList.size(); i++) {
                    Row row = sheet.createRow(ROW_NUM); // 创建行
    
                    Map<String, String> colMap = dataList.get(i);
                    Cell cell0 = row.createCell(0);
                    cell0.setCellValue(colMap.get("index-0")); // 第0列数据
    
                    Cell cell1 = row.createCell(1);
                    cell1.setCellValue(colMap.get("index-1")); // 第1列数据
    
                    Cell cell2 = row.createCell(2);
                    cell2.setCellValue(colMap.get("index-2")); // 第2列数据
    
                    Cell cell3 = row.createCell(3);
                    cell3.setCellValue(colMap.get("index-3")); // 第3列数据
    
                    Cell cell4 = row.createCell(4);
                    cell4.setCellValue(colMap.get("index-4")); // 第4列数据
    
                    Cell cell5 = row.createCell(5);
                    cell5.setCellValue(colMap.get("index-5")); // 第5列数据
    
    
                    ROW_NUM++;
                }
    
                workbook.write(os);
            }
        }
    
    
    }
    

    生成结果:双击结果文档中的内置excel表格,结果如图

     

    2020-04-07:新增:更新插入的文本框内容

    1:在博友的帮助下,添加了对文本框内容的替换,方式很简单,模板截图如下:随意位置插入文本框即可

    2:主要类:
    该方法参考地址:https://blog.csdn.net/yousun4688/article/details/90108335(感谢老哥)

    package com.example.demo.text;
    
    import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
    import org.apache.poi.xwpf.usermodel.XWPFDocument;
    import org.apache.poi.xwpf.usermodel.XWPFParagraph;
    import org.apache.xmlbeans.XmlCursor;
    import org.apache.xmlbeans.XmlObject;
    
    import java.io.*;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     * 对文本框的替换,对文本框的替换,不是正常输入的文本
     */
    public class TextBox {
    
        public static List<String> patternList = new ArrayList();
    
        //需要处理的节点名称
        static {
            patternList.add("mc:AlternateContent");
            patternList.add("mc:Choice");
            patternList.add("w:drawing");
            patternList.add("wp:anchor");
            patternList.add("a:graphic");
            patternList.add("a:graphicData");
            patternList.add("wps:wsp");
            patternList.add("wps:txbx");
            patternList.add("w:txbxContent");
            patternList.add("w:p");
            patternList.add("w:r");
            patternList.add("w:t");
        }
    
        public static void main(String[] args) throws Exception {
    
            final String returnurl = "D:\\youxi\\jx\\textbox.docx";  // 结果文件
            final String templateurl = "D:\\直真科技工作相关\\demo\\src\\main\\resources\\textbox.docx";  // 模板文件
    
            InputStream is = new FileInputStream(new File(templateurl));
            XWPFDocument doc = new XWPFDocument(is);
    
            // 替换word模板数据
            replaceAll(doc);
    
            // 保存结果文件
            try {
                File file = new File(returnurl);
                if (file.exists()) {
                    file.delete();
                }
                FileOutputStream fos = new FileOutputStream(returnurl);
                doc.write(fos);
                fos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    
        /**
         * @Description: 替换段落和表格中
         */
        public static void replaceAll(XWPFDocument doc) throws Exception {
            doParagraphs(doc); // 处理段落文字数据,包括文字和表格、图片
        }
    
    
        /**
         * 处理段落文字
         *
         * @param doc
         * @throws InvalidFormatException
         * @throws FileNotFoundException
         * @throws IOException
         */
        public static void doParagraphs(XWPFDocument doc) throws Exception {
    
            // 文本数据
            Map<String, String> textMap = new HashMap<String, String>();
            textMap.put("texttext", "我是被替换的普通文本内容");
            textMap.put("name", "我是被替换的文本框内容");
            textMap.put("zuoyou", "左右");
    
            changeTextBox(doc, textMap);
    
        }
    
    
        public static void changeTextBox(XWPFDocument document, Map<String, String> map) {
            for (XWPFParagraph paragraph : document.getParagraphs())
                for (XmlObject object : paragraph.getCTP().getRArray()) {
                    XmlCursor cursor = object.newCursor();
                    eachchild(cursor, 0, map);
                }
        }
    
    
        public static void eachchild(XmlCursor cursor, int start, Map<String, String> map) {
            for (int i = 0; i < 10; i++) {
                if (cursor.toChild(i)) {
                    if (cursor.getDomNode().getNodeName().equals(patternList.get(start))) {
                        if (start == patternList.size() - 1) {
                            String reString = cursor.getTextValue();
                            System.out.println(reString);
                            reString = reString.replaceAll("\\{\\{", "").replaceAll("}}", "");
    
                            for (String e : map.keySet()) {
                                if (reString.equals(e)) {
                                    //    执行替换
                                    reString = reString.replaceAll(e, map.get(e));
                                }
                            }
                            cursor.setTextValue(reString);
                        }
                        eachchild(cursor, start + 1, map);
                    } else {
                        cursor.toParent();
                    }
                }
            }
    
            cursor.toParent();
        }
    
    
    }
    

    3:替换后的效果,这个方法对普通文本不会生效,只会对文本框有效,并且替换的逻辑可以自己控制

     

    2020-04-10:新增:新增一个定位图表的方式

    问题描述:

    在使用word模板中,如果存在很多个图表,如何获取到正确的图表,按照我现有的方式是如图这样。

    通过把图表对象toString后获得“/word/charts/chart1.xml”这样的key值,这种方式对于图表在word模板中的位置是从上到下的很好用。

    但是如果现在word模板中的图表位置很乱,位置是随意插入的,有横着排,也有竖着排,布局很乱的情况,这种方式就不好用了。

    1:解决方案

    对图表编辑数据的表格进行了观察,发现第一行第一列数据,无论怎样设置都不会推图表显示有任何影响,如下图所示的这个格子数据。所以在word模板中,修改每个图表的这个格子数据,保证全局唯一,相当于图表的唯一标识。然后在读取word模板时,读取一下图表的数据,获取第一行第一列格子的值,用来当作key。

    2:修改模板

    右键图表,选择编辑数据,出来的表格,修改第一行第一列的数据,要求全局唯一不重复。然后保存。

    3:新增处理方法

    该方法拿到POIXMLDocumentPart 对象,拿到Workbook对象,返回的text就是第一行第一列的数据。

    /**
         * 获取内置表格数据,拿到第一行第一列格子数据
         * 有时候模板设计太复杂,对于图表不能精准定位,可以通过设置图表表格数据的第一行第一列格子数据来区分,这个数据不影响图表显示,所以用来区分每个图表
         */
        public static String getZeroData(POIXMLDocumentPart poixmlDocumentPart){
            String text = "";
            try {
                XWPFChart chart = (XWPFChart) poixmlDocumentPart;
                chart.getCTChart();
    
                POIXMLDocumentPart xlsPart = chart.getRelations().get(0);
                InputStream xlsin = xlsPart.getPackagePart().getInputStream();
    
                Workbook workbook = new XSSFWorkbook(xlsin);
                // 获取第一个sheet
                Sheet sheet = workbook.getSheetAt(0);
                // 第一行
                Row row = sheet.getRow(0);
                // 第一列
                Cell cell = row.getCell(0);
    
                cell.setCellType(CellType.STRING);  // 设置一下格子类型为字符串,不然如果是数字或者时间的话,获取很麻烦
                text = cell.getStringCellValue();   // 获取格子内容
    
                System.out.println("(0,0)格子值:" + text);
    
                // 关闭流
                xlsin.close();
    
            } catch (Exception e) {
                e.printStackTrace();
            }
    
    
            return text;
        }

     4:设置key

    5:通过key获取图表对象

     

    6:代码对应类:com.example.demo.example.barchart.BarChart

     

    2020-04-11:新增:柱状图动态列,解决需要对图表编辑数据才能有效显示的问题

    1:主类

    package com.example.demo.example.barchart;
    
    import com.example.demo.util.PoiWordTools;
    import com.example.demo.util.PoiWordToolsDynamic;
    import org.apache.poi.ooxml.POIXMLDocumentPart;
    import org.apache.poi.xwpf.usermodel.XWPFChart;
    import org.apache.poi.xwpf.usermodel.XWPFDocument;
    
    import java.io.*;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    
    /**
     * 动态的柱状图,也就是列不确定,由数据决定
     * 示例代码仅提供实现的参考,可根据自己的业务修改逻辑
     */
    public class BarChartDynamic {
    
        public static void main(String[] args) throws Exception {
    
            final String returnurl = "D:\\youxi\\jx\\barchartdynamicresult.docx";  // 结果文件
            final String templateurl = "D:\\直真科技工作相关\\demo\\src\\main\\resources\\barchartdynamic.docx";  // 模板文件
    
            InputStream is = new FileInputStream(new File(templateurl));
            XWPFDocument doc = new XWPFDocument(is);
    
            // 替换word模板数据
            replaceAll(doc);
    
            // 保存结果文件
            try {
                File file = new File(returnurl);
                if (file.exists()) {
                    file.delete();
                }
                FileOutputStream fos = new FileOutputStream(returnurl);
                doc.write(fos);
                fos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    
        /**
         * @Description: 替换段落和表格和图表等内容
         */
        public static void replaceAll(XWPFDocument doc) throws Exception {
            doCharts(doc);  // 处理图表数据,柱状图
        }
    
    
        /**
         * 处理图表
         *
         * @param doc
         * @throws FileNotFoundException
         */
        public static void doCharts(XWPFDocument doc) throws FileNotFoundException {
            /**----------------------------处理图表------------------------------------**/
            // 获取word模板中的所有图表元素,用map存放
            // 为什么不用list保存:查看doc.getRelations()的源码可知,源码中使用了hashMap读取文档图表元素,
            // 对relations变量进行打印后发现,图表顺序和文档中的顺序不一致,也就是说relations的图表顺序不是文档中从上到下的顺序
            Map<String, POIXMLDocumentPart> chartsMap = new HashMap<String, POIXMLDocumentPart>();
            //动态刷新图表
            List<POIXMLDocumentPart> relations = doc.getRelations();
            for (POIXMLDocumentPart poixmlDocumentPart : relations) {
                if (poixmlDocumentPart instanceof XWPFChart) {  // 如果是图表元素
    
                    // 获取图表对应的表格数据里面的第一行第一列数据,可以拿来当作key值
                    String key = new PoiWordTools().getZeroData(poixmlDocumentPart).trim();
    
                    System.out.println("key:" + key);
    
                    chartsMap.put(key, poixmlDocumentPart);
                }
            }
    
            System.out.println("\n图表数量:" + chartsMap.size() + "\n");
    
            // 第一个图表-柱状图
            doCharts1(chartsMap);
    
        }
    
    
        /**
         * 封装图表数据
         * @param chartsMap
         */
        public static void doCharts1(Map<String, POIXMLDocumentPart> chartsMap) {
            // 数据准备
            List<String> titleArr = new ArrayList<String>();// 标题,也就是对图表选择编辑数据后显示的表格数据的第一行
            titleArr.add("");
            titleArr.add("存款$");
            titleArr.add("欠款$");
            titleArr.add("还款$");
    
            List<String> fldNameArr = new ArrayList<String>();// 字段名(数据有多少列,就多少个)
            fldNameArr.add("item1");
            fldNameArr.add("item2");
            fldNameArr.add("item3");
            fldNameArr.add("item4");
    
            // 数据集合
            List<Map<String, String>> listItemsByType = new ArrayList<Map<String, String>>();
    
            // 数据的话随便整都行
    
            // 第一行数据
            Map<String, String> base1 = new HashMap<String, String>();
            base1.put("item1", "2020-05");
            base1.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base1.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base1.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            // 第二行数据
            Map<String, String> base2 = new HashMap<String, String>();
            base2.put("item1", "2020-06");
            base2.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base2.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base2.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            // 第三行数据
            Map<String, String> base3 = new HashMap<String, String>();
            base3.put("item1", "2020-07");
            base3.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base3.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base3.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            listItemsByType.add(base1);
            listItemsByType.add(base2);
            listItemsByType.add(base3);
    
            // 注意这里的key值
            POIXMLDocumentPart poixmlDocumentPart = chartsMap.get("嘻嘻嘻嘻");  // 图表对象
            new PoiWordToolsDynamic().replaceBarCharts(poixmlDocumentPart, titleArr, fldNameArr, listItemsByType);
        }
    
    
    }
    
    

    2:辅助类1

    package com.example.demo.util;
    
    import org.apache.poi.ooxml.POIXMLDocumentPart;
    import org.apache.poi.ss.usermodel.*;
    import org.apache.poi.ss.util.CellRangeAddress;
    import org.apache.poi.xssf.usermodel.XSSFWorkbook;
    import org.apache.poi.xwpf.usermodel.XWPFChart;
    import org.apache.poi.xwpf.usermodel.XWPFTableCell;
    import org.openxmlformats.schemas.drawingml.x2006.chart.*;
    import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor;
    import org.openxmlformats.schemas.drawingml.x2006.main.STSchemeColorVal;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.math.BigDecimal;
    import java.math.BigInteger;
    import java.util.List;
    import java.util.Map;
    
    /**
     * poi生成word的工具类
     * 可以动态生成图表,可以自己设置图表列的数量
     */
    public class PoiWordToolsDynamic {
    
        private static final BigDecimal bd2 = new BigDecimal("2");
    
    
        /**
         * 调用替换柱状图数据-可以实现动态列
         * 其它的折线图、饼图大同小异
         */
        public static void replaceBarCharts(POIXMLDocumentPart poixmlDocumentPart,
                                            List<String> titleArr,
                                            List<String> fldNameArr,
                                            List<Map<String, String>> listItemsByType) {
    
            // 很重要的参数,图表系列的数量,由这里的数据决定
            int culomnNum = titleArr.size() - 1;
    
            XWPFChart chart = (XWPFChart) poixmlDocumentPart;
            chart.getCTChart();
    
            //根据属性第一列名称切换数据类型
            CTChart ctChart = chart.getCTChart();
            CTPlotArea plotArea = ctChart.getPlotArea();
    
            // 柱状图用plotArea.getBarChartArray,
            // 折线图用plotArea.getLineChartArray,
            // 饼图用plotArea.getPieChartArray.....
            // 还有很多其它的
            CTBarChart barChart = plotArea.getBarChartArray(0);
    
            // 清除图表的样式,由代码自己设置
            barChart.getSerList().clear();
    
            //刷新内置excel数据
            new PoiWordToolsDynamic().refreshExcel(chart, listItemsByType, fldNameArr, titleArr);
            //刷新页面显示数据-也就是刷新图表的数据源范围
            refreshBarStrGraphContent(barChart, listItemsByType, fldNameArr, 1, culomnNum, titleArr);
        }
    
    
        /**
         * 调用替换柱状图数据-可以实现动态列
         * 其它的折线图、饼图大同小异
         */
        public static void replaceLineCharts(POIXMLDocumentPart poixmlDocumentPart,
                                             List<String> titleArr,
                                             List<String> fldNameArr,
                                             List<Map<String, String>> listItemsByType) {
    
            // 很重要的参数,图表系列的数量,由这里的数据决定
            int culomnNum = titleArr.size() - 1;
    
            XWPFChart chart = (XWPFChart) poixmlDocumentPart;
            chart.getCTChart();
    
            //根据属性第一列名称切换数据类型
            CTChart ctChart = chart.getCTChart();
            CTPlotArea plotArea = ctChart.getPlotArea();
    
            // 柱状图用plotArea.getBarChartArray,
            // 折线图用plotArea.getLineChartArray,
            // 饼图用plotArea.getPieChartArray.....
            // 还有很多其它的
            CTLineChart ctLineChart = plotArea.getLineChartArray(0);
    
            // 清除图表的样式,由代码自己设置
            ctLineChart.getSerList().clear();
    
            //刷新内置excel数据
            new PoiWordToolsDynamic().refreshExcel(chart, listItemsByType, fldNameArr, titleArr);
            //刷新页面显示数据-也就是刷新图表的数据源范围
            refreshLineStrGraphContent(ctLineChart, listItemsByType, fldNameArr, 1, culomnNum, titleArr);
        }
    
    
        /**
         * 动态添加列-柱状图的
         */
        public static boolean refreshBarStrGraphContent(CTBarChart barChart,
                                                        List<Map<String, String>> dataList,
                                                        List<String> fldNameArr,
                                                        int position,
                                                        int culomnNum,
                                                        List<String> titleArr) {
            boolean result = true;
            //更新数据区域
            for (int i = 0; i < culomnNum; i++) {
                CTBarSer ctBarSer = barChart.addNewSer();
                ctBarSer.addNewIdx().setVal(i);
                ctBarSer.addNewOrder().setVal(i);
    
                // 设置柱状图的系列名称
                // 设置标题 用以下这个方式,可以兼容office和wps(因为是动态添加,不可以直接get到,需要这样写)
                CTSerTx tx = ctBarSer.addNewTx();
                CTStrRef ctStrRef = tx.addNewStrRef();
                CTStrData ctStrData = ctStrRef.addNewStrCache();
                ctStrData.addNewPtCount().setVal(1);
                CTStrVal ctStrVal = ctStrData.addNewPt();
                ctStrVal.setIdx(0);
                ctStrVal.setV(titleArr.get(i + 1));  // 设置系列的名称
    
    
                // 设置柱状图系列的颜色,就是显示的柱子的颜色,不设置的话会默认都是黄色
                // 必须使用ACCENT_x系列的才行
                CTSchemeColor ctSchemeColor = ctBarSer.addNewSpPr().addNewSolidFill().addNewSchemeClr();
                ctSchemeColor.setVal(STSchemeColorValTools.get(i));
    
    
                CTAxDataSource cat = ctBarSer.addNewCat();
                CTNumDataSource val = ctBarSer.addNewVal();
    
                CTStrData strData = cat.addNewStrRef().addNewStrCache();
                CTNumData numData = val.addNewNumRef().addNewNumCache();
                strData.setPtArray((CTStrVal[]) null); // unset old axis text
                numData.setPtArray((CTNumVal[]) null); // unset old values
    
                // set model
                long idx = 0;
                for (int j = 0; j < dataList.size(); j++) {
                    //判断获取的值是否为空
                    String value = "0";
                    if (new BigDecimal(dataList.get(j).get(fldNameArr.get(i + position))) != null) {
                        value = new BigDecimal(dataList.get(j).get(fldNameArr.get(i + position))).toString();
                    }
                    if (!"0".equals(value)) {
                        CTNumVal numVal = numData.addNewPt();//序列值
                        numVal.setIdx(idx);
                        numVal.setV(value);
                    }
                    CTStrVal sVal = strData.addNewPt();//序列名称
                    sVal.setIdx(idx);
                    sVal.setV(dataList.get(j).get(fldNameArr.get(0)));
                    idx++;
                }
    
                numData.addNewPtCount().setVal(idx);
                strData.addNewPtCount().setVal(idx);
    
    
            }
            return result;
        }
    
    
        /**
         * 动态添加列-折线图的
         */
        public static boolean refreshLineStrGraphContent(CTLineChart ctLineChart,
                                                         List<Map<String, String>> dataList,
                                                         List<String> fldNameArr,
                                                         int position,
                                                         int culomnNum,
                                                         List<String> titleArr) {
            boolean result = true;
            //更新数据区域
            for (int i = 0; i < culomnNum; i++) {
                CTLineSer ctLineSer = ctLineChart.addNewSer();
                ctLineSer.addNewIdx().setVal(i);
                ctLineSer.addNewOrder().setVal(i);
    
                // 设置柱状图的系列名称
                // 设置标题 用以下这个方式,可以兼容office和wps(因为是动态添加,不可以直接get到,需要这样写)
                CTSerTx tx = ctLineSer.addNewTx();
                CTStrRef ctStrRef = tx.addNewStrRef();
                CTStrData ctStrData = ctStrRef.addNewStrCache();
                ctStrData.addNewPtCount().setVal(1);
                CTStrVal ctStrVal = ctStrData.addNewPt();
                ctStrVal.setIdx(0);
                ctStrVal.setV(titleArr.get(i + 1));  // 设置系列的名称
    
    
    
                // 设置柱状图系列的颜色,就是显示的柱子的颜色,不设置的话会默认都是黄色
                // 必须使用ACCENT_x系列的才行
                CTSchemeColor ctSchemeColor = ctLineSer.addNewSpPr().addNewLn().addNewSolidFill().addNewSchemeClr();
                ctSchemeColor.setVal(STSchemeColorValTools.get(i));
    
    
                CTAxDataSource cat = ctLineSer.addNewCat();
                CTNumDataSource val = ctLineSer.addNewVal();
    
                CTStrData strData = cat.addNewStrRef().addNewStrCache();
                CTNumData numData = val.addNewNumRef().addNewNumCache();
                strData.setPtArray((CTStrVal[]) null); // unset old axis text
                numData.setPtArray((CTNumVal[]) null); // unset old values
    
                // set model
                long idx = 0;
                for (int j = 0; j < dataList.size(); j++) {
                    //判断获取的值是否为空
                    String value = "0";
                    if (new BigDecimal(dataList.get(j).get(fldNameArr.get(i + position))) != null) {
                        value = new BigDecimal(dataList.get(j).get(fldNameArr.get(i + position))).toString();
                    }
                    if (!"0".equals(value)) {
                        CTNumVal numVal = numData.addNewPt();//序列值
                        numVal.setIdx(idx);
                        numVal.setV(value);
                    }
                    CTStrVal sVal = strData.addNewPt();//序列名称
                    sVal.setIdx(idx);
                    sVal.setV(dataList.get(j).get(fldNameArr.get(0)));
                    idx++;
                }
    
                numData.addNewPtCount().setVal(idx);
                strData.addNewPtCount().setVal(idx);
    
            }
            return result;
        }
    
    
        /**
         * 刷新内置excel数据
         *
         * @param chart
         * @param dataList
         * @param fldNameArr
         * @param titleArr
         * @return
         */
        public static boolean refreshExcel(XWPFChart chart,
                                           List<Map<String, String>> dataList, List<String> fldNameArr, List<String> titleArr) {
            boolean result = true;
            Workbook wb = new XSSFWorkbook();
            Sheet sheet = wb.createSheet("Sheet1");
            //根据数据创建excel第一行标题行
            for (int i = 0; i < titleArr.size(); i++) {
                if (sheet.getRow(0) == null) {
                    sheet.createRow(0).createCell(i).setCellValue(titleArr.get(i) == null ? "" : titleArr.get(i));
                } else {
                    sheet.getRow(0).createCell(i).setCellValue(titleArr.get(i) == null ? "" : titleArr.get(i));
                }
            }
    
            //遍历数据行
            for (int i = 0; i < dataList.size(); i++) {
                Map<String, String> baseFormMap = dataList.get(i);//数据行
                //fldNameArr字段属性
                for (int j = 0; j < fldNameArr.size(); j++) {
                    if (sheet.getRow(i + 1) == null) {
                        if (j == 0) {
                            try {
                                sheet.createRow(i + 1).createCell(j).setCellValue(baseFormMap.get(fldNameArr.get(j)) == null ? "" : baseFormMap.get(fldNameArr.get(j)));
                            } catch (Exception e) {
                                if (baseFormMap.get(fldNameArr.get(j)) == null) {
                                    sheet.createRow(i + 1).createCell(j).setCellValue("");
                                } else {
                                    sheet.createRow(i + 1).createCell(j).setCellValue(baseFormMap.get(fldNameArr.get(j)));
                                }
                            }
                        }
                    } else {
                        BigDecimal b = new BigDecimal(baseFormMap.get(fldNameArr.get(j)));
                        double value = 0d;
                        if (b != null) {
                            value = b.doubleValue();
                        }
                        if (value == 0) {
                            sheet.getRow(i + 1).createCell(j);
                        } else {
                            sheet.getRow(i + 1).createCell(j).setCellValue(b.doubleValue());
                        }
                    }
                }
    
            }
            // 更新嵌入的workbook
            POIXMLDocumentPart xlsPart = chart.getRelations().get(0);
            OutputStream xlsOut = xlsPart.getPackagePart().getOutputStream();
    
            try {
                wb.write(xlsOut);
                xlsOut.close();
            } catch (IOException e) {
                e.printStackTrace();
                result = false;
            } finally {
                if (wb != null) {
                    try {
                        wb.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                        result = false;
                    }
                }
            }
            return result;
        }
    
    }
    

    3:辅助类2

    package com.example.demo.util;
    
    import org.openxmlformats.schemas.drawingml.x2006.main.STSchemeColorVal;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 官方对于颜色的解释: http://poi.apache.org/apidocs/dev/org/apache/poi/sl/draw/binding/STSchemeColorVal.html
     */
    public final class STSchemeColorValTools {
        static List<STSchemeColorVal.Enum> colorEnum = new ArrayList<>();
    
        static {
    //        colorEnum.add(STSchemeColorVal.BG_1);
    //        colorEnum.add(STSchemeColorVal.BG_2);
    //        colorEnum.add(STSchemeColorVal.TX_1);
    //        colorEnum.add(STSchemeColorVal.TX_2);
            colorEnum.add(STSchemeColorVal.ACCENT_1);
            colorEnum.add(STSchemeColorVal.ACCENT_2);
            colorEnum.add(STSchemeColorVal.ACCENT_3);
            colorEnum.add(STSchemeColorVal.ACCENT_4);
            colorEnum.add(STSchemeColorVal.ACCENT_5);
            colorEnum.add(STSchemeColorVal.ACCENT_6);
    //        colorEnum.add(STSchemeColorVal.HLINK);
    //        colorEnum.add(STSchemeColorVal.FOL_HLINK);
    //        colorEnum.add(STSchemeColorVal.PH_CLR);
    //        colorEnum.add(STSchemeColorVal.DK_1);
    //        colorEnum.add(STSchemeColorVal.DK_2);
    //        colorEnum.add(STSchemeColorVal.LT_1);
    //        colorEnum.add(STSchemeColorVal.LT_2);
        }
    
        public static STSchemeColorVal.Enum get(int i){
            return colorEnum.get(i);
        }
    }
    
    
    

    4:模板

    5:结果

    6:如果要显示数字的话,直接在模板里面设置显示就好了

     

    2020-04-21:新增:表格进行合并单元格,横竖都行,两种方式(感谢刘老师)

    场景:在word中插入表格,并对表格进行合并,这里提供两种方式,分别对应两个类

    1:模板文档内容:

    2:类1

    package com.example.demo.example.table;
    
    import com.example.demo.util.PoiWordTools;
    import org.apache.poi.ooxml.POIXMLDocumentPart;
    import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
    import org.apache.poi.util.Units;
    import org.apache.poi.xwpf.usermodel.*;
    import org.apache.xmlbeans.XmlCursor;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHMerge;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTVMerge;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge;
    import org.springframework.util.StringUtils;
    
    import java.io.*;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     * 表格
     */
    public class Table {
    
        public static void main(String[] args) throws Exception {
    
            final String returnurl = "D:\\youxi\\jx\\table1.docx";  // 结果文件
            final String templateurl = "D:\\POI\\demo\\src\\main\\resources\\table1.docx";  // 模板文件
    
            InputStream is = new FileInputStream(new File(templateurl));
            XWPFDocument doc = new XWPFDocument(is);
    
            // 替换word模板数据
            replaceAll(doc);
    
            // 保存结果文件
            try {
                File file = new File(returnurl);
                if (file.exists()) {
                    file.delete();
                }
                FileOutputStream fos = new FileOutputStream(returnurl);
                doc.write(fos);
                fos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    
        /**
         * @Description: 替换段落和表格中
         */
        public static void replaceAll(XWPFDocument doc) throws Exception {
            doParagraphs(doc); // 处理段落文字数据,包括文字和表格、图片
        }
    
    
        /**
         * 处理段落文字
         *
         * @param doc
         * @throws InvalidFormatException
         * @throws FileNotFoundException
         * @throws IOException
         */
        public static void doParagraphs(XWPFDocument doc) throws Exception {
            /**----------------------------处理段落------------------------------------**/
            List<XWPFParagraph> paragraphList = doc.getParagraphs();
            if (paragraphList != null && paragraphList.size() > 0) {
                for (XWPFParagraph paragraph : paragraphList) {
                    List<XWPFRun> runs = paragraph.getRuns();
                    for (XWPFRun run : runs) {
                        String text = run.getText(0);
                        if (text != null) {
    
                            // 动态表格
                            if (text.contains("${table1}")) {
                                run.setText("", 0);
                                XmlCursor cursor = paragraph.getCTP().newCursor();
                                XWPFTable tableOne = doc.insertNewTbl(cursor);// ---这个是关键
    
    
                                // 设置表格宽度,第一行宽度就可以了,这个值的单位,目前我也还不清楚,还没来得及研究
                                tableOne.setWidth(8500);
    
                                // 表格第一行,对于每个列,必须使用createCell(),而不是getCell(),因为第一行嘛,肯定是属于创建的,没有create哪里来的get呢
                                XWPFTableRow tableOneRowOne = tableOne.getRow(0);//行
                                new PoiWordTools().setWordCellSelfStyle(tableOneRowOne.getCell(0), "微软雅黑", "9", 0, "left", "top", "#000000", "#B4C6E7", "10%", "序号");
                                new PoiWordTools().setWordCellSelfStyle(tableOneRowOne.createCell(), "微软雅黑", "9", 0, "left", "top", "#000000", "#B4C6E7", "45%", "公司名称(英文)");
                                new PoiWordTools().setWordCellSelfStyle(tableOneRowOne.createCell(), "微软雅黑", "9", 0, "left", "top", "#000000", "#B4C6E7", "45%", "公司名称(中文)");
    
                                for (int i = 0; i < 10; i ++) {
                                    // 表格第二行
                                    XWPFTableRow tableOneRowTwo = tableOne.createRow();//行
                                    new PoiWordTools().setWordCellSelfStyle(tableOneRowTwo.getCell(0), "微软雅黑", "9", 0, "left", "top", "#000000", "#ffffff", "10%", "一行一列");
                                    new PoiWordTools().setWordCellSelfStyle(tableOneRowTwo.getCell(1), "微软雅黑", "9", 0, "left", "top", "#000000", "#ffffff", "45%", "一行一列");
                                    new PoiWordTools().setWordCellSelfStyle(tableOneRowTwo.getCell(2), "微软雅黑", "9", 0, "left", "top", "#000000", "#ffffff", "45%", "一行一列");
                                }
    
    
                                // 横着合并单元格  -----------------------------
                                CTHMerge cthMergeStart = CTHMerge.Factory.newInstance();
                                cthMergeStart.setVal(STMerge.RESTART);
                                CTHMerge cthMergeEnd = CTHMerge.Factory.newInstance();
                                cthMergeEnd.setVal(STMerge.CONTINUE);
                                XWPFTableCell cell71 = tableOne.getRow(6).getCell(0);  // 第7行的第1列
                                XWPFTableCell cell72 = tableOne.getRow(6).getCell(1);  // 第7行的第2列
                                XWPFTableCell cell73 = tableOne.getRow(6).getCell(2);  // 第7行的第3列
    
                                cell71.getCTTc().getTcPr().setHMerge(cthMergeStart);
                                cell72.getCTTc().getTcPr().setHMerge(cthMergeEnd);
                                cell73.getCTTc().getTcPr().setHMerge(cthMergeEnd);
    
    
                                // 竖着合并单元格   -----------------------------
                                CTVMerge vmergeStart = CTVMerge.Factory.newInstance();
                                vmergeStart.setVal(STMerge.RESTART);
                                CTVMerge vmergeEnd = CTVMerge.Factory.newInstance();
                                vmergeEnd.setVal(STMerge.CONTINUE);
                                XWPFTableCell cell1 = tableOne.getRow(1).getCell(0);  // 第2行第1列  第1行是表头
                                XWPFTableCell cell2 = tableOne.getRow(2).getCell(0);  // 第3行第1列
                                XWPFTableCell cell3 = tableOne.getRow(3).getCell(0);  // 第4行第1列
                                XWPFTableCell cell4 = tableOne.getRow(4).getCell(0);  // 第5行第1列
    
    
                                cell1.getCTTc().getTcPr().setVMerge(vmergeStart);
                                cell2.getCTTc().getTcPr().setVMerge(vmergeEnd);
                                cell3.getCTTc().getTcPr().setVMerge(vmergeEnd);
                                cell4.getCTTc().getTcPr().setVMerge(vmergeEnd);
    
    
    
                                // .......
                            }
    
                        }
                    }
                }
            }
        }
    
    
    
    }
    
    

    3:类2

    package com.example.demo.example.table;
    
    import com.example.demo.util.PoiWordTools;
    import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
    import org.apache.poi.xwpf.usermodel.*;
    import org.apache.xmlbeans.XmlCursor;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHMerge;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTVMerge;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge;
    
    import java.io.*;
    import java.util.List;
    
    /**
     * 表格
     */
    public class Table2 {
    
        public static void main(String[] args) throws Exception {
    
            final String returnurl = "D:\\youxi\\jx\\table1.docx";  // 结果文件
            final String templateurl = "D:\\POI\\demo\\src\\main\\resources\\table2.docx";  // 模板文件
    
            InputStream is = new FileInputStream(new File(templateurl));
            XWPFDocument doc = new XWPFDocument(is);
    
            // 替换word模板数据
            replaceAll(doc);
    
            // 保存结果文件
            try {
                File file = new File(returnurl);
                if (file.exists()) {
                    file.delete();
                }
                FileOutputStream fos = new FileOutputStream(returnurl);
                doc.write(fos);
                fos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    
        /**
         * @Description: 替换段落和表格中
         */
        public static void replaceAll(XWPFDocument doc) throws Exception {
            doParagraphs(doc); // 处理段落文字数据,包括文字和表格、图片
        }
    
    
        /**
         * 处理段落文字
         *
         * @param doc
         * @throws InvalidFormatException
         * @throws FileNotFoundException
         * @throws IOException
         */
        public static void doParagraphs(XWPFDocument doc) throws Exception {
            /**----------------------------处理段落------------------------------------**/
            List<XWPFParagraph> paragraphList = doc.getParagraphs();
            if (paragraphList != null && paragraphList.size() > 0) {
                for (XWPFParagraph paragraph : paragraphList) {
                    List<XWPFRun> runs = paragraph.getRuns();
                    for (XWPFRun run : runs) {
                        String text = run.getText(0);
                        if (text != null) {
    
                            // 动态表格
                            if (text.contains("${table1}")) {
                                run.setText("", 0);
                                XmlCursor cursor = paragraph.getCTP().newCursor();
                                XWPFTable tableOne = doc.insertNewTbl(cursor);// ---这个是关键
    
    
                                // 设置表格宽度,第一行宽度就可以了,这个值的单位,目前我也还不清楚,还没来得及研究
                                tableOne.setWidth(8500);
    
                                // 表格第一行,对于每个列,必须使用createCell(),而不是getCell(),因为第一行嘛,肯定是属于创建的,没有create哪里来的get呢
                                XWPFTableRow tableOneRowOne = tableOne.getRow(0);//行
                                new PoiWordTools().setWordCellSelfStyle(tableOneRowOne.getCell(0), "微软雅黑", "9", 0, "left", "top", "#000000", "#B4C6E7", "10%", "序号");
                                new PoiWordTools().setWordCellSelfStyle(tableOneRowOne.createCell(), "微软雅黑", "9", 0, "left", "top", "#000000", "#B4C6E7", "45%", "公司名称(英文)");
                                new PoiWordTools().setWordCellSelfStyle(tableOneRowOne.createCell(), "微软雅黑", "9", 0, "left", "top", "#000000", "#B4C6E7", "45%", "公司名称(中文)");
    
                                for (int i = 0; i < 10; i ++) {
                                    // 表格第二行
                                    XWPFTableRow tableOneRowTwo = tableOne.createRow();//行
                                    new PoiWordTools().setWordCellSelfStyle(tableOneRowTwo.getCell(0), "微软雅黑", "9", 0, "left", "top", "#000000", "#ffffff", "10%", "一行一列");
                                    new PoiWordTools().setWordCellSelfStyle(tableOneRowTwo.getCell(1), "微软雅黑", "9", 0, "left", "top", "#000000", "#ffffff", "45%", "一行一列");
                                    new PoiWordTools().setWordCellSelfStyle(tableOneRowTwo.getCell(2), "微软雅黑", "9", 0, "left", "top", "#000000", "#ffffff", "45%", "一行一列");
                                }
    
    
                                // 横着合并单元格  -----------------------------
                                XWPFTableCell cell71 = tableOne.getRow(6).getCell(0);  // 第7行的第1列
                                XWPFTableCell cell72 = tableOne.getRow(6).getCell(1);  // 第7行的第2列
                                XWPFTableCell cell73 = tableOne.getRow(6).getCell(2);  // 第7行的第3列
    
                                cell71.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
                                cell72.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
                                cell73.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
    
    
                                // 竖着合并单元格  -----------------------------
                                XWPFTableCell cell1 = tableOne.getRow(1).getCell(0);  // 第2行第1列  第1行是表头
                                XWPFTableCell cell2 = tableOne.getRow(2).getCell(0);  // 第3行第1列
                                XWPFTableCell cell3 = tableOne.getRow(3).getCell(0);  // 第4行第1列
                                XWPFTableCell cell4 = tableOne.getRow(4).getCell(0);  // 第5行第1列
    
                                cell1.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART);
                                cell2.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE);
                                cell3.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE);
                                cell4.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE);
    
    
    
                                // .......
                            }
    
                        }
                    }
                }
            }
        }
    
    
    
    }
    
    

    4:结果:

    两种方式本质上是一样的!

     

    2020-04-23:解决问题:组合图页面显示的数据,跟第二列对应不上(感谢博友:吹古拉朽)

    事情是这样的,博客网友吹古拉朽说,组合图页面显示的数据,跟第二列对应不上,柱状图+折线图的图表,折线图会显示柱状图的数据,显示结果如下图:很明显是不对的;

     如果你已经运行过我的示例代码中的PoiDemoWordTable.java这个类,生成的第6个图表,就是这个;

    解决方案:在第六个图表对应的代码中,修改position参数的值,如图:这个参数代表数据下标,从0开始的。

     

     

    所以我这里改成3就好了。

     

    本文示例源代码:(码云地址)https://gitee.com/loverer/poi-demo

     

    展开全文
  • // 处理图表数据,柱状图、折线图、饼图啊之类的 } /** * 处理段落文字 * * @param doc * @throws InvalidFormatException * @throws FileNotFoundException * @throws IOException */ public ...

    本文参考地址:https://blog.csdn.net/u014427811/article/details/100771314
    在参考文章的基础上,增加了模板样例
    模板样例地址 百度网盘
    链接:https://pan.baidu.com/s/16qDvE2-V-tpX_bY8NNnepw
    提取码:yhbd
    这个必须引入poi4.0以上版本,以验证过
    完整pom.xml内容:

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.2.4.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.turing</groupId>
        <artifactId>report</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>report</name>
        <description>Demo project for Spring Boot</description>
    
        <properties>
            <java.version>1.8</java.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <scope>runtime</scope>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
            <!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi</artifactId>
                <version>4.1.0</version>
            </dependency>
    
            <!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi-ooxml</artifactId>
                <version>4.1.0</version>
            </dependency>
    
    
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
                <exclusions>
                    <exclusion>
                        <groupId>org.junit.vintage</groupId>
                        <artifactId>junit-vintage-engine</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>
    

    数据这块完全拷贝大哥的

    package com.turing.report.controller;
    
    import org.apache.poi.ooxml.POIXMLDocumentPart;
    import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
    import org.apache.poi.util.Units;
    import org.apache.poi.xwpf.usermodel.*;
    import org.apache.xmlbeans.XmlCursor;
    import org.springframework.util.StringUtils;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.io.*;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     * @author :MaWT
     * @date :Created in 2020/2/21 11:40
     * @description:
     * @modified By:
     * @version: $
     */
    @RestController
    public class ReportController {
    
    
    
        @GetMapping("export")
        public static void export() throws Exception {
    
            final String returnurl = "C:\\Users\\wangcan\\Desktop\\data\\reportTemplate-word.docx";  // 结果文件
    
            final String templateurl = "C:\\Users\\wangcan\\Desktop\\templates\\reportTemplate-word.docx";  // 模板文件
    
            InputStream is = new FileInputStream(new File(templateurl));
            XWPFDocument doc = new XWPFDocument(is);
    
            // 替换word模板数据
            replaceAll(doc);
    
            // 保存结果文件
            try {
                File file = new File(returnurl);
                if (file.exists()) {
                    file.delete();
                }
                FileOutputStream fos = new FileOutputStream(returnurl);
                doc.write(fos);
                fos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    
        /**
         * @Description: 替换段落和表格中
         */
        public static void replaceAll(XWPFDocument doc) throws InvalidFormatException, IOException {
            doParagraphs(doc); // 处理段落文字数据,包括文字和表格、图片
            doCharts(doc);  // 处理图表数据,柱状图、折线图、饼图啊之类的
        }
    
    
        /**
         * 处理段落文字
         *
         * @param doc
         * @throws InvalidFormatException
         * @throws FileNotFoundException
         * @throws IOException
         */
        public static void doParagraphs(XWPFDocument doc) throws InvalidFormatException, IOException {
    
            // 文本数据
            Map<String, String> textMap = new HashMap<String, String>();
            textMap.put("var", "我是被替换的文本内容");
    
            // 图片数据
            Map<String, String> imgMap = new HashMap<String, String>();
            imgMap.put("img", "E:\\idea\\timg.jpg");
    
    
            /**----------------------------处理段落------------------------------------**/
            List<XWPFParagraph> paragraphList = doc.getParagraphs();
            if (paragraphList != null && paragraphList.size() > 0) {
                for (XWPFParagraph paragraph : paragraphList) {
                    List<XWPFRun> runs = paragraph.getRuns();
                    for (XWPFRun run : runs) {
                        String text = run.getText(0);
                        if (text != null) {
    
                            // 替换文本信息
                            String tempText = text;
                         //   String key = tempText.replaceAll("\\{\\{", "").replaceAll("}}", "");
                            if (!StringUtils.isEmpty(textMap.get(text))) {
                                run.setText(textMap.get(text), 0);
                            }
    
                            // 替换图片内容 参考:https://blog.csdn.net/a909301740/article/details/84984445
                            String tempImgText = text;
                         //   String imgkey = tempImgText.replaceAll("\\{\\{@", "").replaceAll("}}", "");
                            if (!StringUtils.isEmpty(imgMap.get(text))) {
                                String imgPath = imgMap.get(text);
                                try {
                                    run.setText("", 0);
                                    run.addPicture(new FileInputStream(imgPath), Document.PICTURE_TYPE_PNG, "img.png", Units.toEMU(200), Units.toEMU(200));
    
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
    
                            // 动态表格
                            if (text.contains("table")) {
                                run.setText("", 0);
                                XmlCursor cursor = paragraph.getCTP().newCursor();
                                XWPFTable tableOne = doc.insertNewTbl(cursor);// ---这个是关键
    
                                // 设置表格宽度,第一行宽度就可以了,这个值的单位,目前我也还不清楚,还没来得及研究
                                tableOne.setWidth(8500);
    
                                // 表格第一行,对于每个列,必须使用createCell(),而不是getCell(),因为第一行嘛,肯定是属于创建的,没有create哪里来的get呢
                                XWPFTableRow tableOneRowOne = tableOne.getRow(0);//行
                                PoiWordTools.setWordCellSelfStyle(tableOneRowOne.getCell(0), "微软雅黑", "9", 0, "left", "top", "#000000", "#B4C6E7", "10%", "序号");
                                PoiWordTools.setWordCellSelfStyle(tableOneRowOne.createCell(), "微软雅黑", "9", 0, "left", "top", "#000000", "#B4C6E7", "45%", "公司名称(英文)");
                                PoiWordTools.setWordCellSelfStyle(tableOneRowOne.createCell(), "微软雅黑", "9", 0, "left", "top", "#000000", "#B4C6E7", "45%", "公司名称(中文)");
    
                                // 表格第二行
                                XWPFTableRow tableOneRowTwo = tableOne.createRow();//行
                                PoiWordTools.setWordCellSelfStyle(tableOneRowTwo.getCell(0), "微软雅黑", "9", 0, "left", "top", "#000000", "#B4C6E7", "10%", "一行一列");
                                PoiWordTools.setWordCellSelfStyle(tableOneRowTwo.getCell(1), "微软雅黑", "9", 0, "left", "top", "#000000", "#B4C6E7", "45%", "一行一列");
                                PoiWordTools.setWordCellSelfStyle(tableOneRowTwo.getCell(2), "微软雅黑", "9", 0, "left", "top", "#000000", "#B4C6E7", "45%", "一行一列");
    
    
                                // ....... 可动态添加表格
                            }
                        }
                    }
                }
            }
        }
    
    
        /**
         * 处理图表
         *
         * @param doc
         * @throws FileNotFoundException
         */
        public static void doCharts(XWPFDocument doc) throws FileNotFoundException {
            /**----------------------------处理图表------------------------------------**/
    
            // 数据准备
            List<String> titleArr = new ArrayList<String>();// 标题
            titleArr.add("title");
            titleArr.add("金额");
    
            List<String> fldNameArr = new ArrayList<String>();// 字段名
            fldNameArr.add("item1");
            fldNameArr.add("item2");
    
            // 数据集合
            List<Map<String, String>> listItemsByType = new ArrayList<Map<String, String>>();
    
            // 第一行数据
            Map<String, String> base1 = new HashMap<String, String>();
            base1.put("item1", "材料费用");
            base1.put("item2", "500");
    
            // 第二行数据
            Map<String, String> base2 = new HashMap<String, String>();
            base2.put("item1", "出差费用");
            base2.put("item2", "300");
    
            // 第三行数据
            Map<String, String> base3 = new HashMap<String, String>();
            base3.put("item1", "住宿费用");
            base3.put("item2", "300");
    
            listItemsByType.add(base1);
            listItemsByType.add(base2);
            listItemsByType.add(base3);
    
    
            // 获取word模板中的所有图表元素,用map存放
            // 为什么不用list保存:查看doc.getRelations()的源码可知,源码中使用了hashMap读取文档图表元素,
            // 对relations变量进行打印后发现,图表顺序和文档中的顺序不一致,也就是说relations的图表顺序不是文档中从上到下的顺序
            Map<String, POIXMLDocumentPart> chartsMap = new HashMap<String, POIXMLDocumentPart>();
            //动态刷新图表
            List<POIXMLDocumentPart> relations = doc.getRelations();
            for (POIXMLDocumentPart poixmlDocumentPart : relations) {
                if (poixmlDocumentPart instanceof XWPFChart) {  // 如果是图表元素
                    String str = poixmlDocumentPart.toString();
                    System.out.println("str:" + str);
                    String key = str.replaceAll("Name: ", "")
                        .replaceAll(" - Content Type: application/vnd\\.openxmlformats-officedocument\\.drawingml\\.chart\\+xml", "").trim();
                    System.out.println("key:" + key);
    
                    chartsMap.put(key, poixmlDocumentPart);
                }
            }
    
            System.out.println("\n图表数量:" + chartsMap.size() + "\n");
    
    
            // 第一个图表-条形图
            POIXMLDocumentPart poixmlDocumentPart0 = chartsMap.get("/word/charts/chart1.xml");
            PoiWordTools.replaceBarCharts(poixmlDocumentPart0, titleArr, fldNameArr, listItemsByType);
    
            // 第二个-柱状图
            POIXMLDocumentPart poixmlDocumentPart1 = chartsMap.get("/word/charts/chart2.xml");
            PoiWordTools.replaceBarCharts(poixmlDocumentPart1, titleArr, fldNameArr, listItemsByType);
    
            // 第三个图表-多列柱状图
            doCharts3(chartsMap);
    
            // 第四个图表-折线图
            doCharts4(chartsMap);
    
            // 第五个图表-饼图
            POIXMLDocumentPart poixmlDocumentPart4 = chartsMap.get("/word/charts/chart5.xml");
            PoiWordTools.replacePieCharts(poixmlDocumentPart4, titleArr, fldNameArr, listItemsByType);
    
    
            doCharts6(chartsMap);
        }
    
    
        public static void doCharts3(Map<String, POIXMLDocumentPart> chartsMap) {
            // 数据准备
            List<String> titleArr = new ArrayList<String>();// 标题
            titleArr.add("姓名");
            titleArr.add("欠款");
            titleArr.add("存款");
    
            List<String> fldNameArr = new ArrayList<String>();// 字段名
            fldNameArr.add("item1");
            fldNameArr.add("item2");
            fldNameArr.add("item3");
    
            // 数据集合
            List<Map<String, String>> listItemsByType = new ArrayList<Map<String, String>>();
    
            // 第一行数据
            Map<String, String> base1 = new HashMap<String, String>();
            base1.put("item1", "老张");
            base1.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base1.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            // 第二行数据
            Map<String, String> base2 = new HashMap<String, String>();
            base2.put("item1", "老李");
            base2.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base2.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            // 第三行数据
            Map<String, String> base3 = new HashMap<String, String>();
            base3.put("item1", "老刘");
            base3.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base3.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
    
            listItemsByType.add(base1);
            listItemsByType.add(base2);
            listItemsByType.add(base3);
    
            POIXMLDocumentPart poixmlDocumentPart2 = chartsMap.get("/word/charts/chart3.xml");
            PoiWordTools.replaceBarCharts(poixmlDocumentPart2, titleArr, fldNameArr, listItemsByType);
        }
    
    
    
        public static void doCharts4(Map<String, POIXMLDocumentPart> chartsMap) {
            // 数据准备
            List<String> titleArr = new ArrayList<String>();// 标题
            titleArr.add("title");
            titleArr.add("占基金资产净值比例22222(%)");
            titleArr.add("额外的(%)");
            titleArr.add("额外的(%)");
    
            List<String> fldNameArr = new ArrayList<String>();// 字段名
            fldNameArr.add("item1");
            fldNameArr.add("item2");
            fldNameArr.add("item3");
            fldNameArr.add("item4");
    
            // 数据集合
            List<Map<String, String>> listItemsByType = new ArrayList<Map<String, String>>();
    
            // 第一行数据
            Map<String, String> base1 = new HashMap<String, String>();
            base1.put("item1", "材料费用");
            base1.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base1.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base1.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            // 第二行数据
            Map<String, String> base2 = new HashMap<String, String>();
            base2.put("item1", "出差费用");
            base2.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base2.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base2.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            // 第三行数据
            Map<String, String> base3 = new HashMap<String, String>();
            base3.put("item1", "住宿费用");
            base3.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base3.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base3.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
    
            listItemsByType.add(base1);
            listItemsByType.add(base2);
            listItemsByType.add(base3);
    
            POIXMLDocumentPart poixmlDocumentPart2 = chartsMap.get("/word/charts/chart4.xml");
            PoiWordTools.replaceLineCharts(poixmlDocumentPart2, titleArr, fldNameArr, listItemsByType);
        }
    
    
        /**
         * 对应文档中的第6个图表(预处理—分公司情况)
         */
        public static void doCharts6(Map<String, POIXMLDocumentPart> chartsMap) {
            // 数据准备
            List<String> titleArr = new ArrayList<String>();// 标题
            titleArr.add("title");
            titleArr.add("投诉受理量(次)");
            titleArr.add("预处理拦截工单量(次)");
            titleArr.add("拦截率");
    
            List<String> fldNameArr = new ArrayList<String>();// 字段名
            fldNameArr.add("item1");
            fldNameArr.add("item2");
            fldNameArr.add("item3");
            fldNameArr.add("item4");
    
            // 数据集合
            List<Map<String, String>> listItemsByType = new ArrayList<Map<String, String>>();
    
            // 第一行数据
            Map<String, String> base1 = new HashMap<String, String>();
            base1.put("item1", "通辽");
            base1.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base1.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base1.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            // 第二行数据
            Map<String, String> base2 = new HashMap<String, String>();
            base2.put("item1", "呼和浩特");
            base2.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base2.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base2.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            // 第三行数据
            Map<String, String> base3 = new HashMap<String, String>();
            base3.put("item1", "锡林郭勒");
            base3.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base3.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base3.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            // 第四行数据
            Map<String, String> base4 = new HashMap<String, String>();
            base4.put("item1", "阿拉善");
            base4.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base4.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base4.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            // 第五行数据
            Map<String, String> base5 = new HashMap<String, String>();
            base5.put("item1", "巴彦淖尔");
            base5.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base5.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base5.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            // 第六行数据
            Map<String, String> base6 = new HashMap<String, String>();
            base6.put("item1", "兴安");
            base6.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base6.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base6.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            // 第七行数据
            Map<String, String> base7 = new HashMap<String, String>();
            base7.put("item1", "乌兰察布");
            base7.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base7.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base7.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            // 第八行数据
            Map<String, String> base8 = new HashMap<String, String>();
            base8.put("item1", "乌海");
            base8.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base8.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base8.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            // 第九行数据
            Map<String, String> base9 = new HashMap<String, String>();
            base9.put("item1", "赤峰");
            base9.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base9.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base9.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            // 第十行数据
            Map<String, String> base10 = new HashMap<String, String>();
            base10.put("item1", "包头");
            base10.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base10.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base10.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            // 第十一行数据
            Map<String, String> base11 = new HashMap<String, String>();
            base11.put("item1", "呼伦贝尔");
            base11.put("item2", (int)(int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base11.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base11.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            // 第十二行数据
            Map<String, String> base12 = new HashMap<String, String>();
            base12.put("item1", "鄂尔多斯");
            base12.put("item2", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base12.put("item3", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
            base12.put("item4", (int)(1 + Math.random() * (100 - 1 + 1)) + "");
    
            listItemsByType.add(base1);
            listItemsByType.add(base2);
            listItemsByType.add(base3);
            listItemsByType.add(base4);
            listItemsByType.add(base5);
            listItemsByType.add(base6);
            listItemsByType.add(base7);
            listItemsByType.add(base8);
            listItemsByType.add(base9);
            listItemsByType.add(base10);
            listItemsByType.add(base11);
            listItemsByType.add(base12);
    
            // 下标0的图表-折线图
            POIXMLDocumentPart poixmlDocumentPart5 = chartsMap.get("/word/charts/chart6.xml");
            PoiWordTools.replaceCombinationCharts(poixmlDocumentPart5, titleArr, fldNameArr, listItemsByType);
        }
    
    
    }
    
    

    工具类也是参考的加上游客的意见

    package com.turing.report.controller;
    
    import org.apache.poi.ooxml.POIXMLDocumentPart;
    import org.apache.poi.ss.usermodel.Sheet;
    import org.apache.poi.ss.usermodel.Workbook;
    import org.apache.poi.ss.util.CellRangeAddress;
    import org.apache.poi.xssf.usermodel.XSSFWorkbook;
    import org.apache.poi.xwpf.usermodel.XWPFChart;
    import org.apache.poi.xwpf.usermodel.XWPFTableCell;
    import org.openxmlformats.schemas.drawingml.x2006.chart.*;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
    import org.springframework.stereotype.Component;
    
    import java.io.IOException;
    import java.io.OutputStream;
    import java.math.BigDecimal;
    import java.math.BigInteger;
    import java.util.List;
    import java.util.Map;
    
    
    
    /**
     * poi生成word的工具类
     */
    @Component
    public class PoiWordTools {
     
        private static final BigDecimal bd2 = new BigDecimal("2");
     
     
        /**
         * 调用替换柱状图数据
         */
        public static void replaceBarCharts(POIXMLDocumentPart poixmlDocumentPart,
                                            List<String> titleArr, List<String> fldNameArr, List<Map<String, String>> listItemsByType) {
            XWPFChart chart = (XWPFChart) poixmlDocumentPart;
            chart.getCTChart();
     
            //根据属性第一列名称切换数据类型
            CTChart ctChart = chart.getCTChart();
            CTPlotArea plotArea = ctChart.getPlotArea();
     
            CTBarChart barChart = plotArea.getBarChartArray(0);
            List<CTBarSer> BarSerList = barChart.getSerList();  // 获取柱状图单位
     
            //刷新内置excel数据
           refreshExcel(chart, listItemsByType, fldNameArr, titleArr);
            //刷新页面显示数据
            refreshBarStrGraphContent(barChart, BarSerList, listItemsByType, fldNameArr, 1);
     
        }
     
     
        /**
         * 调用替换折线图数据
         */
        public static void replaceLineCharts(POIXMLDocumentPart poixmlDocumentPart,
                                             List<String> titleArr, List<String> fldNameArr, List<Map<String, String>> listItemsByType) {
            XWPFChart chart = (XWPFChart) poixmlDocumentPart;
            chart.getCTChart();
     
            //根据属性第一列名称切换数据类型
            CTChart ctChart = chart.getCTChart();
            CTPlotArea plotArea = ctChart.getPlotArea();
     
            CTLineChart lineChart = plotArea.getLineChartArray(0);
            List<CTLineSer> lineSerList = lineChart.getSerList();   // 获取折线图单位
     
            //刷新内置excel数据
            refreshExcel(chart, listItemsByType, fldNameArr, titleArr);
            //刷新页面显示数据
            refreshLineStrGraphContent(lineChart, lineSerList, listItemsByType, fldNameArr, 1);
     
        }
     
     
        /**
         * 调用替换饼图数据
         */
        public static void replacePieCharts(POIXMLDocumentPart poixmlDocumentPart,
                                            List<String> titleArr, List<String> fldNameArr, List<Map<String, String>> listItemsByType) {
            XWPFChart chart = (XWPFChart) poixmlDocumentPart;
            chart.getCTChart();
     
            //根据属性第一列名称切换数据类型
            CTChart ctChart = chart.getCTChart();
            CTPlotArea plotArea = ctChart.getPlotArea();
     
            CTPieChart pieChart = plotArea.getPieChartArray(0);
            List<CTPieSer> pieSerList = pieChart.getSerList();  // 获取饼图单位
     
            //刷新内置excel数据
            refreshExcel(chart, listItemsByType, fldNameArr, titleArr);
            //刷新页面显示数据
            refreshPieStrGraphContent(pieChart, pieSerList, listItemsByType, fldNameArr, 1);
     
        }
     
     
        /**
         * 调用替换柱状图、折线图组合数据
         */
        public static void replaceCombinationCharts(POIXMLDocumentPart poixmlDocumentPart,
                                                    List<String> titleArr, List<String> fldNameArr, List<Map<String, String>> listItemsByType) {
            XWPFChart chart = (XWPFChart) poixmlDocumentPart;
            chart.getCTChart();
     
            //根据属性第一列名称切换数据类型
            CTChart ctChart = chart.getCTChart();
            CTPlotArea plotArea = ctChart.getPlotArea();
     
            CTBarChart barChart = plotArea.getBarChartArray(0);
            List<CTBarSer> barSerList = barChart.getSerList();  // 获取柱状图单位
            //刷新内置excel数据
            refreshExcel(chart, listItemsByType, fldNameArr, titleArr);
            //刷新页面显示数据
            refreshBarStrGraphContent(barChart, barSerList, listItemsByType, fldNameArr, 1);
     
     
            CTBarChart barChart2 = plotArea.getBarChartArray(0);
            List<CTBarSer> barSerList2 = barChart2.getSerList();  // 获取柱状图单位
            //刷新内置excel数据
            refreshExcel(chart, listItemsByType, fldNameArr, titleArr);
            //刷新页面显示数据
            refreshBarStrGraphContent(barChart2, barSerList2, listItemsByType, fldNameArr, 1);
     
     
            CTLineChart lineChart = plotArea.getLineChartArray(0);
            List<CTLineSer> lineSerList = lineChart.getSerList();   // 获取折线图单位
            //刷新内置excel数据
            refreshExcel(chart, listItemsByType, fldNameArr, titleArr);
            //刷新页面显示数据
            refreshLineStrGraphContent(lineChart, lineSerList, listItemsByType, fldNameArr, 1);
     
        }
     
     
        /**
         * 刷新折线图数据方法
         *
         * @param typeChart
         * @param serList
         * @param dataList
         * @param fldNameArr
         * @param position
         * @return
         */
        public static boolean refreshLineStrGraphContent(Object typeChart,
                                                         List<?> serList, List<Map<String, String>> dataList, List<String> fldNameArr, int position) {
     
            boolean result = true;
            //更新数据区域
            for (int i = 0; i < serList.size(); i++) {
                //CTSerTx tx=null;
                CTAxDataSource cat = null;
                CTNumDataSource val = null;
                CTLineSer ser = ((CTLineChart) typeChart).getSerArray(i);
                //tx= ser.getTx();
                // Category Axis Data
                cat = ser.getCat();
                // 获取图表的值
                val = ser.getVal();
                // strData.set
                CTStrData strData = cat.getStrRef().getStrCache();
                CTNumData numData = val.getNumRef().getNumCache();
                strData.setPtArray((CTStrVal[]) null); // unset old axis text
                numData.setPtArray((CTNumVal[]) null); // unset old values
     
                // set model
                long idx = 0;
                for (int j = 0; j < dataList.size(); j++) {
                    //判断获取的值是否为空
                    String value = "0";
                    if (new BigDecimal(dataList.get(j).get(fldNameArr.get(i + position))) != null) {
                        value = new BigDecimal(dataList.get(j).get(fldNameArr.get(i + position))).toString();
                    }
                    if (!"0".equals(value)) {
                        CTNumVal numVal = numData.addNewPt();//序列值
                        numVal.setIdx(idx);
                        numVal.setV(value);
                    }
                    CTStrVal sVal = strData.addNewPt();//序列名称
                    sVal.setIdx(idx);
                    sVal.setV(dataList.get(j).get(fldNameArr.get(0)));
                    idx++;
                }
                numData.getPtCount().setVal(idx);
                strData.getPtCount().setVal(idx);
     
     
                //赋值横坐标数据区域
                String axisDataRange = new CellRangeAddress(1, dataList.size(), 0, 0)
                        .formatAsString("Sheet1", false);
                cat.getStrRef().setF(axisDataRange);
     
                //数据区域
                String numDataRange = new CellRangeAddress(1, dataList.size(), i + position, i + position)
                        .formatAsString("Sheet1", false);
                val.getNumRef().setF(numDataRange);
     
                // 设置系列生成方向
     
     
            }
            return result;
        }
     
     
        /**
         * 刷新柱状图数据方法
         *
         * @param typeChart
         * @param serList
         * @param dataList
         * @param fldNameArr
         * @param position
         * @return
         */
        public  static boolean refreshBarStrGraphContent(Object typeChart,
                                                        List<?> serList, List<Map<String, String>> dataList, List<String> fldNameArr, int position) {
            boolean result = true;
            //更新数据区域
            for (int i = 0; i < serList.size(); i++) {
                //CTSerTx tx=null;
                CTAxDataSource cat = null;
                CTNumDataSource val = null;
                CTBarSer ser = ((CTBarChart) typeChart).getSerArray(i);
                //tx= ser.getTx();
                // Category Axis Data
                cat = ser.getCat();
                // 获取图表的值
                val = ser.getVal();
                // strData.set
                CTStrData strData = cat.getStrRef().getStrCache();
                CTNumData numData = val.getNumRef().getNumCache();
                strData.setPtArray((CTStrVal[]) null); // unset old axis text
                numData.setPtArray((CTNumVal[]) null); // unset old values
     
                // set model
                long idx = 0;
                for (int j = 0; j < dataList.size(); j++) {
                    //判断获取的值是否为空
                    String value = "0";
    
                    if (new BigDecimal(dataList.get(j).get(fldNameArr.get(i+position))) != null) {
                        value = new BigDecimal(dataList.get(j).get(fldNameArr.get(i + position))).toString();
                    }
                    if (!"0".equals(value)) {
                        CTNumVal numVal = numData.addNewPt();//序列值
                        numVal.setIdx(idx);
                        numVal.setV(value);
                    }
                    CTStrVal sVal = strData.addNewPt();//序列名称
                    sVal.setIdx(idx);
                    sVal.setV(dataList.get(j).get(fldNameArr.get(0)));
                    idx++;
                }
                numData.getPtCount().setVal(idx);
                strData.getPtCount().setVal(idx);
     
     
                //赋值横坐标数据区域
                String axisDataRange = new CellRangeAddress(1, dataList.size(), 0, 0)
                        .formatAsString("Sheet1", true);
                cat.getStrRef().setF(axisDataRange);
     
                //数据区域
                String numDataRange = new CellRangeAddress(1, dataList.size(), i + position, i + position)
                        .formatAsString("Sheet1", true);
                val.getNumRef().setF(numDataRange);
     
            }
            return result;
        }
     
     
     
        /**
         * 刷新饼图数据方法
         *
         * @param typeChart
         * @param serList
         * @param dataList
         * @param fldNameArr
         * @param position
         * @return
         */
        public static boolean refreshPieStrGraphContent(Object typeChart,
                                                        List<?> serList, List<Map<String, String>> dataList, List<String> fldNameArr, int position) {
     
            boolean result = true;
            //更新数据区域
            for (int i = 0; i < serList.size(); i++) {
                //CTSerTx tx=null;
                CTAxDataSource cat = null;
                CTNumDataSource val = null;
                CTPieSer ser = ((CTPieChart) typeChart).getSerArray(i);
     
                //tx= ser.getTx();
                // Category Axis Data
                cat = ser.getCat();
                // 获取图表的值
                val = ser.getVal();
                // strData.set
                CTStrData strData = cat.getStrRef().getStrCache();
                CTNumData numData = val.getNumRef().getNumCache();
                strData.setPtArray((CTStrVal[]) null); // unset old axis text
                numData.setPtArray((CTNumVal[]) null); // unset old values
     
                // set model
                long idx = 0;
                for (int j = 0; j < dataList.size(); j++) {
                    //判断获取的值是否为空
                    String value = "0";
                    if (new BigDecimal(dataList.get(j).get(fldNameArr.get(i + position))) != null) {
                        value = new BigDecimal(dataList.get(j).get(fldNameArr.get(i + position))).toString();
                    }
                    if (!"0".equals(value)) {
                        CTNumVal numVal = numData.addNewPt();//序列值
                        numVal.setIdx(idx);
                        numVal.setV(value);
                    }
                    CTStrVal sVal = strData.addNewPt();//序列名称
                    sVal.setIdx(idx);
                    sVal.setV(dataList.get(j).get(fldNameArr.get(0)));
                    idx++;
                }
                numData.getPtCount().setVal(idx);
                strData.getPtCount().setVal(idx);
     
     
                //赋值横坐标数据区域
                String axisDataRange = new CellRangeAddress(1, dataList.size(), 0, 0)
                        .formatAsString("Sheet1", true);
                cat.getStrRef().setF(axisDataRange);
     
                //数据区域
                String numDataRange = new CellRangeAddress(1, dataList.size(), i + position, i + position)
                        .formatAsString("Sheet1", true);
                val.getNumRef().setF(numDataRange);
            }
            return result;
        }
     
     
        /**
         * 刷新内置excel数据
         *
         * @param chart
         * @param dataList
         * @param fldNameArr
         * @param titleArr
         * @return
         */
        public static boolean refreshExcel(XWPFChart chart,
                                           List<Map<String, String>> dataList, List<String> fldNameArr, List<String> titleArr) {
            boolean result = true;
            Workbook wb = new XSSFWorkbook();
            Sheet sheet = wb.createSheet("Sheet1");
            //根据数据创建excel第一行标题行
            for (int i = 0; i < titleArr.size(); i++) {
                if (sheet.getRow(0) == null) {
                    sheet.createRow(0).createCell(i).setCellValue(titleArr.get(i) == null ? "" : titleArr.get(i));
                } else {
                    sheet.getRow(0).createCell(i).setCellValue(titleArr.get(i) == null ? "" : titleArr.get(i));
                }
            }
     
            //遍历数据行
            for (int i = 0; i < dataList.size(); i++) {
                Map<String, String> baseFormMap = dataList.get(i);//数据行
                //fldNameArr字段属性
                for (int j = 0; j < fldNameArr.size(); j++) {
                    if (sheet.getRow(i + 1) == null) {
                        if (j == 0) {
                            try {
                                sheet.createRow(i + 1).createCell(j).setCellValue(baseFormMap.get(fldNameArr.get(j)) == null ? "" : baseFormMap.get(fldNameArr.get(j)));
                            } catch (Exception e) {
                                if (baseFormMap.get(fldNameArr.get(j)) == null) {
                                    sheet.createRow(i + 1).createCell(j).setCellValue("");
                                } else {
                                    sheet.createRow(i + 1).createCell(j).setCellValue(baseFormMap.get(fldNameArr.get(j)));
                                }
                            }
                        }
                    } else {
                        BigDecimal b = new BigDecimal(baseFormMap.get(fldNameArr.get(j)));
                        double value = 0d;
                        if (b != null) {
                            value = b.doubleValue();
                        }
                        if (value == 0) {
                            sheet.getRow(i + 1).createCell(j);
                        } else {
                            sheet.getRow(i + 1).createCell(j).setCellValue(b.doubleValue());
                        }
                    }
                }
     
            }
            // 更新嵌入的workbook
    
            List<POIXMLDocumentPart> pxdList = chart.getRelations();
            if(pxdList!=null&&pxdList.size()>0){
                for(int i = 0;i<pxdList.size();i++){
                    if(pxdList.get(i).toString().contains("sheet")){//判断为sheet再去进行更新表格数据
                        POIXMLDocumentPart xlsPart =  pxdList.get(i);
                        OutputStream xlsOut = xlsPart.getPackagePart().getOutputStream();
    
                        try {
                            wb.write(xlsOut);
                            xlsOut.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                            result = false;
                        } finally {
                            if (wb != null) {
                                try {
                                    wb.close();
                                } catch (IOException e) {
                                    e.printStackTrace();
                                    result = false;
                                }
                            }
                        }
                        break;
                    }
                }
            }
            return result;
        }
     
     
        /**
         * 设置表格样式
         *
         * @param cell
         * @param fontName
         * @param fontSize
         * @param fontBlod
         * @param alignment
         * @param vertical
         * @param fontColor
         * @param bgColor
         * @param cellWidth
         * @param content
         */
        public static void setWordCellSelfStyle(XWPFTableCell cell, String fontName, String fontSize, int fontBlod,
                                                String alignment, String vertical, String fontColor,
                                                String bgColor, String cellWidth, String content) {
     
            //poi对字体大小设置特殊,不支持小数,但对原word字体大小做了乘2处理
            BigInteger bFontSize = new BigInteger("24");
            if (fontSize != null && !fontSize.equals("")) {
                //poi对字体大小设置特殊,不支持小数,但对原word字体大小做了乘2处理
                BigDecimal fontSizeBD = new BigDecimal(fontSize);
                fontSizeBD = bd2.multiply(fontSizeBD);
                fontSizeBD = fontSizeBD.setScale(0, BigDecimal.ROUND_HALF_UP);//这里取整
                bFontSize = new BigInteger(fontSizeBD.toString());// 字体大小
            }
     
            // 设置单元格宽度
            cell.setWidth(cellWidth);
     
            //=====获取单元格
            CTTc tc = cell.getCTTc();
            //====tcPr开始====》》》》
            CTTcPr tcPr = tc.getTcPr();//获取单元格里的<w:tcPr>
            if (tcPr == null) {//没有<w:tcPr>,创建
                tcPr = tc.addNewTcPr();
            }
     
            //  --vjc开始-->>
            CTVerticalJc vjc = tcPr.getVAlign();//获取<w:tcPr>  的<w:vAlign w:val="center"/>
            if (vjc == null) {//没有<w:w:vAlign/>,创建
                vjc = tcPr.addNewVAlign();
            }
            //设置单元格对齐方式
            vjc.setVal(vertical.equals("top") ? STVerticalJc.TOP : vertical.equals("bottom") ? STVerticalJc.BOTTOM : STVerticalJc.CENTER); //垂直对齐
     
            CTShd shd = tcPr.getShd();//获取<w:tcPr>里的<w:shd w:val="clear" w:color="auto" w:fill="C00000"/>
            if (shd == null) {//没有<w:shd>,创建
                shd = tcPr.addNewShd();
            }
            // 设置背景颜色
            shd.setFill(bgColor.substring(1));
            //《《《《====tcPr结束====
     
            //====p开始====》》》》
            CTP p = tc.getPList().get(0);//获取单元格里的<w:p w:rsidR="00C36068" w:rsidRPr="00B705A0" w:rsidRDefault="00C36068" w:rsidP="00C36068">
     
            //---ppr开始--->>>
            CTPPr ppr = p.getPPr();//获取<w:p>里的<w:pPr>
            if (ppr == null) {//没有<w:pPr>,创建
                ppr = p.addNewPPr();
            }
            //  --jc开始-->>
            CTJc jc = ppr.getJc();//获取<w:pPr>里的<w:jc w:val="left"/>
            if (jc == null) {//没有<w:jc/>,创建
                jc = ppr.addNewJc();
            }
            //设置单元格对齐方式
            jc.setVal(alignment.equals("left") ? STJc.LEFT : alignment.equals("right") ? STJc.RIGHT : STJc.CENTER); //水平对齐
            //  <<--jc结束--
            //  --pRpr开始-->>
            CTParaRPr pRpr = ppr.getRPr(); //获取<w:pPr>里的<w:rPr>
            if (pRpr == null) {//没有<w:rPr>,创建
                pRpr = ppr.addNewRPr();
            }
            CTFonts pfont = pRpr.getRFonts();//获取<w:rPr>里的<w:rFonts w:ascii="宋体" w:eastAsia="宋体" w:hAnsi="宋体"/>
            if (pfont == null) {//没有<w:rPr>,创建
                pfont = pRpr.addNewRFonts();
            }
            //设置字体
            pfont.setAscii(fontName);
            pfont.setEastAsia(fontName);
            pfont.setHAnsi(fontName);
     
            CTOnOff pb = pRpr.getB();//获取<w:rPr>里的<w:b/>
            if (pb == null) {//没有<w:b/>,创建
                pb = pRpr.addNewB();
            }
            //设置字体是否加粗
            pb.setVal(fontBlod == 1 ? STOnOff.ON : STOnOff.OFF);
     
            CTHpsMeasure psz = pRpr.getSz();//获取<w:rPr>里的<w:sz w:val="32"/>
            if (psz == null) {//没有<w:sz w:val="32"/>,创建
                psz = pRpr.addNewSz();
            }
            // 设置单元格字体大小
            psz.setVal(bFontSize);
            CTHpsMeasure pszCs = pRpr.getSzCs();//获取<w:rPr>里的<w:szCs w:val="32"/>
            if (pszCs == null) {//没有<w:szCs w:val="32"/>,创建
                pszCs = pRpr.addNewSzCs();
            }
            // 设置单元格字体大小
            pszCs.setVal(bFontSize);
            //  <<--pRpr结束--
            //<<<---ppr结束---
     
            //---r开始--->>>
            List<CTR> rlist = p.getRList(); //获取<w:p>里的<w:r w:rsidRPr="00B705A0">
            CTR r = null;
            if (rlist != null && rlist.size() > 0) {//获取第一个<w:r>
                r = rlist.get(0);
            } else {//没有<w:r>,创建
                r = p.addNewR();
            }
            //--rpr开始-->>
            CTRPr rpr = r.getRPr();//获取<w:r w:rsidRPr="00B705A0">里的<w:rPr>
            if (rpr == null) {//没有<w:rPr>,创建
                rpr = r.addNewRPr();
            }
            //->-
            CTFonts font = rpr.getRFonts();//获取<w:rPr>里的<w:rFonts w:ascii="宋体" w:eastAsia="宋体" w:hAnsi="宋体" w:hint="eastAsia"/>
            if (font == null) {//没有<w:rFonts>,创建
                font = rpr.addNewRFonts();
            }
            //设置字体
            font.setAscii(fontName);
            font.setEastAsia(fontName);
            font.setHAnsi(fontName);
     
            CTOnOff b = rpr.getB();//获取<w:rPr>里的<w:b/>
            if (b == null) {//没有<w:b/>,创建
                b = rpr.addNewB();
            }
            //设置字体是否加粗
            b.setVal(fontBlod == 1 ? STOnOff.ON : STOnOff.OFF);
            CTColor color = rpr.getColor();//获取<w:rPr>里的<w:color w:val="FFFFFF" w:themeColor="background1"/>
            if (color == null) {//没有<w:color>,创建
                color = rpr.addNewColor();
            }
            // 设置字体颜色
            if (content.contains("↓")) {
                color.setVal("43CD80");
            } else if (content.contains("↑")) {
                color.setVal("943634");
            } else {
                color.setVal(fontColor.substring(1));
            }
            CTHpsMeasure sz = rpr.getSz();
            if (sz == null) {
                sz = rpr.addNewSz();
            }
            sz.setVal(bFontSize);
            CTHpsMeasure szCs = rpr.getSzCs();
            if (szCs == null) {
                szCs = rpr.addNewSz();
            }
            szCs.setVal(bFontSize);
            //-<-
            //<<--rpr结束--
            List<CTText> tlist = r.getTList();
            CTText t = null;
            if (tlist != null && tlist.size() > 0) {//获取第一个<w:r>
                t = tlist.get(0);
            } else {//没有<w:r>,创建
                t = r.addNewT();
            }
            t.setStringValue(content);
            //<<<---r结束---
        }
     
    }
    
    

    模板需要按照楼主的模板来做

    展开全文
  • java导出word中 Document 用的包比较乱,这里需要注意是个坑,我最下面测试用了两种方式导出word,XWPFDocument 与 com.lowagie.text包下的Document.,个人感觉XWPFDocument 方式比较好,图片也支持读取流或读图片路径...

    写在前面,springboot pom 中引入下面就可以了,省了在csdn找包很麻烦。

            <dependency>
                <artifactId>jfreechart</artifactId>
                <groupId>org.jfree</groupId>
                <version>1.0.19</version>
            </dependency>
    

    java导出word中 Document 用的包比较乱,这里需要注意是个坑,我最下面测试用了两种方式导出word,XWPFDocument 与 com.lowagie.text包下的Document.,个人感觉XWPFDocument 方式比较好,图片也支持读取流或读图片路径两种方式写入word,相对来说Document只能用Image img = Image.getInstance(“E:\picture\bar.png”);读取路径方式。

    Image 类的包导入也要注意,示例只能用java8,java11 写入word报错就没用。
    只试了两个柱状图可以用,原引用用导出字体有问题,我下面已经补上了。根据自已想要的样式再稍作调整。
    //设置整个图片的标题字体
    chart.getTitle().setFont(labelFont);
    在这里插入图片描述
    原文引用

    https://blog.csdn.net/zyb_java/article/details/22291473

    
    import com.lowagie.text.Image;
    import com.lowagie.text.*;
    import com.lowagie.text.rtf.RtfWriter2;
    import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
    import org.apache.poi.util.Units;
    import org.apache.poi.xwpf.usermodel.XWPFDocument;
    import org.apache.poi.xwpf.usermodel.XWPFParagraph;
    import org.apache.poi.xwpf.usermodel.XWPFRun;
    import org.jfree.chart.ChartFactory;
    import org.jfree.chart.ChartUtilities;
    import org.jfree.chart.JFreeChart;
    import org.jfree.chart.axis.CategoryAxis;
    import org.jfree.chart.axis.CategoryLabelPositions;
    import org.jfree.chart.axis.NumberAxis;
    import org.jfree.chart.axis.ValueAxis;
    import org.jfree.chart.labels.StandardCategoryItemLabelGenerator;
    import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
    import org.jfree.chart.plot.CategoryPlot;
    import org.jfree.chart.plot.PiePlot3D;
    import org.jfree.chart.plot.PlotOrientation;
    import org.jfree.chart.renderer.category.BarRenderer;
    import org.jfree.chart.renderer.category.LineAndShapeRenderer;
    import org.jfree.chart.renderer.category.StackedBarRenderer;
    import org.jfree.chart.title.TextTitle;
    import org.jfree.data.category.CategoryDataset;
    import org.jfree.data.general.DatasetUtilities;
    import org.jfree.data.general.DefaultPieDataset;
    import org.jfree.data.general.PieDataset;
    
    import javax.imageio.ImageIO;
    import java.awt.Font;
    import java.awt.*;
    import java.awt.image.BufferedImage;
    import java.io.*;
    import java.text.DecimalFormat;
    import java.text.NumberFormat;
    
    ;
    
    
    /**
     * <p><br/>
     *
     * @version v1.0.0
     * @className CreateChartServiceImpl.java<br />
     * @packageName com.sinosoft.webmodule.landLibrary<br />
     * @date 2014-3-23 下午04:39:19<br/>
     * </p>
     */
    
    public class Test {
        private static final String CHART_PATH = "E:/picture/";
    
        @org.junit.Test
        public void main() {
            // 生成单组柱状图
            makeBarChart();
    /*        // 生成饼状图
            makePieChart();
            // 生成单组柱状图
            makeBarChart();
            // 生成单组柱状图
            makeBarChart2();
            // 生成多组柱状图
            makeBarGroupChart();
            // 生成堆积柱状图
            makeStackedBarChart();
            // 生成折线图
            makeLineAndShapeChart();*/
    
        }
    
        /**
         * 生成折线图
         */
        public void makeLineAndShapeChart() {
            double[][] data = new double[][]{{672, 766, 223, 540, 126},
                    {325, 521, 210, 340, 106}, {332, 256, 523, 240, 526}};
            String[] rowKeys = {"苹果", "梨子", "葡萄"};
            String[] columnKeys = {"北京", "上海", "广州", "成都", "深圳"};
            CategoryDataset dataset = getBarData(data, rowKeys, columnKeys);
            createTimeXYChar("折线图", "x轴", "y轴", dataset, "lineAndShap.jpg");
        }
    
        /**
         * 生成分组的柱状图
         */
        public void makeBarGroupChart() {
            double[][] data = new double[][]{{672, 766, 223, 540, 126},
                    {325, 521, 210, 340, 106}, {332, 256, 523, 240, 526}};
            String[] rowKeys = {"苹果", "梨子", "葡萄"};
            String[] columnKeys = {"北京", "上海", "广州", "成都", "深圳"};
            CategoryDataset dataset = getBarData(data, rowKeys, columnKeys);
            createBarChart(dataset, "x坐标", "y坐标", "柱状图", "barGroup.png");
        }
    
        /**
         * 生成柱状图
         */
        @org.junit.Test
        public void makeBarChart() {
            double[][] data = new double[][]{{672, 766, 223, 540, 126}};
            String[] rowKeys = {"苹果"};
            String[] columnKeys = {"北京", "上海", "广州", "成都", "深圳"};
            CategoryDataset dataset = getBarData(data, rowKeys, columnKeys);
            createBarChart(dataset, "", "", "柱状图", "bar.png");
        }
    
        /**
         * 生成柱状图
         */
        public void makeBarChart2() {
            double[][] data = new double[][]{{672, 766, 223, 540, 126}};
            String[] rowKeys = {"苹果"};
            String[] columnKeys = {"北京", "上海", "广州", "成都", "深圳"};
            CategoryDataset dataset = getBarData(data, rowKeys, columnKeys);
            createHorizontalBarChart(dataset, "x坐标", "y坐标", "柱状图", "bar2.png");
        }
    
        /**
         * 生成堆栈柱状图
         */
        public void makeStackedBarChart() {
            double[][] data = new double[][]{{0.21, 0.66, 0.23, 0.40, 0.26},
                    {0.25, 0.21, 0.10, 0.40, 0.16}};
            String[] rowKeys = {"苹果", "梨子"};
            String[] columnKeys = {"北京", "上海", "广州", "成都", "深圳"};
            CategoryDataset dataset = getBarData(data, rowKeys, columnKeys);
            createStackedBarChart(dataset, "x坐标", "y坐标", "柱状图", "stsckedBar.png");
        }
    
        /**
         * 生成饼状图
         */
        public void makePieChart() {
            double[] data = {9, 91};
            String[] keys = {"失败率", "成功率"};
    
            createValidityComparePimChar(getDataPieSetByUtil(data, keys), "饼状图",
                    "pie2.png", keys);
        }
    
        // 柱状图,折线图 数据集
        public CategoryDataset getBarData(double[][] data, String[] rowKeys,
                                          String[] columnKeys) {
            return DatasetUtilities
                    .createCategoryDataset(rowKeys, columnKeys, data);
    
        }
    
        // 饼状图 数据集
        public PieDataset getDataPieSetByUtil(double[] data,
                                              String[] datadescription) {
            if (data != null && datadescription != null) {
                if (data.length == datadescription.length) {
                    DefaultPieDataset dataset = new DefaultPieDataset();
                    for (int i = 0; i < data.length; i++) {
                        dataset.setValue(datadescription[i], data[i]);
                    }
                    return dataset;
                }
    
            }
    
            return null;
        }
    
        /**
         * 柱状图
         *
         * @param dataset    数据集
         * @param xName      x轴的说明(如种类,时间等)
         * @param yName      y轴的说明(如速度,时间等)
         * @param chartTitle 图标题
         * @param charName   生成图片的名字
         * @return
         */
        public String createBarChart(CategoryDataset dataset, String xName,
                                     String yName, String chartTitle, String charName) {
            JFreeChart chart = ChartFactory.createBarChart(chartTitle, // 图表标题
                    xName, // 目录轴的显示标签
                    yName, // 数值轴的显示标签
                    dataset, // 数据集
                    PlotOrientation.VERTICAL, // 图表方向:水平、垂直
                    false, // 是否显示图例(对于简单的柱状图必须是false),(true时,x轴legend下柱子的标题)
                    false, // 是否生成工具
                    false // 是否生成URL链接
            );
            //Font labelFont = new Font("SansSerif", Font.TRUETYPE_FONT, 12);
            Font labelFont = new Font("宋体", Font.BOLD, 15);
            //设置整个图片的标题字体
            chart.getTitle().setFont(labelFont);
            //设置x轴上代表柱子的标题,与上面legend:true 配合使用
            // chart.getLegend().setItemFont(labelFont);
            /*
             * VALUE_TEXT_ANTIALIAS_OFF表示将文字的抗锯齿关闭,
             * 使用的关闭抗锯齿后,字体尽量选择12到14号的宋体字,这样文字最清晰好看
             */
            // chart.getRenderingHints().put(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
            chart.setTextAntiAlias(false);
            chart.setBackgroundPaint(Color.white);
            // create plot
            CategoryPlot plot = chart.getCategoryPlot();
            // 设置横虚线可见
            plot.setRangeGridlinesVisible(true);
            // 虚线色彩
            plot.setRangeGridlinePaint(Color.gray);
    
            // 数据轴精度
    /*        NumberAxis vn = (NumberAxis) plot.getRangeAxis();
            // vn.setAutoRangeIncludesZero(true);
            DecimalFormat df = new DecimalFormat("#0.00");
            vn.setNumberFormatOverride(df); // 数据轴数据标签的显示格式*/
            // x轴设置
            CategoryAxis domainAxis = plot.getDomainAxis();
            domainAxis.setLabelFont(labelFont);// 轴标题
            domainAxis.setTickLabelFont(labelFont);// 轴数值
    
            // Lable(Math.PI/3.0)度倾斜
            // domainAxis.setCategoryLabelPositions(CategoryLabelPositions
            // .createUpRotationLabelPositions(Math.PI / 3.0));
    
            domainAxis.setMaximumCategoryLabelWidthRatio(0.6f);// 横轴上的 Lable 是否完整显示
    
            // 设置距离图片左端距离
            domainAxis.setLowerMargin(0.1);
            // 设置距离图片右端距离
            domainAxis.setUpperMargin(0.1);
            // 设置 columnKey 是否间隔显示
            // domainAxis.setSkipCategoryLabelsToFit(true);
    
            plot.setDomainAxis(domainAxis);
            // 设置柱图背景色(注意,系统取色的时候要使用16位的模式来查看颜色编码,这样比较准确)
            plot.setBackgroundPaint(new Color(255, 255, 204));
    
            // y轴设置
            ValueAxis rangeAxis = plot.getRangeAxis();
            rangeAxis.setLabelFont(labelFont);
            rangeAxis.setTickLabelFont(labelFont);
            // 设置最高的一个 Item 与图片顶端的距离
            rangeAxis.setUpperMargin(0.15);
            // 设置最低的一个 Item 与图片底端的距离
            rangeAxis.setLowerMargin(0.15);
            plot.setRangeAxis(rangeAxis);
    
            BarRenderer renderer = new BarRenderer();
            // 设置柱子宽度
            renderer.setMaximumBarWidth(0.05);
            // 设置柱子高度
            renderer.setMinimumBarLength(0.2);
            // 设置柱子边框颜色
            renderer.setBaseOutlinePaint(Color.BLACK);
            // 设置柱子边框可见
            renderer.setDrawBarOutline(true);
    
            // // 设置柱的颜色
            renderer.setSeriesPaint(0, new Color(204, 255, 255));
            renderer.setSeriesPaint(1, new Color(153, 204, 255));
            renderer.setSeriesPaint(2, new Color(51, 204, 204));
    
            // 设置每个地区所包含的平行柱的之间距离
            renderer.setItemMargin(0.0);
    
            // 显示每个柱的数值,并修改该数值的字体属性
            renderer.setIncludeBaseInRange(true);
            renderer
                    .setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator());
            renderer.setBaseItemLabelsVisible(true);
    
            plot.setRenderer(renderer);
            // 设置柱的透明度
            plot.setForegroundAlpha(1.0f);
    
            FileOutputStream fos_jpg = null;
            try {
                isChartPathExist(CHART_PATH);
                String chartName = CHART_PATH + charName;
                fos_jpg = new FileOutputStream(chartName);
                ChartUtilities.writeChartAsPNG(fos_jpg, chart, 500, 500, true, 10);
                return chartName;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            } finally {
                try {
                    fos_jpg.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
        /**
         * 柱状图 返回JFreeChart
         *
         * @param dataset    数据集
         * @param xName      x轴的说明(如种类,时间等)
         * @param yName      y轴的说明(如速度,时间等)
         * @param chartTitle 图标题
         * @param charName   生成图片的名字
         * @return JFreeChart
         */
        public JFreeChart createBarChart2(CategoryDataset dataset, String xName,
                                          String yName, String chartTitle, String charName) {
            JFreeChart chart = ChartFactory.createBarChart(chartTitle, // 图表标题
                    xName, // 目录轴的显示标签
                    yName, // 数值轴的显示标签
                    dataset, // 数据集
                    PlotOrientation.VERTICAL, // 图表方向:水平、垂直
                    false, // 是否显示图例(对于简单的柱状图必须是false),(true时,x轴legend下柱子的标题)
                    false, // 是否生成工具
                    false // 是否生成URL链接
            );
            //Font labelFont = new Font("SansSerif", Font.TRUETYPE_FONT, 12);
            Font labelFont = new Font("宋体", Font.BOLD, 15);
            //设置整个图片的标题字体
            chart.getTitle().setFont(labelFont);
            //设置x轴上代表柱子的标题,与上面legend:true 配合使用
            // chart.getLegend().setItemFont(labelFont);
            /*
             * VALUE_TEXT_ANTIALIAS_OFF表示将文字的抗锯齿关闭,
             * 使用的关闭抗锯齿后,字体尽量选择12到14号的宋体字,这样文字最清晰好看
             */
            // chart.getRenderingHints().put(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
            chart.setTextAntiAlias(false);
            chart.setBackgroundPaint(Color.white);
            // create plot
            CategoryPlot plot = chart.getCategoryPlot();
            // 设置横虚线可见
            plot.setRangeGridlinesVisible(true);
            // 虚线色彩
            plot.setRangeGridlinePaint(Color.gray);
    
            // 数据轴精度
    /*        NumberAxis vn = (NumberAxis) plot.getRangeAxis();
            // vn.setAutoRangeIncludesZero(true);
            DecimalFormat df = new DecimalFormat("#0.00");
            vn.setNumberFormatOverride(df); // 数据轴数据标签的显示格式*/
            // x轴设置
            CategoryAxis domainAxis = plot.getDomainAxis();
            domainAxis.setLabelFont(labelFont);// 轴标题
            domainAxis.setTickLabelFont(labelFont);// 轴数值
    
            // Lable(Math.PI/3.0)度倾斜
            // domainAxis.setCategoryLabelPositions(CategoryLabelPositions
            // .createUpRotationLabelPositions(Math.PI / 3.0));
    
            domainAxis.setMaximumCategoryLabelWidthRatio(0.6f);// 横轴上的 Lable 是否完整显示
    
            // 设置距离图片左端距离
            domainAxis.setLowerMargin(0.1);
            // 设置距离图片右端距离
            domainAxis.setUpperMargin(0.1);
            // 设置 columnKey 是否间隔显示
            // domainAxis.setSkipCategoryLabelsToFit(true);
    
            plot.setDomainAxis(domainAxis);
            // 设置柱图背景色(注意,系统取色的时候要使用16位的模式来查看颜色编码,这样比较准确)
            plot.setBackgroundPaint(new Color(255, 255, 204));
    
            // y轴设置
            ValueAxis rangeAxis = plot.getRangeAxis();
            rangeAxis.setLabelFont(labelFont);
            rangeAxis.setTickLabelFont(labelFont);
            // 设置最高的一个 Item 与图片顶端的距离
            rangeAxis.setUpperMargin(0.15);
            // 设置最低的一个 Item 与图片底端的距离
            rangeAxis.setLowerMargin(0.15);
            plot.setRangeAxis(rangeAxis);
    
            BarRenderer renderer = new BarRenderer();
            // 设置柱子宽度
            renderer.setMaximumBarWidth(0.05);
            // 设置柱子高度
            renderer.setMinimumBarLength(0.2);
            // 设置柱子边框颜色
            renderer.setBaseOutlinePaint(Color.BLACK);
            // 设置柱子边框可见
            renderer.setDrawBarOutline(true);
    
            // // 设置柱的颜色
            renderer.setSeriesPaint(0, new Color(204, 255, 255));
            renderer.setSeriesPaint(1, new Color(153, 204, 255));
            renderer.setSeriesPaint(2, new Color(51, 204, 204));
    
            // 设置每个地区所包含的平行柱的之间距离
            renderer.setItemMargin(0.0);
    
            // 显示每个柱的数值,并修改该数值的字体属性
            renderer.setIncludeBaseInRange(true);
            renderer
                    .setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator());
            renderer.setBaseItemLabelsVisible(true);
    
            plot.setRenderer(renderer);
            // 设置柱的透明度
            plot.setForegroundAlpha(1.0f);
    
            FileOutputStream fos_jpg = null;
            return chart;
        }
    
        /**
         * 横向图
         *
         * @param dataset    数据集
         * @param xName      x轴的说明(如种类,时间等)
         * @param yName      y轴的说明(如速度,时间等)
         * @param chartTitle 图标题
         * @param charName   生成图片的名字
         * @return
         */
        public String createHorizontalBarChart(CategoryDataset dataset,
                                               String xName, String yName, String chartTitle, String charName) {
            JFreeChart chart = ChartFactory.createBarChart(chartTitle, // 图表标题
                    xName, // 目录轴的显示标签
                    yName, // 数值轴的显示标签
                    dataset, // 数据集
                    PlotOrientation.VERTICAL, // 图表方向:水平、垂直
                    true, // 是否显示图例(对于简单的柱状图必须是false)
                    false, // 是否生成工具
                    false // 是否生成URL链接
            );
    
            CategoryPlot plot = chart.getCategoryPlot();
            // 数据轴精度
            NumberAxis vn = (NumberAxis) plot.getRangeAxis();
            // 设置刻度必须从0开始
            // vn.setAutoRangeIncludesZero(true);
            DecimalFormat df = new DecimalFormat("#0.00");
            vn.setNumberFormatOverride(df); // 数据轴数据标签的显示格式
    
            CategoryAxis domainAxis = plot.getDomainAxis();
    
            domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_45); // 横轴上的
            // Lable
            Font labelFont = new Font("SansSerif", Font.TRUETYPE_FONT, 12);
    
            domainAxis.setLabelFont(labelFont);// 轴标题
            domainAxis.setTickLabelFont(labelFont);// 轴数值
    
            domainAxis.setMaximumCategoryLabelWidthRatio(0.8f);// 横轴上的 Lable 是否完整显示
            // domainAxis.setVerticalCategoryLabels(false);
            plot.setDomainAxis(domainAxis);
    
            ValueAxis rangeAxis = plot.getRangeAxis();
            // 设置最高的一个 Item 与图片顶端的距离
            rangeAxis.setUpperMargin(0.15);
            // 设置最低的一个 Item 与图片底端的距离
            rangeAxis.setLowerMargin(0.15);
            plot.setRangeAxis(rangeAxis);
            BarRenderer renderer = new BarRenderer();
            // 设置柱子宽度
            renderer.setMaximumBarWidth(0.03);
            // 设置柱子高度
            renderer.setMinimumBarLength(30);
    
            renderer.setBaseOutlinePaint(Color.BLACK);
    
            // 设置柱的颜色
            renderer.setSeriesPaint(0, Color.GREEN);
            renderer.setSeriesPaint(1, new Color(0, 0, 255));
            // 设置每个地区所包含的平行柱的之间距离
            renderer.setItemMargin(0.5);
            // 显示每个柱的数值,并修改该数值的字体属性
            renderer
                    .setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator());
            // 设置柱的数值可见
            renderer.setBaseItemLabelsVisible(true);
    
            plot.setRenderer(renderer);
            // 设置柱的透明度
            plot.setForegroundAlpha(0.6f);
    
            FileOutputStream fos_jpg = null;
            try {
                isChartPathExist(CHART_PATH);
                String chartName = CHART_PATH + charName;
                fos_jpg = new FileOutputStream(chartName);
                ChartUtilities.writeChartAsPNG(fos_jpg, chart, 500, 500, true, 10);
                return chartName;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            } finally {
                try {
                    fos_jpg.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
        /**
         * 饼状图
         *
         * @param dataset    数据集
         * @param chartTitle 图标题
         * @param charName   生成图的名字
         * @param pieKeys    分饼的名字集
         * @return
         */
        public String createValidityComparePimChar(PieDataset dataset,
                                                   String chartTitle, String charName, String[] pieKeys) {
            JFreeChart chart = ChartFactory.createPieChart3D(chartTitle, // chart
                    // title
                    dataset,// data
                    true,// include legend
                    true, false);
    
            // 使下说明标签字体清晰,去锯齿类似于
            // chart.getRenderingHints().put(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);的效果
            chart.setTextAntiAlias(false);
            // 图片背景色
            chart.setBackgroundPaint(Color.white);
            // 设置图标题的字体重新设置title
            Font font = new Font("隶书", Font.BOLD, 25);
            TextTitle title = new TextTitle(chartTitle);
            title.setFont(font);
            chart.setTitle(title);
    
            PiePlot3D plot = (PiePlot3D) chart.getPlot();
            // 图片中显示百分比:默认方式
    
            // 指定饼图轮廓线的颜色
            // plot.setBaseSectionOutlinePaint(Color.BLACK);
            // plot.setBaseSectionPaint(Color.BLACK);
    
            // 设置无数据时的信息
            plot.setNoDataMessage("无对应的数据,请重新查询。");
    
            // 设置无数据时的信息显示颜色
            plot.setNoDataMessagePaint(Color.red);
    
            // 图片中显示百分比:自定义方式,{0} 表示选项, {1} 表示数值, {2} 表示所占比例 ,小数点后两位
            plot.setLabelGenerator(new StandardPieSectionLabelGenerator(
                    "{0}={1}({2})", NumberFormat.getNumberInstance(),
                    new DecimalFormat("0.00%")));
            // 图例显示百分比:自定义方式, {0} 表示选项, {1} 表示数值, {2} 表示所占比例
            plot.setLegendLabelGenerator(new StandardPieSectionLabelGenerator(
                    "{0}={1}({2})"));
    
            plot.setLabelFont(new Font("SansSerif", Font.TRUETYPE_FONT, 12));
    
            // 指定图片的透明度(0.0-1.0)
            plot.setForegroundAlpha(0.65f);
            // 指定显示的饼图上圆形(false)还椭圆形(true)
            plot.setCircular(false, true);
    
            // 设置第一个 饼块section 的开始位置,默认是12点钟方向
            plot.setStartAngle(90);
    
            // // 设置分饼颜色
            plot.setSectionPaint(pieKeys[0], new Color(244, 194, 144));
            plot.setSectionPaint(pieKeys[1], new Color(144, 233, 144));
    
            FileOutputStream fos_jpg = null;
            try {
                // 文件夹不存在则创建
                isChartPathExist(CHART_PATH);
                String chartName = CHART_PATH + charName;
                fos_jpg = new FileOutputStream(chartName);
                // 高宽的设置影响椭圆饼图的形状
                ChartUtilities.writeChartAsPNG(fos_jpg, chart, 500, 230);
    
                return chartName;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            } finally {
                try {
                    fos_jpg.close();
                    System.out.println("create pie-chart.");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
    
        }
    
        /**
         * 判断文件夹是否存在,如果不存在则新建
         *
         * @param chartPath
         */
        private void isChartPathExist(String chartPath) {
            File file = new File(chartPath);
            if (!file.exists()) {
                file.mkdirs();
                // log.info("CHART_PATH="+CHART_PATH+"create.");
            }
        }
    
        /**
         * 折线图
         *
         * @param chartTitle
         * @param x
         * @param y
         * @param xyDataset
         * @param charName
         * @return
         */
        public String createTimeXYChar(String chartTitle, String x, String y,
                                       CategoryDataset xyDataset, String charName) {
            JFreeChart chart = ChartFactory.createLineChart(chartTitle, x, y,
                    xyDataset, PlotOrientation.VERTICAL, true, true, false);
    
            chart.setTextAntiAlias(false);
            chart.setBackgroundPaint(Color.WHITE);
            // 设置图标题的字体重新设置title
            Font font = new Font("隶书", Font.BOLD, 25);
            TextTitle title = new TextTitle(chartTitle);
            title.setFont(font);
            chart.setTitle(title);
            // 设置面板字体
            Font labelFont = new Font("SansSerif", Font.TRUETYPE_FONT, 12);
    
            chart.setBackgroundPaint(Color.WHITE);
    
            CategoryPlot categoryplot = (CategoryPlot) chart.getPlot();
            // x轴 // 分类轴网格是否可见
            categoryplot.setDomainGridlinesVisible(true);
            // y轴 //数据轴网格是否可见
            categoryplot.setRangeGridlinesVisible(true);
    
            categoryplot.setRangeGridlinePaint(Color.WHITE);// 虚线色彩
    
            categoryplot.setDomainGridlinePaint(Color.WHITE);// 虚线色彩
    
            categoryplot.setBackgroundPaint(Color.lightGray);
    
            // 设置轴和面板之间的距离
            // categoryplot.setAxisOffset(new RectangleInsets(5D, 5D, 5D, 5D));
    
            CategoryAxis domainAxis = categoryplot.getDomainAxis();
    
            domainAxis.setLabelFont(labelFont);// 轴标题
            domainAxis.setTickLabelFont(labelFont);// 轴数值
    
            domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_45); // 横轴上的
            // Lable
            // 45度倾斜
            // 设置距离图片左端距离
            domainAxis.setLowerMargin(0.0);
            // 设置距离图片右端距离
            domainAxis.setUpperMargin(0.0);
    
            NumberAxis numberaxis = (NumberAxis) categoryplot.getRangeAxis();
            numberaxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
            numberaxis.setAutoRangeIncludesZero(true);
    
            // 获得renderer 注意这里是下嗍造型到lineandshaperenderer!!
            LineAndShapeRenderer lineandshaperenderer = (LineAndShapeRenderer) categoryplot
                    .getRenderer();
    
            lineandshaperenderer.setBaseShapesVisible(true); // series 点(即数据点)可见
            lineandshaperenderer.setBaseLinesVisible(true); // series 点(即数据点)间有连线可见
    
            // 显示折点数据
            // lineandshaperenderer.setBaseItemLabelGenerator(new
            // StandardCategoryItemLabelGenerator());
            // lineandshaperenderer.setBaseItemLabelsVisible(true);
    
            FileOutputStream fos_jpg = null;
            try {
                isChartPathExist(CHART_PATH);
                String chartName = CHART_PATH + charName;
                fos_jpg = new FileOutputStream(chartName);
    
                // 将报表保存为png文件
                ChartUtilities.writeChartAsPNG(fos_jpg, chart, 500, 510);
    
                return chartName;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            } finally {
                try {
                    fos_jpg.close();
                    System.out.println("create time-createTimeXYChar.");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
        /**
         * 堆栈柱状图
         *
         * @param dataset
         * @param xName
         * @param yName
         * @param chartTitle
         * @param charName
         * @return
         */
        public String createStackedBarChart(CategoryDataset dataset, String xName,
                                            String yName, String chartTitle, String charName) {
            // 1:得到 CategoryDataset
    
            // 2:JFreeChart对象
            JFreeChart chart = ChartFactory.createStackedBarChart(chartTitle, // 图表标题
                    xName, // 目录轴的显示标签
                    yName, // 数值轴的显示标签
                    dataset, // 数据集
                    PlotOrientation.VERTICAL, // 图表方向:水平、垂直
                    true, // 是否显示图例(对于简单的柱状图必须是false)
                    false, // 是否生成工具
                    false // 是否生成URL链接
            );
            // 图例字体清晰
            chart.setTextAntiAlias(false);
    
            chart.setBackgroundPaint(Color.WHITE);
    
            // 2 .2 主标题对象 主标题对象是 TextTitle 类型
            chart
                    .setTitle(new TextTitle(chartTitle, new Font("隶书", Font.BOLD,
                            25)));
            // 2 .2.1:设置中文
            // x,y轴坐标字体
            Font labelFont = new Font("SansSerif", Font.TRUETYPE_FONT, 12);
    
            // 2 .3 Plot 对象 Plot 对象是图形的绘制结构对象
            CategoryPlot plot = chart.getCategoryPlot();
    
            // 设置横虚线可见
            plot.setRangeGridlinesVisible(true);
            // 虚线色彩
            plot.setRangeGridlinePaint(Color.gray);
    
            // 数据轴精度
            NumberAxis vn = (NumberAxis) plot.getRangeAxis();
            // 设置最大值是1
            vn.setUpperBound(1);
            // 设置数据轴坐标从0开始
            // vn.setAutoRangeIncludesZero(true);
            // 数据显示格式是百分比
            DecimalFormat df = new DecimalFormat("0.00%");
            vn.setNumberFormatOverride(df); // 数据轴数据标签的显示格式
            // DomainAxis (区域轴,相当于 x 轴), RangeAxis (范围轴,相当于 y 轴)
            CategoryAxis domainAxis = plot.getDomainAxis();
    
            domainAxis.setLabelFont(labelFont);// 轴标题
            domainAxis.setTickLabelFont(labelFont);// 轴数值
    
            // x轴坐标太长,建议设置倾斜,如下两种方式选其一,两种效果相同
            // 倾斜(1)横轴上的 Lable 45度倾斜
            // domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_45);
            // 倾斜(2)Lable(Math.PI 3.0)度倾斜
            // domainAxis.setCategoryLabelPositions(CategoryLabelPositions
            // .createUpRotationLabelPositions(Math.PI / 3.0));
    
            domainAxis.setMaximumCategoryLabelWidthRatio(0.6f);// 横轴上的 Lable 是否完整显示
    
            plot.setDomainAxis(domainAxis);
    
            // y轴设置
            ValueAxis rangeAxis = plot.getRangeAxis();
            rangeAxis.setLabelFont(labelFont);
            rangeAxis.setTickLabelFont(labelFont);
            // 设置最高的一个 Item 与图片顶端的距离
            rangeAxis.setUpperMargin(0.15);
            // 设置最低的一个 Item 与图片底端的距离
            rangeAxis.setLowerMargin(0.15);
            plot.setRangeAxis(rangeAxis);
    
            // Renderer 对象是图形的绘制单元
            StackedBarRenderer renderer = new StackedBarRenderer();
            // 设置柱子宽度
            renderer.setMaximumBarWidth(0.05);
            // 设置柱子高度
            renderer.setMinimumBarLength(0.1);
            // 设置柱的边框颜色
            renderer.setBaseOutlinePaint(Color.BLACK);
            // 设置柱的边框可见
            renderer.setDrawBarOutline(true);
    
            // // 设置柱的颜色(可设定也可默认)
            renderer.setSeriesPaint(0, new Color(204, 255, 204));
            renderer.setSeriesPaint(1, new Color(255, 204, 153));
    
            // 设置每个地区所包含的平行柱的之间距离
            renderer.setItemMargin(0.4);
    
            plot.setRenderer(renderer);
            // 设置柱的透明度(如果是3D的必须设置才能达到立体效果,如果是2D的设置则使颜色变淡)
            // plot.setForegroundAlpha(0.65f);
    
            FileOutputStream fos_jpg = null;
            try {
                isChartPathExist(CHART_PATH);
                String chartName = CHART_PATH + charName;
                fos_jpg = new FileOutputStream(chartName);
                ChartUtilities.writeChartAsPNG(fos_jpg, chart, 500, 500, true, 10);
                return chartName;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            } finally {
                try {
                    fos_jpg.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
        /**
         * 获取图片流
         *
         * @param jfreechart
         * @param weight
         * @param height
         * @return
         */
        public static InputStream getChartStream(JFreeChart jfreechart, int weight, int height) {
            InputStream input = null;
            try {
                BufferedImage bufferedImage = jfreechart.createBufferedImage(weight, height);
                ByteArrayOutputStream os = new ByteArrayOutputStream();
                ImageIO.write(bufferedImage, "png", os);
                input = new ByteArrayInputStream(os.toByteArray());
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println("-------------------------------------" + e.getMessage());
            }
            return input;
        }
    
    
        /**
         * java 8 必须
         */
        @org.junit.Test
        public void createXWPFDocument() throws IOException, DocumentException, InvalidFormatException {
            System.out.println("createXWPFDocument==================");
            XWPFDocument doc = new XWPFDocument();
            double[][] data = new double[][]{{672, 766, 223, 540, 126}};
            String[] rowKeys = {"苹果"};
            String[] columnKeys = {"北京", "上海", "广州", "成都", "深圳"};
            CategoryDataset dataset = getBarData(data, rowKeys, columnKeys);
            JFreeChart jfreechart = this.createBarChart2(dataset, "", "", "柱状图", "barGroup.png");
            InputStream inputStream = getChartStream(jfreechart, 550, 300);
    
            XWPFParagraph paragraph = doc.createParagraph();
            XWPFRun run = paragraph.createRun();
            run.setBold(true); //加粗
            run.setText("加粗的内容");
            run.setColor("FF0000");
            run.setText("红色的字。");
            XWPFParagraph paragraph2 = doc.createParagraph();
            XWPFRun run2 = paragraph2.createRun();
            run2.addPicture(inputStream, XWPFDocument.PICTURE_TYPE_PNG, "图片1", Units.toEMU(400), Units.toEMU(300));
            OutputStream os = new FileOutputStream("E:\\picture\\test.docx");
            //把doc输出到输出流
            doc.write(os);
        }
    
        @org.junit.Test
        public void TestDocument() throws DocumentException {
            //创建文本
            Document doc = new Document(PageSize.A4);
            try {
                RtfWriter2.getInstance(doc,
                        new FileOutputStream("E://picture//test2.doc"));
                doc.open();
    
                double[][] data = new double[][]{{672, 766, 223, 540, 126}};
                String[] rowKeys = {"苹果"};
                String[] columnKeys = {"北京", "上海", "广州", "成都", "深圳"};
                CategoryDataset dataset = getBarData(data, rowKeys, columnKeys);
                JFreeChart jfreechart = this.createBarChart2(dataset, "", "", "柱状图", "barGroup.png");
                InputStream inputStream = getChartStream(jfreechart, 550, 300);
    
                com.lowagie.text.Font font = new com.lowagie.text.Font(com.lowagie.text.Font.NORMAL, 12, com.lowagie.text.Font.BOLD, new Color(0, 0, 0));
                Paragraph paragraph = new Paragraph("5.学生家长对学校开展爱国主义教育(活动形式、活动效果等)的评价", font);
                paragraph.setAlignment(1);
                Image img = Image.getInstance("E:\\picture\\bar.png");
                img.scaleAbsolute(400, 400);//自定义大小
                //img.scaleToFit(500, 300);//
                paragraph.add(img);
                doc.add(paragraph);
    
    
                doc.close();
                System.out.println("=============com.lowagie.text.Document");
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    
    
    展开全文
  • 上个博客生成了一个静态的柱状图 也就是将柱状图的图片放到word里,这个博客说说 ftl文件里给他设置数据动态 1创建.docx文档模板: 类似于这样的模板 2.生成xml在线解析格式然后转ftl: 类似于这样 它...
  • Springboot Controller中使用service调SQL语句的方法,动态获取数据库信息添加到WORD表格中,检查到的数据绘制为柱形图(直方图)添加到文档中,并生成word(含表格,柱状图)存储到本地,在浏览器下载本地的word文档
  • java 动态获取数据库信息生成word(含表格,柱状图),并下载
  • 写了一个月 4月20-5月20,终于完成 …一个日报 大多es查的数据,有一点mysql查的数据 先占个坑,回头有空记录一下
  • 这是一部分自己做的代码,但是不知道怎么设置统计的样式 public void setChartDate(String filepath,String pos,List[]> list){ ActiveXComponent word=null; Dispatch doc=null; Dispatch graph=null; ...
  • 对于实现word文档插入...但是aspose插件也无法对生成柱状图进行颜色的设置,生成柱状图按照word默认的颜色生成。如下图: 基本都是这个颜色顺序 这种弊端一般情况下还是可以接受的,但是如果是下图的需求,...
  • package barchartdemo1; import &... class='replace_word' title="Java EE知识库" target='_blank' style='color:#df3434; font-weight:bold;'&gt;Java&lt;/a&g...
  • <div><p>该提问来源于开源项目:aspose-words/Aspose.Words-for-Java</p></div>
  • poi终于支持在Word中动态刷新图表了 poi版本 1.maven坐标 org.apache.poi poi 4.1.0 org.apache.poi poi-ooxml 4.1.0
  • Python入门到实战(五)conda使用、pandas操作Excel、数据可视化、绘制柱状图、操作Word、数据报表生成、pip install国内镜像下载conda使用常用操作配置VS+CondaPython实现办公自动化操作ExcelPandas将数据写入...
  • 最近在写一些报告,要用到不少表格和图,一开始不知道如何画柱状图和折线图的结合体,查了一番后搞定,记录下,以备日后翻阅。 以GDP的数据为例说明: 1、在word中插入一张柱状图表,会自动生成一个excel,用来...
  • 利用以上教程可以使用Origin绘制简单的三维堆积柱状图,本文主要记录一下其他需求,比如坐标轴范围修改、柱子颜色调整、堆积柱子形状调整、如何粘贴源文件到word等等。基本操作参考以上教程,下文体现较少。 一、...

空空如也

空空如也

1 2 3 4 5 6
收藏数 102
精华内容 40
关键字:

word生成柱状图