Poi-tl实现导出word

834 阅读6分钟

一、需求

  1. 正本(普通+带样式文本+图片)
  2. 表格
  3. 列表
  4. 单一饼图
  5. 单一柱状图
  6. 单一折线图
  7. 组合图表
  8. word 转pdf等其他文档类型

Maven依赖

<dependency>
    <groupId>com.deepoove</groupId>
    <artifactId>poi-tl</artifactId>
    <version>1.8.2</version>
</dependency>

Poi-tl常用标签

文本

格式:{{var}}

数据模型:

类型描述
String纯文本
TextRenderData带有样式的文本
HyperLinkTextRenderData超链接文本
Object调用toString()方法转化成文本

代码示例:

        //文本
        TextContentData contentData = new TextContentData();
        contentData.setContent("office处理方案").setLabelName("title").setTypeEnum(WordContentTypeEnum.TEXT);
        generates.add(contentData);
        //带样式文本
        TextContentData typeData = new TextContentData();
        typeData.setRenderData(new TextRenderData("cc0000","这是带样式的内容")).setLabelName("content").setTypeEnum(WordContentTypeEnum.TEXT);
        generates.add(typeData);
        //超链接
        TextContentData linkData = new TextContentData();
        HyperLinkTextRenderData hyperLinkTextRenderData = new HyperLinkTextRenderData("掘金社区", "https://feifan.iflytek.com/welcome/");
        linkData.setRenderData(hyperLinkTextRenderData).setLabelName("typeContent").setTypeEnum(WordContentTypeEnum.TEXT);
        /*linkData.setLinkData(hyperLinkTextRenderData);*/
        generates.add(linkData);

模板示例: image.png

图片

格式:{{@var}}

数据模型:

类型描述
PictureRenderData可以支持本地图片、也可以支持远程的URL地址(主要讲URL图片转成BufferedImage)

代码示例:

        //插入图片
        PictureContentData picData = new PictureContentData();
        picData.setWidth(200).setHeight(160).setPicType(PicTypeEnum.JPG).setFile(new File("D:\\data\\tmp\\img\\monkey.png"))
                .setLabelName("picture").setTypeEnum(WordContentTypeEnum.PICTURE);
        generates.add(picData);

模板示例:

image.png

表格

格式:{{#var}}

数据模型:

类型描述
MiniTableRenderData该类主要也是调用TextRenderData,提供样式等

代码示例:

        //插入表格
        TableSeriesRenderData tableData = new TableSeriesRenderData();
        List<TextRenderData[]> contents = Arrays.asList(
                new TextRenderData[] {new TextRenderData("杨思宏1"), new TextRenderData("男"), new TextRenderData("18")},
                new TextRenderData[] {new TextRenderData("杨思宏2"), new TextRenderData("男"), new TextRenderData("18")});
        tableData.setHeader(new TextRenderData[]{new TextRenderData("姓名"), new TextRenderData("性别"), new TextRenderData("年龄")})
                .setContents(contents).setLabelName("table").setTypeEnum(WordContentTypeEnum.TABLE);
        generates.add(tableData);

模板示例:

image.png

列表

格式:{{*var}}

数据模型:

类型描述
NumbericRenderData该类主要也是调用TextRenderData,提供样式等

说明:NumbericRenderData中支持列表样式,主要有罗马字符、有序无序等。

FMT_DECIMAL // 1. 2. 3.

FMT_DECIMAL_PARENTHESES // 1) 2) 3)

FMT_BULLET // ● ● ●

FMT_LOWER_LETTER // a. b. c.

FMT_LOWER_ROMAN // i ⅱ ⅲ

FMT_UPPER_LETTER // A. B. C.

代码示例:

        //插入列表
        ListRenderData listRenderData = new ListRenderData();
        List<TextRenderData> listData = Arrays.asList(
                new TextRenderData("第一名"), new TextRenderData("第二名"), new TextRenderData("第三名")
        );
        listRenderData.setList(listData).setPair(NumbericRenderData.FMT_DECIMAL).setTypeEnum(WordContentTypeEnum.LIST).setLabelName("textList");

模板示例:

image.png

单系列图表

描述:单系列图标,是指在图形中只展示一列数据,例如:单数据的柱状图,饼图等。

格式:{{val}}

模板操作:插入-图表-饼图,点击饼图图层,编辑右侧【标题】 image.png image.png

image.png

数据模型:

类型描述
ChartSingleSeriesRenderData该类提供了设置标题、类别等

代码示例:

        //折线
        ChartSeriesRenderData lineData = new ChartSeriesRenderData();
        List<ChartSeriesRenderData.RenderData> lineRenderData = new ArrayList<>();
        ChartSeriesRenderData.RenderData lightRenderData = new ChartSeriesRenderData.RenderData();
        ChartSeriesRenderData.RenderData highRenderData = new ChartSeriesRenderData.RenderData();
        lightRenderData.setRenderTitle("严重BUG数").setData(new Double[] {11.02,19.42,10.61,11.41,7.91,5.44,5.30,2.75,1.24,0.35});
        highRenderData.setRenderTitle("轻微BUG数").setData(new Number[]{12.66,19.41,15.16,19.72,17.05,15.92,15.10,13.04,10.65,9.15});
        lineRenderData.add(lightRenderData);
        lineRenderData.add(highRenderData);
        lineData.setTitle("开发质量报告")
                .setCategories(new String[] {"1月","2月","3月","4月","5月","6月","7月","8月","9月","10月"})
                .setSenderData(lineRenderData).setTypeEnum(WordContentTypeEnum.CHART).setLabelName("qaLine");
        generates.add(lineData);
        //柱状图
        ChartSeriesRenderData barData = new ChartSeriesRenderData();
        List<ChartSeriesRenderData.RenderData> barRenderData = new ArrayList<>();
        ChartSeriesRenderData.RenderData openRenderData = new ChartSeriesRenderData.RenderData();
        ChartSeriesRenderData.RenderData moneyData = new ChartSeriesRenderData.RenderData();
        openRenderData.setRenderTitle("2011年GDP(亿)")
                .setData(new Number[]{129118.58,122875.6,87435,77715,61345.05,61345.8,53734.92,53109.85,48670.37,45045,44652.8,42370.4,41610.9,32772.68,32074.7,29129.03,28975.1,28954.2,26300.87,25642.59,23159,20164.58,17741.34,16311.34,15901,13070.24,11201.6,6818.22,5069.57,3610.1,2132.64});
        moneyData.setRenderTitle("2012年GDP(亿)")
                .setData(new Number[]{119118.58,112875.6,81435,71715,62345.05,62345.8,51734.92,51109.85,42670.37,41045,41652.8,41370.4,44610.9,37772.68,39074.7,23129.03,21975.1,21954.2,21300.87,21642.59,21159,20164.58,11741.34,11311.34,19901,12070.24,13201.6,6218.22,5269.57,3310.1,2332.64});
        barRenderData.add(openRenderData);
        barRenderData.add(moneyData);
        barData.setTitle("各省GDP")
                .setCategories(new String[] {"广东省","江苏省","山东省","浙江省","河南省","四川省","湖北省","福建省","湖南省","安徽省","上海","河北省","北京","陕西省","江西省","重庆","辽宁省","云南省","广西省","山西省","内蒙古","贵州省","新疆","天津","黑龙江省","吉林省","甘肃省","海南省","宁夏省","青海省","西藏省"})
                .setSenderData(barRenderData).setTypeEnum(WordContentTypeEnum.CHART).setLabelName("gdp");

        generates.add(barData);
        //生成饼图
        ChartSeriesRenderData areaData = new ChartSeriesRenderData();
        List<ChartSeriesRenderData.RenderData> areaRenderDatas = new ArrayList<>();
        ChartSeriesRenderData.RenderData areaRenderData = new ChartSeriesRenderData.RenderData();
        areaRenderData.setData(new Number[]{8200, 1000}).setRenderTitle("比例")
                .setComboType(SeriesRenderData.ComboType.AREA);
        areaRenderDatas.add(areaRenderData);
        areaData.setTitle("研发男女比例").setSenderData(areaRenderDatas).setCharType(CharCombinationType.Single)
                .setCategories(new String[]{"男", "女"})
                .setLabelName("showRate").setTypeEnum(WordContentTypeEnum.CHART);
        generates.add(areaData);

        //横向柱状图
        ChartSeriesRenderData lateralData = new ChartSeriesRenderData();
        List<ChartSeriesRenderData.RenderData> lateralRenderData = new ArrayList<>();
        ChartSeriesRenderData.RenderData year22Data = new ChartSeriesRenderData.RenderData();
        ChartSeriesRenderData.RenderData year23Data = new ChartSeriesRenderData.RenderData();
        year22Data.setRenderTitle("2022年").setData(new Number[]{3000, 3500});
        year23Data.setRenderTitle("2023年").setData(new Number[]{3000, 3500});
        lateralRenderData.add(year22Data);
        lateralRenderData.add(year23Data);
        lateralData.setTitle("工资涨幅")
                .setCategories(new String[] {"基本工资", "绩效工资"})
                .setSenderData(lateralRenderData).setTypeEnum(WordContentTypeEnum.CHART).setLabelName("salary");
        generates.add(lateralData);

多系统图表

描述:很多报表都需要多系统图表,例如:柱状图与折线图组合展示

格式:{{val}}

模板操作:插入-图表-组合,点击图表图层,编辑右侧【标题】

image.png

数据模型:

类型描述
ChartMultiSeriesRenderData该类提供了设置标题、类别等

代码示例:

        //组合图表
        ChartSeriesRenderData groupData = new ChartSeriesRenderData();
        List<ChartSeriesRenderData.RenderData> groupRenderData = new ArrayList<>();
        ChartSeriesRenderData.RenderData incrData = new ChartSeriesRenderData.RenderData();
        ChartSeriesRenderData.RenderData radioData = new ChartSeriesRenderData.RenderData();
        incrData.setComboType(SeriesRenderData.ComboType.BAR).setRenderTitle("薪资涨幅(亿)")
                .setData(new Number[]{50, 50, 100, 200, 500});
        radioData.setComboType(SeriesRenderData.ComboType.LINE).setRenderTitle("增长率(%)")
                .setData(new Number[]{5, 10, 30, 15, 23});
        groupRenderData.add(incrData);
        groupRenderData.add(radioData);
        groupData.setTitle("各年薪资涨幅报告")
                .setCategories(new String[] {"2019", "2020", "2021", "2022", "2023"})
                .setSenderData(groupRenderData).setTypeEnum(WordContentTypeEnum.CHART).setLabelName("gdpGroup");
        generates.add(groupData);

word转换其他文档类型

POI-TL自身并不支持相关文档转换,它只负责生成word

完整代码

        File templateFile = null;
        try {
            templateFile = new ClassPathResource(TEMPLATE_PATH).getFile();
        } catch (IOException e) {
            log.error("Word模板读取异常:{}", e);
        }
        List<LabelData> generates = new ArrayList<>();
        //文本
        TextContentData contentData = new TextContentData();
        contentData.setContent("掘金社区office处理方案").setLabelName("title").setTypeEnum(WordContentTypeEnum.TEXT);
        generates.add(contentData);
        //带样式文本
        TextContentData typeData = new TextContentData();
        typeData.setRenderData(new TextRenderData("cc0000","这是带样式的内容")).setLabelName("content").setTypeEnum(WordContentTypeEnum.TEXT);
        generates.add(typeData);
        //超链接
        TextContentData linkData = new TextContentData();
        HyperLinkTextRenderData hyperLinkTextRenderData = new HyperLinkTextRenderData("掘金社区", "https://feifan.iflytek.com/welcome/");
        linkData.setRenderData(hyperLinkTextRenderData).setLabelName("typeContent").setTypeEnum(WordContentTypeEnum.TEXT);
        /*linkData.setLinkData(hyperLinkTextRenderData);*/
        generates.add(linkData);


        //插入图片
        PictureContentData picData = new PictureContentData();
        picData.setWidth(200).setHeight(160).setPicType(PicTypeEnum.JPG).setFile(new File("D:\\data\\tmp\\img\\monkey.png"))
                .setLabelName("picture").setTypeEnum(WordContentTypeEnum.PICTURE);
        generates.add(picData);
        //插入表格
        TableSeriesRenderData tableData = new TableSeriesRenderData();
        List<TextRenderData[]> contents = Arrays.asList(
                new TextRenderData[] {new TextRenderData("杨思宏1"), new TextRenderData("男"), new TextRenderData("18")},
                new TextRenderData[] {new TextRenderData("杨思宏2"), new TextRenderData("男"), new TextRenderData("18")});
        tableData.setHeader(new TextRenderData[]{new TextRenderData("姓名"), new TextRenderData("性别"), new TextRenderData("年龄")})
                .setContents(contents).setLabelName("table").setTypeEnum(WordContentTypeEnum.TABLE);
        generates.add(tableData);
        //插入列表
        ListRenderData listRenderData = new ListRenderData();
        List<TextRenderData> listData = Arrays.asList(
                new TextRenderData("第一名"), new TextRenderData("第二名"), new TextRenderData("第三名")
        );
        listRenderData.setList(listData).setPair(NumbericRenderData.FMT_DECIMAL).setTypeEnum(WordContentTypeEnum.LIST).setLabelName("textList");
        generates.add(listRenderData);
        //折线
        ChartSeriesRenderData lineData = new ChartSeriesRenderData();
        List<ChartSeriesRenderData.RenderData> lineRenderData = new ArrayList<>();
        ChartSeriesRenderData.RenderData lightRenderData = new ChartSeriesRenderData.RenderData();
        ChartSeriesRenderData.RenderData highRenderData = new ChartSeriesRenderData.RenderData();
        lightRenderData.setRenderTitle("严重BUG数").setData(new Double[] {11.02,19.42,10.61,11.41,7.91,5.44,5.30,2.75,1.24,0.35});
        highRenderData.setRenderTitle("轻微BUG数").setData(new Number[]{12.66,19.41,15.16,19.72,17.05,15.92,15.10,13.04,10.65,9.15});
        lineRenderData.add(lightRenderData);
        lineRenderData.add(highRenderData);
        lineData.setTitle("开发质量报告")
                .setCategories(new String[] {"1月","2月","3月","4月","5月","6月","7月","8月","9月","10月"})
                .setSenderData(lineRenderData).setTypeEnum(WordContentTypeEnum.CHART).setLabelName("qaLine");
        generates.add(lineData);
        //柱状图
        ChartSeriesRenderData barData = new ChartSeriesRenderData();
        List<ChartSeriesRenderData.RenderData> barRenderData = new ArrayList<>();
        ChartSeriesRenderData.RenderData openRenderData = new ChartSeriesRenderData.RenderData();
        ChartSeriesRenderData.RenderData moneyData = new ChartSeriesRenderData.RenderData();
        openRenderData.setRenderTitle("2011年GDP(亿)")
                .setData(new Number[]{129118.58,122875.6,87435,77715,61345.05,61345.8,53734.92,53109.85,48670.37,45045,44652.8,42370.4,41610.9,32772.68,32074.7,29129.03,28975.1,28954.2,26300.87,25642.59,23159,20164.58,17741.34,16311.34,15901,13070.24,11201.6,6818.22,5069.57,3610.1,2132.64});
        moneyData.setRenderTitle("2012年GDP(亿)")
                .setData(new Number[]{119118.58,112875.6,81435,71715,62345.05,62345.8,51734.92,51109.85,42670.37,41045,41652.8,41370.4,44610.9,37772.68,39074.7,23129.03,21975.1,21954.2,21300.87,21642.59,21159,20164.58,11741.34,11311.34,19901,12070.24,13201.6,6218.22,5269.57,3310.1,2332.64});
        barRenderData.add(openRenderData);
        barRenderData.add(moneyData);
        barData.setTitle("各省GDP")
                .setCategories(new String[] {"广东省","江苏省","山东省","浙江省","河南省","四川省","湖北省","福建省","湖南省","安徽省","上海","河北省","北京","陕西省","江西省","重庆","辽宁省","云南省","广西省","山西省","内蒙古","贵州省","新疆","天津","黑龙江省","吉林省","甘肃省","海南省","宁夏省","青海省","西藏省"})
                .setSenderData(barRenderData).setTypeEnum(WordContentTypeEnum.CHART).setLabelName("gdp");

        generates.add(barData);
        //生成饼图
        ChartSeriesRenderData areaData = new ChartSeriesRenderData();
        List<ChartSeriesRenderData.RenderData> areaRenderDatas = new ArrayList<>();
        ChartSeriesRenderData.RenderData areaRenderData = new ChartSeriesRenderData.RenderData();
        areaRenderData.setData(new Number[]{8200, 1000}).setRenderTitle("比例")
                .setComboType(SeriesRenderData.ComboType.AREA);
        areaRenderDatas.add(areaRenderData);
        areaData.setTitle("研发男女比例").setSenderData(areaRenderDatas).setCharType(CharCombinationType.Single)
                .setCategories(new String[]{"男", "女"})
                .setLabelName("showRate").setTypeEnum(WordContentTypeEnum.CHART);
        generates.add(areaData);

        //横向柱状图
        ChartSeriesRenderData lateralData = new ChartSeriesRenderData();
        List<ChartSeriesRenderData.RenderData> lateralRenderData = new ArrayList<>();
        ChartSeriesRenderData.RenderData year22Data = new ChartSeriesRenderData.RenderData();
        ChartSeriesRenderData.RenderData year23Data = new ChartSeriesRenderData.RenderData();
        year22Data.setRenderTitle("2022年").setData(new Number[]{3000, 3500});
        year23Data.setRenderTitle("2023年").setData(new Number[]{3000, 3500});
        lateralRenderData.add(year22Data);
        lateralRenderData.add(year23Data);
        lateralData.setTitle("工资涨幅")
                .setCategories(new String[] {"基本工资", "绩效工资"})
                .setSenderData(lateralRenderData).setTypeEnum(WordContentTypeEnum.CHART).setLabelName("salary");
        generates.add(lateralData);

        //组合图表
        ChartSeriesRenderData groupData = new ChartSeriesRenderData();
        List<ChartSeriesRenderData.RenderData> groupRenderData = new ArrayList<>();
        ChartSeriesRenderData.RenderData incrData = new ChartSeriesRenderData.RenderData();
        ChartSeriesRenderData.RenderData radioData = new ChartSeriesRenderData.RenderData();
        incrData.setComboType(SeriesRenderData.ComboType.BAR).setRenderTitle("薪资涨幅(亿)")
                .setData(new Number[]{50, 50, 100, 200, 500});
        radioData.setComboType(SeriesRenderData.ComboType.LINE).setRenderTitle("增长率(%)")
                .setData(new Number[]{5, 10, 30, 15, 23});
        groupRenderData.add(incrData);
        groupRenderData.add(radioData);
        groupData.setTitle("各年薪资涨幅报告")
                .setCategories(new String[] {"2019", "2020", "2021", "2022", "2023"})
                .setSenderData(groupRenderData).setTypeEnum(WordContentTypeEnum.CHART).setLabelName("gdpGroup");
        generates.add(groupData);

        //生成word
        String destFilePath = "D:\\data\\tmp\\office\\word\\output.docx";
        FileOutputStream fos = null;
        XWPFTemplate template = null;
        try {
            template = XWPFTemplate.compile(templateFile).render(new HashMap<String,Object>(contents.size()){{
                generates.forEach(content -> {
                    if (null == content.getTypeEnum()) {
                        log.error("该图表配置异常:{}", content.toString());
                    }
                    GenerateWord backData = GenerateWordFactory.getBackData(content.getTypeEnum());
                    put(content.getLabelName(),backData.generateWord(content));
                });
            }});
            fos = new FileOutputStream(destFilePath);
            template.write(fos);
            fos.flush();
        }catch (Exception e){
            log.error("生成Word异常:{}", e);
        }finally {
            try{
                if (Objects.nonNull(fos)){
                    fos.close();
                }
                if (Objects.nonNull(template)){
                    template.close();
                }
            }catch (Exception e){
                log.error("关闭数据流异常:{}", e);
            }
        }

导出word示例

image.png