本编文章继SpringBoot+Poi-tl根据Word模板动态生成word(含动态行表格)文章之后
介绍Poi-tl导出word的延伸功能:

所需依赖以及word模板所属位置 见 SpringBoot+Poi-tl根据Word模板动态生成word(含动态行表格),这里不再累赘。

直接介绍延伸功能的实现。

一、延伸功能

功能1:导出多个动态行表格(固定个数)
功能2:导出循环列表下的动态行表格(个数不固定)
功能3:导出合并单元格
功能4:导出循环列表下合并单元格
功能5:导出循环列表下合并单元格、外加一个动态行表格

二、功能实现

功能1:导出多个动态行表格(固定个数)

(1)新建一个word(orderD2.docx),编写word模板:

(2)在ExportWordController类中,编写相应的导出方法,供页面请求

 /*** 销售订单信息导出word --- poi-tl(包含两个动态行表格)* @throws IOException */@RequestMapping("/exportDataWordD4")public void exportDataWordD4(HttpServletRequest request,HttpServletResponse response) throws IOException{try {Map<String, Object> params = new HashMap<>();// TODO 渲染其他类型的数据请参考官方文档DecimalFormat df = new DecimalFormat("######0.00");   Calendar now = Calendar.getInstance(); double money = 0;//总金额//组装表格列表数据List<Map<String,Object>> typeList=new ArrayList<Map<String,Object>>();for (int i = 0; i < 2; i++) {Map<String,Object> detailMap = new HashMap<String, Object>();detailMap.put("index", i+1);//序号if(i == 0){detailMap.put("sub_type", "监督技术装备");//商品所属大类名称}else if(i == 1){detailMap.put("sub_type", "火灾调查装备");//商品所属大类名称}else if(i == 2){detailMap.put("sub_type", "工程验收装备");//商品所属大类名称}double saleprice=Double.valueOf(String.valueOf(100+i));Integer buy_num=Integer.valueOf(String.valueOf(3+i));String buy_price=df.format(saleprice*buy_num);detailMap.put("buy_price", buy_price);//所属大类总价格money=money+Double.valueOf(buy_price);typeList.add(detailMap);}//组装表格列表数据List<Map<String,Object>> detailList=new ArrayList<Map<String,Object>>();for (int i = 0; i < 3; i++) {Map<String,Object> detailMap = new HashMap<String, Object>();detailMap.put("index", i+1);//序号if(i == 0 || i == 1){detailMap.put("product_type", "二级分类1");//商品二级分类}else{detailMap.put("product_type", "二级分类2");//商品二级分类}detailMap.put("title", "商品"+i);//商品名称detailMap.put("product_description", "套");//商品规格detailMap.put("buy_num", 3+i);//销售数量detailMap.put("saleprice", 100+i);//销售价格detailMap.put("technical_parameter", "技术参数"+i);//技术参数detailList.add(detailMap);}//总金额String order_money=String.valueOf(money);//金额中文大写String money_total = MoneyUtils.change(money);//word模板地址获取方式一:缺点---打jar包获取不到该路径
//          String basePath=ClassUtils.getDefaultClassLoader().getResource("").getPath()+"static/template/";
//          String resource =basePath+"orderD2.docx";//word模板地址//word模板地址获取方式二:优点---相比上一种方式,这种方法不会在linux或者jar上失效ClassPathResource classPathResource = new ClassPathResource("static/template/orderD2.docx");String resource = classPathResource.getURL().getPath();//渲染表格  动态行HackLoopTableRenderPolicy  policy = new HackLoopTableRenderPolicy();Configure config = Configure.newBuilder().bind("typeList", policy).bind("detailList", policy).build();XWPFTemplate template = XWPFTemplate.compile(resource, config).render(new HashMap<String, Object>() {{put("typeList", typeList);put("detailList",detailList);put("order_number", "2356346346645");put("y", now.get(Calendar.YEAR));//当前年put("m", (now.get(Calendar.MONTH) + 1));//当前月put("d", now.get(Calendar.DAY_OF_MONTH));//当前日put("order_money",order_money);//总金额put("money_total",money_total);//金额中文大写}});//=================生成文件保存在本地D盘某目录下=================String temDir="D:/mimi/"+File.separator+"file/word/"; ;//生成临时文件存放地址//生成文件名Long time = new Date().getTime();// 生成的word格式String formatSuffix = ".docx";// 拼接后的文件名String fileName = time + formatSuffix;//文件名  带后缀FileOutputStream fos = new FileOutputStream(temDir+fileName);template.write(fos);//=================生成word到设置浏览默认下载地址=================// 设置强制下载不打开response.setContentType("application/force-download");// 设置文件名response.addHeader("Content-Disposition", "attachment;fileName=" + fileName);OutputStream out = response.getOutputStream();template.write(out);out.flush();out.close();template.close();} catch (Exception e) {e.printStackTrace();}}

(3)页面编写调用方法

<div class="m2" style="margin-top: 30px;">使用<span class="s1">POI-tl</span>根据word模板动态生成word(包含两个动态行表格)</div>
<a href="#" class="easyui-linkbutton" onclick="doExportWordD4();" data-options="iconCls:'icon-save'">导出word(包含两个动态行表格)</a>
//方式一导出word(包含两个动态行表格)function doExportWordD4(){window.location.href="<%=basePath%>/auth/exportWord/exportDataWordD4";}

(4)导出结果:

功能2:导出循环列表下的动态行表格(个数不固定)

如果列表的每一项不是简单的文本,而是包含很多文档内容,或者多级列表该怎么生成? 区块对的循环功能可以很好的循环列表,并且支持编号有序。

(1)新建一个word(order2.docx),编写word模板:

(2)在ExportWordController类中,编写相应的导出方法,供页面请求

/*** 销售订单信息导出word --- poi-tl(包含动态行表格、循环列表中的动态行表格)* @throws IOException */@RequestMapping("/exportDataWord4")public void exportDataWord4(HttpServletRequest request,HttpServletResponse response) throws IOException{try {Map<String, Object> params = new HashMap<>();// TODO 渲染其他类型的数据请参考官方文档DecimalFormat df = new DecimalFormat("######0.00");   Calendar now = Calendar.getInstance(); double money = 0;//总金额//组装表格列表数据List<Map<String,Object>> typeList=new ArrayList<Map<String,Object>>();for (int i = 0; i < 2; i++) {Map<String,Object> detailMap = new HashMap<String, Object>();detailMap.put("index", i+1);//序号if(i == 0){detailMap.put("sub_type", "监督技术装备");//商品所属大类名称}else if(i == 1){detailMap.put("sub_type", "火灾调查装备");//商品所属大类名称}else if(i == 2){detailMap.put("sub_type", "工程验收装备");//商品所属大类名称}double saleprice=Double.valueOf(String.valueOf(100+i));Integer buy_num=Integer.valueOf(String.valueOf(3+i));String buy_price=df.format(saleprice*buy_num);detailMap.put("buy_price", buy_price);//所属大类总价格money=money+Double.valueOf(buy_price);typeList.add(detailMap);}//组装表格列表数据List<Map<String,Object>> detailList=new ArrayList<Map<String,Object>>();for (int i = 0; i < 3; i++) {Map<String,Object> detailMap = new HashMap<String, Object>();detailMap.put("index", i+1);//序号if(i == 0 || i == 1){detailMap.put("product_type", "二级分类1");//商品二级分类}else{detailMap.put("product_type", "二级分类2");//商品二级分类}detailMap.put("title", "商品"+i);//商品名称detailMap.put("product_description", "套");//商品规格detailMap.put("buy_num", 3+i);//销售数量detailMap.put("saleprice", 100+i);//销售价格detailMap.put("technical_parameter", "技术参数"+i);//技术参数detailList.add(detailMap);}List<Map<String,Object>> tList=new ArrayList<Map<String,Object>>();Map<String,Object> tMap = new HashMap<String, Object>();tMap.put("index", 1);tMap.put("sub_type", "监督技术装备");tMap.put("detailList", detailList);tMap.put("buy_price", 100);tList.add(tMap);tMap = new HashMap<String, Object>();tMap.put("index", 2);tMap.put("sub_type", "火灾调查装备");tMap.put("detailList", detailList);tMap.put("buy_price", 200);tList.add(tMap);tMap = new HashMap<String, Object>();tMap.put("index", 3);tMap.put("sub_type", "工程验收装备");tMap.put("detailList", detailList);tMap.put("buy_price", 300);tList.add(tMap);//总金额String order_money=String.valueOf(money);//金额中文大写String money_total = MoneyUtils.change(money);//word模板地址获取方式一:缺点---打jar包获取不到该路径
//          String basePath=ClassUtils.getDefaultClassLoader().getResource("").getPath()+"static/template/";
//          String resource =basePath+"order2.docx";//word模板地址//word模板地址获取方式二:优点---相比上一种方式,这种方法不会在linux或者jar上失效ClassPathResource classPathResource = new ClassPathResource("static/template/order2.docx");String resource = classPathResource.getURL().getPath();//渲染表格  动态行HackLoopTableRenderPolicy  policy = new HackLoopTableRenderPolicy();Configure config = Configure.newBuilder().bind("typeList", policy).bind("detailList", policy).build();XWPFTemplate template = XWPFTemplate.compile(resource, config).render(new HashMap<String, Object>() {{put("typeList", typeList);put("typeProducts",tList);put("order_number", "2356346346645");put("y", now.get(Calendar.YEAR));//当前年put("m", (now.get(Calendar.MONTH) + 1));//当前月put("d", now.get(Calendar.DAY_OF_MONTH));//当前日put("order_money",order_money);//总金额put("money_total",money_total);//金额中文大写}});//=================生成文件保存在本地D盘某目录下=================String temDir="D:/mimi/"+File.separator+"file/word/"; ;//生成临时文件存放地址//生成文件名Long time = new Date().getTime();// 生成的word格式String formatSuffix = ".docx";// 拼接后的文件名String fileName = time + formatSuffix;//文件名  带后缀FileOutputStream fos = new FileOutputStream(temDir+fileName);template.write(fos);//=================生成word到设置浏览默认下载地址=================// 设置强制下载不打开response.setContentType("application/force-download");// 设置文件名response.addHeader("Content-Disposition", "attachment;fileName=" + fileName);OutputStream out = response.getOutputStream();template.write(out);out.flush();out.close();template.close();} catch (Exception e) {e.printStackTrace();}}

(3)页面编写调用方法

<div class="m2" style="margin-top: 30px;">使用<span class="s1">POI-tl</span>根据word模板动态生成word(包含动态行表格、循环列表下动态行表格)</div><a href="#" class="easyui-linkbutton" onclick="doExportWord4();" data-options="iconCls:'icon-save'">导出word(包含动态行表格、循环列表下动态行表格)</a>
//方式一导出word(包含动态行表格、循环列表中的动态行表格)function doExportWord4(){window.location.href="<%=basePath%>/auth/exportWord/exportDataWord4";}

(4)导出结果:


功能3:导出合并单元格(一个列表下的合并行)

示例中:
比较复杂的表格,一个二级分类下,有多个商品。由7列组成,行数不定。

默认表格数据模型(MiniTableRenderData)实现了最基本的样式,当需求中的表格更加复杂的时候,我们完全可以设计好那些固定的部分,将需要动态渲染的部分单元格交给自定义模板渲染策略。

poi-tl提供了抽象表格策略DynamicTableRenderPolicy来实现这样的功能,{{detail_table}}标签可以在表格内的任意单元格内,DynamicTableRenderPolicy会获取XWPFTable对象进而获得操作整个表格的能力。

(1)新建一个word(order4.docx),编写word模板:

设置{{detail_table}}为自定义模板渲染策略(继承抽象表格策略DynamicTableRenderPolicy),自定义已有表格中部分单元格的渲染。

(2)代码实现:

新建渲染策略DetailTablePolicy2,继承于抽象表格策略:

package com.example.word.common.mergeCell2;import java.util.List;
import java.util.Map;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import com.deepoove.poi.data.RowRenderData;
import com.deepoove.poi.policy.DynamicTableRenderPolicy;
import com.deepoove.poi.policy.MiniTableRenderPolicy;
import com.deepoove.poi.util.TableTools;public class DetailTablePolicy2 extends DynamicTableRenderPolicy {// 填充数据所在行数int listsStartRow = 1;@Overridepublic void render(XWPFTable table, Object data) {if (null == data) return;DetailData2 detailData = (DetailData2) data;// 商品订单详情列表数据 循环渲染List<RowRenderData> lists = detailData.getPlists();// 二级分类分组统计商品个数数据List<Map<String,Object>> tlists = detailData.getTlists();if (null != lists) {table.removeRow(listsStartRow);// 循环插入行for (int i = lists.size()-1; i >=0; i--) {XWPFTableRow insertNewTableRow = table.insertNewTableRow(listsStartRow);for (int j = 0; j < 7; j++)insertNewTableRow.createCell();// 渲染单行商品订单详情数据MiniTableRenderPolicy.Helper.renderRow(table, listsStartRow, lists.get(i));}//处理合并for (int i=0;i<lists.size();i++) {Object v =lists.get(i).getCells().get(1).getCellText();String type_name=String.valueOf(v);for(int j=0;j<tlists.size();j++){String typeName = String.valueOf(tlists.get(j).get("typeName"));Integer listSize = Integer.parseInt(String.valueOf(tlists.get(j).get("listSize")));if(type_name.equals(typeName)){// 合并第1列的第i+1行到第i+listSize行的单元格TableTools.mergeCellsVertically(table, 1, i+1, i+listSize);//处理垂直居中for (int y = 1; y < 7; y++){XWPFTableCell cell = table.getRow(i+1).getCell(y);cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER); //垂直居中}tlists.remove(j);break;}}System.out.println(v);}}}
}

DetailData2:

package com.example.word.common.mergeCell2;import java.util.List;
import java.util.Map;import com.deepoove.poi.data.RowRenderData;public class DetailData2 {// 商品订单详情列表数据private List<RowRenderData> plists;// 二级分类分组统计商品个数数据private List<Map<String,Object>> tlists;public List<RowRenderData> getPlists() {return plists;}public void setPlists(List<RowRenderData> plists) {this.plists = plists;}public List<Map<String,Object>> getTlists() {return tlists;}public void setTlists(List<Map<String,Object>> tlists) {this.tlists = tlists;}}

PaymentData2:

package com.example.word.common.mergeCell2;import com.deepoove.poi.el.Name;public class PaymentData2 {@Name("detail_table")private DetailData2 detailTable;private String total;public void setDetailTable(DetailData2 detailTable) {this.detailTable = detailTable;}public DetailData2 getDetailTable() {return this.detailTable;}public String getTotal() {return total;}public void setTotal(String total) {this.total = total;}}

在ExportWordController类中,编写相应的导出方法,供页面请求:

/*** 销售订单信息导出word --- poi-tl(合并单元格(一个列表下的合并行)--商品订单明细)* @throws IOException */@RequestMapping("/exportDataWord6")public void exportDataWord6(HttpServletRequest request,HttpServletResponse response) throws IOException{try {Map<String, Object> params = new HashMap<>();// TODO 渲染其他类型的数据请参考官方文档//word模板地址获取方式一:缺点---打jar包获取不到该路径
//          String basePath=ClassUtils.getDefaultClassLoader().getResource("").getPath()+"static/template/";
//          String resource =basePath+"order4.docx";//word模板地址//word模板地址获取方式二:优点---相比上一种方式,这种方法不会在linux或者jar上失效ClassPathResource classPathResource = new ClassPathResource("static/template/order4.docx");String resource = classPathResource.getURL().getPath();PaymentData2 datas = new PaymentData2();TableStyle rowStyle = new TableStyle();rowStyle = new TableStyle();rowStyle.setAlign(STJc.CENTER);DetailData2 detailTable = new DetailData2();List<RowRenderData> plists =new ArrayList<RowRenderData>();for(int i=0;i<6;i++){String typeName="二级分类1";if(i == 3 || i == 4){typeName="二级分类2";}else if(i == 5){typeName="二级分类3";}String index = String.valueOf(i+1);RowRenderData plist = RowRenderData.build(index, typeName, "商品"+i, "套", "2","100","技术参数"+i);plist.setRowStyle(rowStyle);plists.add(plist);}//二级分类 分组统计   商品个数List<Map<String,Object>> tlists = new ArrayList<Map<String,Object>>();Map<String,Object> map = new HashMap<String, Object>();map.put("typeName", "二级分类1");map.put("listSize", "3");tlists.add(map);map = new HashMap<String, Object>();map.put("typeName", "二级分类2");map.put("listSize", "2");tlists.add(map);map = new HashMap<String, Object>();map.put("typeName", "二级分类3");map.put("listSize", "1");tlists.add(map);detailTable.setPlists(plists);detailTable.setTlists(tlists);datas.setDetailTable(detailTable);datas.setTotal("1000");Configure config = Configure.newBuilder().bind("detail_table", new DetailTablePolicy2()).build();XWPFTemplate template = XWPFTemplate.compile(resource, config).render(datas);//=================生成文件保存在本地D盘某目录下=================String temDir="D:/mimi/"+File.separator+"file/word/"; ;//生成临时文件存放地址//生成文件名Long time = new Date().getTime();// 生成的word格式String formatSuffix = ".docx";// 拼接后的文件名String fileName = time + formatSuffix;//文件名  带后缀FileOutputStream fos = new FileOutputStream(temDir+fileName);template.write(fos);//=================生成word到设置浏览默认下载地址=================// 设置强制下载不打开response.setContentType("application/force-download");// 设置文件名response.addHeader("Content-Disposition", "attachment;fileName=" + fileName);OutputStream out = response.getOutputStream();template.write(out);out.flush();out.close();template.close();} catch (Exception e) {e.printStackTrace();}}

注意: @Name(“detail_table”) 是必须的,不然word表格无法渲染, name可以自定义,要和 模板的一致

(3)页面编写调用方法

<div class="m2" style="margin-top: 30px;">使用<span class="s1">POI-tl</span>根据word模板动态生成word(合并单元格2)</div>
<a href="#" class="easyui-linkbutton" onclick="doExportWord6();" data-options="iconCls:'icon-save'">导出word(合并单元格(一个列表下的合并行)--商品订单明细)</a>
<div style="font-size: 13px;color:#cccccc">如:合并第1列的第1行到第3行的单元格</div>
//方式一导出word(合并单元格(一个列表下的合并行)--商品订单明细))function doExportWord6(){window.location.href="<%=basePath%>/auth/exportWord/exportDataWord6";}

(4)导出结果:

功能4:导出循环列表下合并单元格(循环列表下的合并行)

在功能3的基础上做修改:

(1)新建一个word(order5.docx),编写word模板:

(2)代码实现:

复用 功能3中的合并处理类,修改PaymentData2.java类,添加 typeLists变量存储循环列表(@Name(“typeLists”)用于表格渲染,不能省略):

package com.example.word.common.mergeCell2;import java.util.List;
import java.util.Map;import com.deepoove.poi.el.Name;public class PaymentData2 {@Name("detail_table")private DetailData2 detailTable;@Name("typeLists")private List<Map<String,Object>> typeLists;//所属大类统计列表private String total;public void setDetailTable(DetailData2 detailTable) {this.detailTable = detailTable;}public DetailData2 getDetailTable() {return this.detailTable;}public String getTotal() {return total;}public void setTotal(String total) {this.total = total;}public List<Map<String, Object>> getTypeLists() {return typeLists;}public void setTypeLists(List<Map<String, Object>> typeLists) {this.typeLists = typeLists;}}

在ExportWordController类中,编写相应的导出方法,供页面请求:

 /*** 销售订单信息导出word --- poi-tl(合并单元格(循环列表下的合并行)--商品订单明细)* @throws IOException */@RequestMapping("/exportDataWord7")public void exportDataWord7(HttpServletRequest request,HttpServletResponse response) throws IOException{try {Map<String, Object> params = new HashMap<>();// TODO 渲染其他类型的数据请参考官方文档//word模板地址获取方式一:缺点---打jar包获取不到该路径
//          String basePath=ClassUtils.getDefaultClassLoader().getResource("").getPath()+"static/template/";
//          String resource =basePath+"order5.docx";//word模板地址//word模板地址获取方式二:优点---相比上一种方式,这种方法不会在linux或者jar上失效ClassPathResource classPathResource = new ClassPathResource("static/template/order5.docx");String resource = classPathResource.getURL().getPath();PaymentData2 datas = new PaymentData2();TableStyle rowStyle = new TableStyle();rowStyle = new TableStyle();rowStyle.setAlign(STJc.CENTER);//组装循环体List<Map<String,Object>> typeLists = new ArrayList<Map<String,Object>>();for(int x=0;x<3;x++){DetailData2 detailTable = new DetailData2();List<RowRenderData> plists =new ArrayList<RowRenderData>();for(int i=0;i<6;i++){String typeName="二级分类1"+x;if(i == 3 || i == 4){typeName="二级分类2"+x;}else if(i == 5){typeName="二级分类3"+x;}String index = String.valueOf(i+1);RowRenderData plist = RowRenderData.build(index, typeName, "商品"+i, "套", "2","100","技术参数"+i);plist.setRowStyle(rowStyle);plists.add(plist);}//二级分类 分组统计   商品个数List<Map<String,Object>> tlists = new ArrayList<Map<String,Object>>();Map<String,Object> map = new HashMap<String, Object>();map.put("typeName", "二级分类1"+x);map.put("listSize", "3");tlists.add(map);map = new HashMap<String, Object>();map.put("typeName", "二级分类2"+x);map.put("listSize", "2");tlists.add(map);map = new HashMap<String, Object>();map.put("typeName", "二级分类3"+x);map.put("listSize", "1");tlists.add(map);detailTable.setPlists(plists);detailTable.setTlists(tlists);Map<String,Object> data= new HashMap<String, Object>();data.put("detail_table", detailTable);data.put("sub_type", "大类"+x);data.put("total_price", 100+x);typeLists.add(data);}datas.setTypeLists(typeLists);Configure config = Configure.newBuilder().bind("detail_table", new DetailTablePolicy2()).build();XWPFTemplate template = XWPFTemplate.compile(resource, config).render(datas);//=================生成文件保存在本地D盘某目录下=================String temDir="D:/mimi/"+File.separator+"file/word/"; ;//生成临时文件存放地址//生成文件名Long time = new Date().getTime();// 生成的word格式String formatSuffix = ".docx";// 拼接后的文件名String fileName = time + formatSuffix;//文件名  带后缀FileOutputStream fos = new FileOutputStream(temDir+fileName);template.write(fos);//=================生成word到设置浏览默认下载地址=================// 设置强制下载不打开response.setContentType("application/force-download");// 设置文件名response.addHeader("Content-Disposition", "attachment;fileName=" + fileName);OutputStream out = response.getOutputStream();template.write(out);out.flush();out.close();template.close();} catch (Exception e) {e.printStackTrace();}}

(3)页面编写调用方法

<div class="m2" style="margin-top: 30px;">使用<span class="s1">POI-tl</span>根据word模板动态生成word(循环列表下的动态行表格以及合并单元格)</div>
<a href="#" class="easyui-linkbutton" onclick="doExportWord7();" data-options="iconCls:'icon-save'">导出word(合并单元格(循环列表下的合并行)--商品订单明细)</a>
 //方式一导出word(合并单元格(循环列表下的合并行)--商品订单明细)function doExportWord7(){window.location.href="<%=basePath%>/auth/exportWord/exportDataWord7";}

(4)导出结果:




功能5:导出循环列表下合并单元格、外加一个动态行表格

(1)新建一个word(order6.docx),编写word模板:


(2)代码实现:

功能4中已经编写了循环列表合并处理,见上述。 讲解下如何在循环列表合并的基础上,再加上一个动态行表格:

①新增DetailTablePolicy4用于 另加的动态行表格的插入与渲染:

package com.example.word.common.mergeCell3;import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STJc;import com.deepoove.poi.data.RowRenderData;
import com.deepoove.poi.data.style.TableStyle;
import com.deepoove.poi.policy.DynamicTableRenderPolicy;
import com.deepoove.poi.policy.MiniTableRenderPolicy;
import com.deepoove.poi.util.TableTools;/*** 商品所属大类统计 表格动态行插入、渲染、合并单元格处理* @author Administrator**/
public class DetailTablePolicy4 extends DynamicTableRenderPolicy {// 填充数据所在行数int listsStartRow = 1;@Overridepublic void render(XWPFTable table, Object data) {if (null == data) return;//文本居中TableStyle rowStyle = new TableStyle();rowStyle = new TableStyle();rowStyle.setAlign(STJc.CENTER);List<RowRenderData> lists = new ArrayList<RowRenderData>();//所属大类列表数据List<Map<String,Object>> typeLists = (List<Map<String, Object>>) data;for(Map<String,Object> map:typeLists){String index =String.valueOf(map.get("index")); String sub_type =String.valueOf(map.get("sub_type")); String total_price =String.valueOf(map.get("total_price")); RowRenderData tlist = RowRenderData.build(index, sub_type, total_price,total_price);tlist.setRowStyle(rowStyle);lists.add(tlist);}if (null != lists) {table.removeRow(listsStartRow);// 循环插入行for (int i = lists.size()-1; i >=0; i--) {XWPFTableRow insertNewTableRow = table.insertNewTableRow(listsStartRow);for (int j = 0; j < 4; j++)insertNewTableRow.createCell();// 渲染单行所属大类数据MiniTableRenderPolicy.Helper.renderRow(table, listsStartRow, lists.get(i));}}}
}

②PaymentData2类新增两个变量:

    private String order_money;//订单总金额private String money_total;//订单总金额的中文大写

③导出方法修改
在功能4的导出方法做如下修改:

导出方法完整代码:

 /*** 销售订单信息导出word --- poi-tl(合并单元格(循环列表下的合并行)--商品订单明细、另加一个动态行表格)* @throws IOException */@RequestMapping("/exportDataWord8")public void exportDataWord8(HttpServletRequest request,HttpServletResponse response) throws IOException{try {Map<String, Object> params = new HashMap<>();// TODO 渲染其他类型的数据请参考官方文档//word模板地址获取方式一:缺点---打jar包获取不到该路径
//          String basePath=ClassUtils.getDefaultClassLoader().getResource("").getPath()+"static/template/";
//          String resource =basePath+"order6.docx";//word模板地址//word模板地址获取方式二:优点---相比上一种方式,这种方法不会在linux或者jar上失效ClassPathResource classPathResource = new ClassPathResource("static/template/order6.docx");String resource = classPathResource.getURL().getPath();PaymentData2 datas = new PaymentData2();TableStyle rowStyle = new TableStyle();rowStyle = new TableStyle();rowStyle.setAlign(STJc.CENTER);//组装循环体List<Map<String,Object>> typeLists = new ArrayList<Map<String,Object>>();List<Map<String,Object>> typeTotalList = new ArrayList<Map<String,Object>>();for(int x=0;x<3;x++){DetailData2 detailTable = new DetailData2();List<RowRenderData> plists =new ArrayList<RowRenderData>();for(int i=0;i<6;i++){String typeName="二级分类1"+x;if(i == 3 || i == 4){typeName="二级分类2"+x;}else if(i == 5){typeName="二级分类3"+x;}String index = String.valueOf(i+1);RowRenderData plist = RowRenderData.build(index, typeName, "商品"+i, "套", "2","100","技术参数"+i);plist.setRowStyle(rowStyle);plists.add(plist);}//二级分类 分组统计   商品个数List<Map<String,Object>> tlists = new ArrayList<Map<String,Object>>();Map<String,Object> map = new HashMap<String, Object>();map.put("typeName", "二级分类1"+x);map.put("listSize", "3");tlists.add(map);map = new HashMap<String, Object>();map.put("typeName", "二级分类2"+x);map.put("listSize", "2");tlists.add(map);map = new HashMap<String, Object>();map.put("typeName", "二级分类3"+x);map.put("listSize", "1");tlists.add(map);detailTable.setPlists(plists);detailTable.setTlists(tlists);Map<String,Object> data= new HashMap<String, Object>();data.put("detail_table", detailTable);data.put("index", x+1);data.put("sub_type", "大类"+x);data.put("total_price", 100+x);typeLists.add(data);}datas.setTypeLists(typeLists);datas.setOrder_money("100");datas.setMoney_total("壹佰元整");Configure config = Configure.newBuilder().bind("detail_table", new DetailTablePolicy2()).bind("typeLists", new DetailTablePolicy4()).build();XWPFTemplate template = XWPFTemplate.compile(resource, config).render(datas);//=================生成文件保存在本地D盘某目录下=================String temDir="D:/mimi/"+File.separator+"file/word/"; ;//生成临时文件存放地址//生成文件名Long time = new Date().getTime();// 生成的word格式String formatSuffix = ".docx";// 拼接后的文件名String fileName = time + formatSuffix;//文件名  带后缀FileOutputStream fos = new FileOutputStream(temDir+fileName);template.write(fos);//=================生成word到设置浏览默认下载地址=================// 设置强制下载不打开response.setContentType("application/force-download");// 设置文件名response.addHeader("Content-Disposition", "attachment;fileName=" + fileName);OutputStream out = response.getOutputStream();template.write(out);out.flush();out.close();template.close();} catch (Exception e) {e.printStackTrace();}}

(3)页面编写调用方法

<div class="m2" style="margin-top: 30px;">使用<span class="s1">POI-tl</span>根据word模板动态生成word(循环列表下的动态行表格以及合并单元格)</div>
<a href="#" class="easyui-linkbutton" onclick="doExportWord8();" data-options="iconCls:'icon-save'">导出word(合并单元格(循环列表下的合并行)--商品订单明细、另加一个动态行表格)</a>
//方式一导出word(合并单元格(循环列表下的合并行)--商品订单明细、另加一个动态行表格)
function doExportWord8(){window.location.href="<%=basePath%>/auth/exportWord/exportDataWord8";
}

(4)导出结果:



三、完整代码

点击此处获取

SpringBoot+Poi-tl根据Word模板动态生成word(含动态行表格、合并单元格)相关推荐

  1. 使用POI创建word表格合并单元格兼容wps

    poi创建word表格合并单元格代码如下: /** * @Description: 跨列合并 */ public void mergeCellsHorizontal(XWPFTable table, ...

  2. 关于JAVA POI解析WPS docx文档中的table(复杂表格包含单元格横向,纵向的合并)

    关于JAVA POI解析WPS docx文档中的table(复杂表格包含单元格横向,纵向的合并) 首先,关于poi解析表格先阅读一篇他人的博客 使用poi读取word2007(.docx)中的复杂表格 ...

  3. poi生成word特殊表格合并单元格,wps不兼容问题

    百度了半天没百度出来解决的问题,可能是poi技术就是不支持吧.所以我用了其他思想让他兼容. 先说点废话: 我们用的技术时poi框架  这个框架是有微软office兼容的,但是他对wps以及其他的工具还 ...

  4. springboot中使用poi-tl导出word(包含表格合并单元格)实例

    一.背景 在业务开发过程中,遇到有需要生成包含表格的word文档,且一部分表格需要动态生成,且需要根据数据来合并单元格,最后呈现的方式如下图: 一开始想到的解决方案是通过freemarker来生成,但 ...

  5. C# 操作word表格合并单元格

    C# 操作word表格 遇到合并单元格的时候,假设表格是3行6列 newTable.Cell(1, 1).Merge(newTable.Cell(1, 3));//合并第1行第1列到横向单元格合并,使 ...

  6. python 批量打印文档_使用python将Excel数据填充Word模板并生成Word

    [项目需求] Excel中有一万多条学生学平险数据,需要给每位学生打印购买回执单,回执单包括学生姓名,身份证号,学校等信息,目前只能从Excel拷贝数据到Word模板中,然后打印,效率及其低下,寻求帮 ...

  7. Word模板设计时,如何让照片填满单元格

    出处:http://u13382036813.blog.163.com/blog/static/128966032200910268114547/ 2009-09-11 20:30:04|  分类: ...

  8. java word模板poi生成文件_poi读写word模板 / java生成word文档

    有一word文档表格 形如: 姓名 ${name} 电话 ${tel} 下载包链接:点击进入 从数据库读取记录替换上述变量 import java.io.FileOutputStream; impor ...

  9. 关于Angular Js动态表格合并单元格的一点见解

    记第一篇笔记  hell OwO rld          最近公司有一点点小需求,做个另类的表格,要求动态的样式(PS:不能直接写死那种),没办法打工人只能硬着头皮去干.         网上传的一 ...

  10. layui表格合并单元格多表_layui动态表格之合并单元格

    需求: 下面用excel表格大概模拟下需求,左边是原来的,要改成右边这样的: ①第一步:再生成表格后调用此方法,以合并重复的单元格done : function(res, curr, count) { ...

最新文章

  1. Spring中使用缓存时你应该知道的知识
  2. 计算机硬件Word,[计算机硬件及网络]word的操作.doc
  3. 开发经验分享_02_解决问题3步走(实战)
  4. 第 20 章 观察者模式
  5. 在Linux上显示某个进程的线程的几种方式
  6. python关键词共现图谱_Python简单实战项目:《冰与火之歌1-5》角色关系图谱构建——人物关系可视化...
  7. 微软更新Win10工具Media Creation Tool
  8. excel-按条件向下填充
  9. 物联网与嵌入式系统的关系
  10. 坚果云服务器地址,#网盘每日小技巧分享# 坚果云API是什么?
  11. 简易的安卓天气app(四)——搜索城市、完善页面
  12. 卓一电子 智能防雷定时插座 ZYT21时控开关 定时功能设置说明书
  13. Excel学习日记:L8-工作表的设定与多个工作表合并计算
  14. 学电子信息工程,出路在哪里?
  15. 印光大师、净空法师:法师、居士示现神通需注意哪些事项?
  16. 服务器主机玩游戏性能如何,用服务器主机玩游戏怎么样
  17. win11任务栏图标闪烁|任务栏QQ图标闪动|新消息任务栏自动弹出|设置自动隐藏任务栏之后,QQ或微信等工具新消息自动弹出任务栏并颜色提示问题解决方案
  18. 计算机毕业论文有必要建模吗,本科生真有必要写毕业论文吗
  19. 重新审视Visio的本质
  20. OM | 运筹学在医疗运营管理中的应用

热门文章

  1. 【转】windows server 2008 R2如何安装Intel网卡驱动
  2. 如何对Windows剪切板里的内容进行取证分析 Windows剪切板取证
  3. Linux系统安装ffmpeg + h264视频编码
  4. 2021年上半年信息系统项目管理师真题与答案完整版(综合知识、案例分析、论文)
  5. 如何写公有云月度运维报告?
  6. Microsoft Visual C++下载,VC++下载
  7. 推荐几个程序员最爱用的Java学习网站!
  8. ArcGIS教程:Zonal相关的工作原理及实例
  9. windows 2008 终端服务器配置,Windows Server 2008搭建终端服务器
  10. 引用计算机写源码,C#读写EXCEL源码提示“office检测到此文件存在一个问题。为帮助保护您的计算机,不能打开此文件。 ”的解决...