SpringBoot+Poi-tl根据Word模板动态生成word(含动态行表格、合并单元格)
本编文章继SpringBoot+Poi-tl根据Word模板动态生成word(含动态行表格)文章之后介绍Poi-tl导出word的延伸功能:所需依赖以及word模板所属位置 见 SpringBoot+Poi-tl根据Word模板动态生成word(含动态行表格),这里不再累赘。直接介绍延伸功能的实现。一、延伸功能功能1:导出多个动态行表格(固定个数)功能2:导出循环列表下的动态行表格(个数不固定)功
本编文章继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;
@Override
public 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;
@Override
public 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)导出结果:
三、完整代码
点击此处获取
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)