SpringBoot集成文件 - 如何基于POI-tl和word模板导出庞大的Word文件?

字节探雪人
• 阅读 2583
前文我们介绍了通过Apache POI通过来导出word的例子;那如果是word模板方式,有没有开源库通过模板方式导出word呢?poi-tl是一个基于Apache POI的Word模板引擎,也是一个免费开源的Java类库,你可以非常方便的加入到你的项目中,并且拥有着让人喜悦的特性。本文主要介绍通过SpringBoot集成poi-tl实现模板方式的Word导出功能。

知识准备

需要理解文件上传和下载的常见场景和技术手段。@pdai

什么是poi-tl

如下内容来源于,poi-tl官网

poi-tl(poi template language)是Word模板引擎,使用Word模板和数据创建很棒的Word文档。

优势:

SpringBoot集成文件 - 如何基于POI-tl和word模板导出庞大的Word文件?

它还支持自定义插件,如下是官网代码仓库支持的特性

poi-tl supports custom functions (plug-ins), functions can be executed anywhere in the Word template, do anything anywhere in the document is the goal of poi-tl.
FeatureDescription
TextRender the tag as text
PictureRender the tag as a picture
TableRender the tag as a table
NumberingRender the tag as a numbering
ChartBar chart (3D bar chart), column chart (3D column chart), area chart (3D area chart), line chart (3D line chart), radar chart, pie chart (3D pie Figure) and other chart rendering
If ConditionHide or display certain document content (including text, paragraphs, pictures, tables, lists, charts, etc.) according to conditions
Foreach LoopLoop through certain document content (including text, paragraphs, pictures, tables, lists, charts, etc.) according to the collection
Loop table rowLoop to copy a row of the rendered table
Loop table columnLoop copy and render a column of the table
Loop ordered listSupport the loop of ordered list, and support multi-level list at the same time
Highlight codeWord highlighting of code blocks, supporting 26 languages ​​and hundreds of coloring styles
MarkdownConvert Markdown to a word document
Word attachmentInsert attachment in Word
Word CommentsComplete support comment, create comment, modify comment, etc.
Word SDTComplete support structured document tag
TextboxTag support in text box
Picture replacementReplace the original picture with another picture
bookmarks, anchors, hyperlinksSupport setting bookmarks, anchors and hyperlinks in documents
Expression LanguageFully supports SpringEL expressions and can extend more expressions: OGNL, MVEL...
StyleThe template is the style, and the code can also set the style
Template nestingThe template contains sub-templates, and the sub-templates then contain sub-templates
MergeWord merge Merge, you can also merge in the specified position
custom functions (plug-ins)Plug-in design, execute function anywhere in the document

poi-tl的TDO模式

TDO模式:Template + data-model = output

以官网的例子为例:

XWPFTemplate template = XWPFTemplate.compile("template.docx").render(
  new HashMap<String, Object>(){{
    put("title", "Hi, poi-tl Word模板引擎");
}});  
template.writeAndClose(new FileOutputStream("output.docx")); 
  • compile 编译模板 - Template
  • render 渲染数据 - data-model
  • write 输出到流 - output

Template:模板

模板是Docx格式的Word文档,你可以使用Microsoft office、WPS Office、Pages等任何你喜欢的软件制作模板,也可以使用Apache POI代码来生成模板。

所有的标签都是以{{开头,以}}结尾,标签可以出现在任何位置,包括页眉,页脚,表格内部,文本框等,表格布局可以设计出很多优秀专业的文档,推荐使用表格布局。

poi-tl模板遵循“所见即所得”的设计,模板和标签的样式会被完全保留。

Data-model:数据

数据类似于哈希或者字典,可以是Map结构(key是标签名称):

Map<String, Object> data = new HashMap<>();
data.put("name", "Sayi");
data.put("start_time", "2019-08-04");

可以是对象(属性名是标签名称):

public class Data {
  private String name;
  private String startTime;
  private Author author;
}

数据可以是树结构,每级之间用点来分隔开,比如{ {author.name} }标签对应的数据是author对象的name属性值。

Word模板不是由简单的文本表示,所以在渲染图片、表格等元素时提供了数据模型,它们都实现了接口RenderData,比如图片数据模型PictureRenderData包含图片路径、宽、高三个属性。

Output:输出

以流的方式进行输出:

template.write(OutputStream stream);

可以写到任意输出流中,比如文件流:

template.write(new FileOutputStream("output.docx"));

比如网络流:

response.setContentType("application/octet-stream");
response.setHeader("Content-disposition","attachment;filename=\""+"out_template.docx"+"\"");

// HttpServletResponse response
OutputStream out = response.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(out);
template.write(bos);
bos.flush();
out.flush();
PoitlIOUtils.closeQuietlyMulti(template, bos, out); // 最后不要忘记关闭这些流。

实现案例

这里展示SpringBoot集成poi-tl基于word模板导出Word, 以及导出markdown为word的例子。

Pom依赖

引入poi的依赖包

基础的包:

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

插件的包如下,比如highlight,markdown包

<dependency>
    <groupId>com.deepoove</groupId>
    <artifactId>poi-tl-plugin-highlight</artifactId>
    <version>1.0.0</version>
</dependency>
<dependency>
    <groupId>com.deepoove</groupId>
    <artifactId>poi-tl-plugin-markdown</artifactId>
    <version>1.0.3</version>
</dependency>

导出基于template的word

controller中的方法

@ApiOperation("Download Word")
@GetMapping("/word/download")
public void download(HttpServletResponse response) {
    try {
        XWPFTemplate document = userService.generateWordXWPFTemplate();
        response.reset();
        response.setContentType("application/octet-stream");
        response.setHeader("Content-disposition",
                "attachment;filename=user_word_" + System.currentTimeMillis() + ".docx");
        OutputStream os = response.getOutputStream();
        document.write(os);
        os.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Service中的实际方法

@Override
public XWPFTemplate generateWordXWPFTemplate() throws IOException {
    Map<String, Object> content = new HashMap<>();
    content.put("title", "Java 全栈知识体系");
    content.put("author", "pdai");
    content.put("site", new HyperlinkTextRenderData("https://pdai.tech", "https://pdai.tech"));

    content.put("poiText", "Apache POI 是创建和维护操作各种符合Office Open XML(OOXML)标准和微软的OLE 2复合文档格式(OLE2)的Java API。用它可以使用Java读取和创建,修改MS Excel文件.而且,还可以使用Java读取和创建MS Word和MSPowerPoint文件。更多请参考[官方文档](https://poi.apache.org/index.html)");

    content.put("poiText2", "生成xls和xlsx有什么区别?POI对Excel中的对象的封装对应关系?");
    content.put("poiList", Numberings.create("excel03只能打开xls格式,无法直接打开xlsx格式",
            "xls只有65536行、256列; xlsx可以有1048576行、16384列",
            "xls占用空间大, xlsx占用空间小,运算速度也会快一点"));

    RowRenderData headRow = Rows.of("ID", "Name", "Email", "TEL", "Description").textColor("FFFFFF")
            .bgColor("4472C4").center().create();
    TableRenderData table = Tables.create(headRow);
    getUserList()
            .forEach(a -> table.addRow(Rows.create(a.getId() + "", a.getUserName(), a.getEmail(), a.getPhoneNumber() + "", a.getDescription())));
    content.put("poiTable", table);

    Resource resource = new ClassPathResource("pdai-guli.png");
    content.put("poiImage", Pictures.ofStream(new FileInputStream(resource.getFile())).create());

    return XWPFTemplate.compile(new ClassPathResource("poi-tl-template.docx").getFile()).render(content);
}

private List<User> getUserList() {
    List<User> userList = new ArrayList<>();
    for (int i = 0; i < 5; i++) {
        userList.add(User.builder()
                .id(Long.parseLong(i + "")).userName("pdai" + i).email("pdai@pdai.tech" + i).phoneNumber(121231231231L)
                .description("hello world" + i)
                .build());
    }
    return userList;
}

准备模板

SpringBoot集成文件 - 如何基于POI-tl和word模板导出庞大的Word文件?

导出word

SpringBoot集成文件 - 如何基于POI-tl和word模板导出庞大的Word文件?

导出markdown为word

controller中的方法

@ApiOperation("Download Word based on markdown")
@GetMapping("/word/downloadMD")
public void downloadMD(HttpServletResponse response) {
    try {
        XWPFTemplate document = userService.generateWordXWPFTemplateMD();
        response.reset();
        response.setContentType("application/octet-stream");
        response.setHeader("Content-disposition",
                "attachment;filename=user_word_" + System.currentTimeMillis() + ".docx");
        OutputStream os = response.getOutputStream();
        document.write(os);
        os.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Service中实现的方法


@Override
public XWPFTemplate generateWordXWPFTemplateMD() throws IOException {
    MarkdownRenderData code = new MarkdownRenderData();

    Resource resource = new ClassPathResource("test.md");
    code.setMarkdown(new String(Files.readAllBytes(resource.getFile().toPath())));
    code.setStyle(MarkdownStyle.newStyle());

    Map<String, Object> data = new HashMap<>();
    data.put("md", code);

    Configure config = Configure.builder().bind("md", new MarkdownRenderPolicy()).build();

    return XWPFTemplate.compile(new ClassPathResource("markdown_template.docx").getFile(), config).render(data);
}

准备模板

SpringBoot集成文件 - 如何基于POI-tl和word模板导出庞大的Word文件?

导出word

SpringBoot集成文件 - 如何基于POI-tl和word模板导出庞大的Word文件?

示例源码

https://github.com/realpdai/t...

参考文章

http://deepoove.com/poi-tl/

更多内容

告别碎片化学习,无套路一站式体系化学习后端开发: Java 全栈知识体系(https://pdai.tech)

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
美凌格栋栋酱 美凌格栋栋酱
6个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
3年前
java word导出pdf
整体思路就是:使用word模板引擎,将占位符(格式:{{title}})替换为查询出来的数据,再将替换完成的word转换为pdf!(https://oscimg.oschina.net/oscnet/76ac1bc3da6d1cec6f1c2f9406c8e07a768.jpg)doc转pdf源码:https://gitee.com/java
Wesley13 Wesley13
3年前
java调用PageOffice生成word
一、在开发OA办公或与文档相关的Web系统中,难免会遇到动态生成word文档的需求,为了解决工作中遇到导出word文档的需求,前一段时间上网找了一些资料,在word导出这方面有很多工具可以使用,jacob、poi、java2word、itext。jacob要求服务器必须是windows操作系统,服务器上还必须安装office软件,果断放弃!poi需要针对do
秋桐 秋桐
2年前
如何通过Java程序合并Word文档
合并Word文档是指将多个Word文档的内容、样式和格式合并成一个新的Word文档。这个功能通常在需要整合多个文档内容时使用,比如在对多个人员提交的文档进行汇总、审阅或编辑时。通过合并Word文档,可以大大提高工作效率,减少手动复制粘贴等繁琐操作,同时保留
秋桐 秋桐
2年前
通过Java实现Word转PDF
Word转为PDF是非常常见的一种格式转换。通过转换可以将文档以更为稳定的格式进行保存,避免他人随意修改格式和内容。其实Word转PDF并不难,除了直接转换外也可以通过编程的方式来实现。网上相关的教程分享也很多。今天想介绍一个JavaWord组件——Fre
Wesley13 Wesley13
3年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Stella981 Stella981
3年前
PHPWord导出word文档
最近接了个把数据导出到word文档的需求,之前一直都是使用PHPExcel库导出excel的,还是头次接到导出到word文档的需求,我想既然有PHPExcel,那么肯定也会有PHPWord库吧,在网上一搜,还真有!而且都是phpoffice家的。看了下文档,最终决定使用模板的方式来导出数据,感觉也是最简单的一种方式了。过程如下:使用composer下
Stella981 Stella981
3年前
Python中办公软件(创建word)
当前目录下创建word文件importwin32comimportwin32com.clientimportosdefmakeWordFile(fileName,name):wordwin32com.client.Dispatch("Word.Application")获取word程序让文档可见word.Visi
Wesley13 Wesley13
3年前
Java 程序动态替换 docx 模板中定制值的实现例子
项目系统中打印功能,导出word文档功能是挺常用的,本文介绍自定文档模板,程序实现模板内容中值替代的功能。模板文件template.docx !(https://oscimg.oschina.net/oscnet/fddfe774b063f795b701911f99ad581538f.png)​执行main publi