Poi-tl

Poi-tl是一个基于Apache POI的Word模板引擎,也是一个免费开源的Java类库,你可以非常方便的加入到你的项目中;可以使用模版创建也可以不使用模版,但是使用模版便于生成文档和修改,研发人员只需要封装好数据提供给模版,不需要耗费心思在样式和格式上。
文档链接:Poi-tl文档链接


一、引入maven依赖

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

二、使用模版创建word非常方便,只需要封装好数据就行

1.文本:{{city}}

数据模型:

  • String :文本

  • TextRenderData :有样式的文本

  • HyperlinkTextRenderData :超链接和锚点文本

  • Object :调用 toString() 方法转化为文本

put("name", "Sayi");
put("author", Texts.of("Sayi").color("000000").create());
put("link", Texts.of("website").link("http://deepoove.com").create());
put("anchor", Texts.of("anchortxt").anchor("appendix1").create());
  • 示例:
// wordTemp-模版文件全路径(/home/server/word/template.docx)
// outReport-生成word文件全路径(/home/server/word/20240611.docx)
XWPFTemplate.compile(wordTemp).render(new HashMap<String, Object>() {
           {
               put("city", city);
           }
       }).writeToFile(outReport);

2.图片:{{@tempPic_P}}

数据模型:

  • String :图片url或者本地路径,默认使用图片自身尺寸

  • ByteArrayPictureRenderData

  • FilePictureRenderData

  • UrlPictureRenderData

// 指定图片路径
put("image", "logo.png");
// svg图片
put("svg", "https://img.shields.io/badge/jdk-1.6%2B-orange.svg");

// 图片文件
put("image1", Pictures.ofLocal("logo.png").size(120, 120).create());

// 图片流
put("streamImg", Pictures.ofStream(new FileInputStream("logo.jpeg"), PictureType.JPEG)
  .size(100, 120).create());

// 网络图片(注意网络耗时对系统可能的性能影响)
put("urlImg", Pictures.ofUrl("http://deepoove.com/images/icecream.png")
  .size(100, 100).create());

// java图片,我们可以利用Java生成图表插入到word文档中
put("buffered", Pictures.ofBufferedImage(bufferImage, PictureType.PNG)
  .size(100, 100).create());

示例:

// tempPic_P:http://192.168.0.188:9000/test-bucket/exp/测试文件3.png
XWPFTemplate.compile(wordTemp).render(new HashMap<String, Object>() {
           {
               put("city", city);
               put("tempPic_P", tempPic_P);
           }
       }).writeToFile(outReport);

3.表格:{{#var}}

数据模型:

  • TableRenderData
  • 推荐使用工厂 Tables 、 Rows 和 Cells 构建表格模型。
// 一个2行2列的表格
put("table0", Tables.of(new String[][] {
                new String[] { "00", "01" },
                new String[] { "10", "11" }
            }).border(BorderStyle.DEFAULT).create());
// 第0行居中且背景为蓝色的表格
RowRenderData row0 = Rows.of("姓名", "学历").textColor("FFFFFF")
      .bgColor("4472C4").center().create();
RowRenderData row1 = Rows.create("李四", "博士");
put("table1", Tables.create(row0, row1));

4. 列表:{{*var}}

数据模型-区块对比列表好用,推荐使用区块对:

  • List

  • NumberingRenderData

5.区块对:{{?sections}}{{/sections}}

  • 示例:
public static void main(String[] args) throws IOException {
        String wordTemp = "E:/test/doc/测试报告生成/testTemplate.docx";
        long time = DateUtil.date().getTime();
        String outReport = "E:/test/doc/测试报告生成/" + time + ".docx";
        List<Map<String, Object>> list = new ArrayList<>();

        for(int i = 0; i < 2; i++){
            Map<String, Object> map = new HashMap<>();
            map.put("index", i+1);
            map.put("name", "测试" + i);
            map.put("province", "测试省" + i);
            map.put("city", "测试市" + i);
            map.put("area", "测试区" + i);
            map.put("sheet", "测试街道" + i);
            map.put("postCode", "测试邮编" + i);
            list.add(map);
        }
        XWPFTemplate.compile(wordTemp).render(new HashMap<String, Object>() {
            {
                put("reportDetail", list);
            }
        }).writeToFile(outReport);
    }

模版内容
生成结果

6.实战生成示例:包含使用自定义插件和图表

  • 如果想一页一个表格,这时需要用到插件
    实现一个插件就是要告诉我们在模板的某个地方用某些数据做某些事情,我们可以通过实现RenderPolicy接口开发自己的插件:
@FunctionalInterface
public interface RenderPolicy {
    void render(ElementTemplate var1, Object var2, XWPFTemplate var3);
}
 public static void main(String[] args) throws IOException {
        String wordTemp = "E:/zxlz/project/hw/doc/测试报告生成/testTemplate.docx";
        long time = DateUtil.date().getTime();
        String outReport = "E:/zxlz/project/hw/doc/测试报告生成/" + time + ".docx";
        List<Map<String, Object>> list = new ArrayList<>();

        // 单系列图表的标签是一个文本:{{var}},标签位置在:图表区格式-可选文字—标题(新版本Microsoft Office标签位置在:编辑替换文字-替换文字)。
        ChartSingleSeriesRenderData pie = Charts
                .ofSingleSeries("城市人数", new String[] { "广东", "福建" })
                .series("cities", new Integer[] { 20, 30 })
                .create();
        // 组合图表的标签是一个文本:{{var}},标签位置在:图表区格式—可选文字—标题(新版本Microsoft Office标签位置在:编辑替换文字-替换文字)。
        ChartMultiSeriesRenderData comb = Charts
                // 图表标题,种类
                .ofComboSeries("2019-2023年全省生产总值及其增速", new String[] { "2019", "2020", "2021", "2022", "2023"})
                // 下面是系列即柱状图或折线图
                .addBarSeries("总量(亿元)", new Double[] { 45428.96, 43004.49, 50091.23, 52741.68, 55803.63 })
                .addLineSeries("增速(%)", new Double[] { 7.3, -5.4, 12.9, 4.0, 6.0 }).create();
        for(int i = 0; i < 2; i++){
            Map<String, Object> map = new HashMap<>();
            map.put("index", i+1);
            map.put("name", "测试" + i);
            map.put("province", "测试省" + i);
            map.put("city", "测试市" + i);
            map.put("area", "测试区" + i);
            map.put("sheet", "测试街道" + i);
            map.put("postCode", "测试邮编" + i);
            // 设置宽高
            map.put("image", Pictures.ofLocal("C:/Users/Administrator/Desktop/image.jpg").size(200, 100).create());
            map.put("imageName", "测试图片");
            map.put("pieChart", pie);
            map.put("combChart", comb);
            list.add(map);
        }
        // 设置自定义的 RenderPolicy
        Configure config = Configure.builder()
                .bind("pageBreak", new ReportChartRenderData()).build();

        XWPFTemplate.compile(wordTemp, config).render(new HashMap<String, Object>() {
            {
                put("title", "测试生成报告");
                put("reportDetail", list);
                put("curDate", DateUtil.format(DateUtil.date(), "yyyy-MM-dd"));

            }
        }).writeToFile(outReport);
    }
public class ReportChartRenderData implements RenderPolicy {
    @Override
    public void render(ElementTemplate eleTemplate, Object data, XWPFTemplate template) {

        // 获取当前的 XWPFDocument 和运行上下文
        XWPFDocument doc = template.getXWPFDocument();
        XWPFRun run = ((RunTemplate) eleTemplate).getRun();
        run.setText("", 0);
        // 插入分页符
        run.addBreak(BreakType.PAGE);
    }
}
  • 模版文件:

模版

  • 根据模版生成文档:
    生成文档

更多推荐