赞
踩
官方文档地址:http://deepoove.com/poi-tl/
源码地址:https://github.com/Sayi/poi-tl
poi-tl(poi template language)是Word模板引擎,使用Word模板和数据创建很棒的Word文档。
最近在做项目时候有一个关于导出Word的文件的需求,需要导出的word文件较大,并且格式比较复杂,使用poi-tl可以很好的解决。在这里记录一下关于复杂表格的合并与生成。
poi-tl的优势
poi-tl 是基于 Apache POI ,使用时请注意poi的版本依赖冲突问题
1. 添加依赖
<!--poi-tl-->
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>
<version>1.12.0</version>
</dependency>
2.快速入门
新建Word文档template.docx,这里模板文件存放resources/word目录下,模板包含标签 {{title}}
代码示例
@GetMapping("/export")
public void export(HttpServletResponse response) throws IOException {
// 获取模板文件流
InputStream resourceAsStream =
this.getClass().getResourceAsStream("/word/template.docx");
//poi-tl 配置
ConfigureBuilder builder = Configure.builder();
builder.useSpringEL(false);
Map<String,Object> map = new HashMap<>();
map.put("title","hello,poi-tl!");
XWPFTemplate template = XWPFTemplate.compile(Objects.requireNonNull(resourceAsStream), builder.build()).render(map);
//输出文件流
template.writeAndClose(new FileOutputStream("D:\\output.docx"));
}
3.输出
可以写到任意输出流中,比如文件流:
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);
导出的word中存在
单个
表格, 或动态的多个
表格
poi-tl提供了抽象表格策略类
DynamicTableRenderPolicy
我们可以自定义模板渲染策略类,继承即可,从而动态渲染的部分单元格,实现我们需求
1.新建数据存储实体类-
ServerTableData
@Data public class ServerTableData { /** * 携带表格中真实数据 */ private List<RowRenderData> serverDataList; /** * 携带要分组的信息 */ private List<Map<String, Object>> groupDataList; /** * 需要合并的列,从0开始 */ private Integer mergeColumn; }
2.新建自定义表格渲染策略类-
ServerTablePolicy
-
public class ServerTablePolicy extends DynamicTableRenderPolicy { @Override public void render(XWPFTable xwpfTable, Object tableData) throws Exception { if (null == tableData) { return; } // 参数数据声明 ServerTableData serverTableData = (ServerTableData) tableData; List<RowRenderData> serverDataList = serverTableData.getServerDataList(); List<Map<String, Object>> groupDataList = serverTableData.getGroupDataList(); Integer mergeColumn = serverTableData.getMergeColumn(); if (CollectionUtils.isNotEmpty(serverDataList)) { // 先删除一行, demo中第一行是为了调整 三线表 样式 xwpfTable.removeRow(1); // 行从中间插入, 因此采用倒序渲染数据 for (int i = serverDataList.size() - 1; i >= 0; i--) { XWPFTableRow newRow = xwpfTable.insertNewTableRow(1); newRow.setHeight(400); for (int j = 0; j < 4; j++) { newRow.createCell(); } // 渲染一行数据 TableRenderPolicy.Helper.renderRow(newRow, serverDataList.get(i)); } // 处理合并 for (int i = 0; i < serverDataList.size(); i++) { // 获取要合并的名称那一列数据 mergeColumn代表要合并的列,从0开始 String typeNameData = serverDataList.get(i).getCells().get(mergeColumn).getParagraphs().get(0).getContents().get(0).toString(); for (int j = 0; j < groupDataList.size(); j++) { String typeNameTemplate = String.valueOf(groupDataList.get(j).get("typeName")); int listSize = Integer.parseInt(String.valueOf(groupDataList.get(j).get("listSize"))); // 若匹配上 就直接合并 if (typeNameTemplate.equals(typeNameData)) { TableTools.mergeCellsVertically(xwpfTable, 0, i + 1, i + listSize); groupDataList.remove(j); break; } } } } } }
3.接口类
@GetMapping("/export") public void export(HttpServletResponse response) throws IOException { // 获取模板文件流 InputStream resourceAsStream = this.getClass().getResourceAsStream("/word/template.docx"); //poi-tl 配置 ConfigureBuilder builder = Configure.builder(); builder.useSpringEL(false); Map<String,Object> map = new HashMap<>(); // 伪造一个表格数据 //单个表格 ServerTableData oneTable = getServerTableData(); map.put("oneTable",oneTable); builder.bind("oneTable",new ServerTablePolicy()); //多个表格 List<Map<String, Object>> dynamicFlag = new ArrayList<>(); // 伪造3个表格数据 for (int i = 0; i < 3; i++) { ServerTableData tableData = getServerTableData(); Map<String, Object> dynamicTableMap = new HashMap<>(); dynamicTableMap.put("serverListTable", tableData); dynamicTableMap.put("tableName", "表名"); dynamicFlag.add(dynamicTableMap); } map.put("listTable",dynamicFlag); builder.bind("serverListTable",new ServerTablePolicy()); XWPFTemplate template = XWPFTemplate.compile(Objects.requireNonNull(resourceAsStream), builder.build()).render(map); //输出网络流 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); } private ServerTableData getServerTableData() { ServerTableData serverTableData = new ServerTableData(); List<RowRenderData> serverDataList = new ArrayList<>(); for (int j = 0; j < 4; j++) { String typeName; RowRenderData serverData; if (j > 1) { typeName = "索隆"; serverData = Rows.of(typeName, "喝酒", "三千世界", "无").center().create(); }else { typeName = "路飞"; serverData = Rows.of(typeName, "大鸡腿", "巨人手枪", "橡胶果实").center().create(); } serverDataList.add(serverData); } List<Map<String, Object>> groupDataList = new ArrayList<>(); Map<String, Object> groupData1 = new HashMap<>(); groupData1.put("typeName", "索隆"); groupData1.put("listSize", "2"); Map<String, Object> groupData2 = new HashMap<>(); groupData2.put("typeName", "路飞"); groupData2.put("listSize", "2"); groupDataList.add(groupData1); groupDataList.add(groupData2); serverTableData.setServerDataList(serverDataList); serverTableData.setGroupDataList(groupDataList); serverTableData.setMergeColumn(0); return serverTableData; }
4.效果图
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。