欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-03-10 17:13:01
本编文章继SpringBoot+Poi-tl根据Word模板动态生成word(含动态行表格)文章之后介绍Poi-tl导出word的延伸功能:所需依赖以及word模板所属位置 见 SpringBoot+Poi-tl根据Word模板动态生成word(含动态行表格),这里不再累赘。直接介绍延伸功能的实现。一、延伸功能功能1:导出多个动态行表格(固定个数)功能2:导出循环列表下的动态行表格(个数不固定)功能3:导出合并单元格功能4:导出循环列表下合并单元格二、功能实现功能1:导出多个动态行表格(...

本编文章继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模板:

SpringBoot+Poi-tl根据Word模板动态生成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);
			
			String basePath=ClassUtils.getDefaultClassLoader().getResource("").getPath()+"static/template/";
			String resource =basePath+"orderD2.docx";//word模板地址
			//渲染表格  动态行
			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)导出结果:

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

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

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

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

SpringBoot+Poi-tl根据Word模板动态生成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);
			
			String basePath=ClassUtils.getDefaultClassLoader().getResource("").getPath()+"static/template/";
			String resource =basePath+"order2.docx";//word模板地址
			//渲染表格  动态行
			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)导出结果:

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

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

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

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

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

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

SpringBoot+Poi-tl根据Word模板动态生成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 渲染其他类型的数据请参考官方文档
			
			String basePath=ClassUtils.getDefaultClassLoader().getResource("").getPath()+"static/template/";
			String resource =basePath+"order4.docx";//word模板地址
			
			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可以自定义,要和 模板的一致
SpringBoot+Poi-tl根据Word模板动态生成word(含动态行表格、合并单元格)

(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)导出结果:

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

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

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

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

SpringBoot+Poi-tl根据Word模板动态生成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 渲染其他类型的数据请参考官方文档
			
			String basePath=ClassUtils.getDefaultClassLoader().getResource("").getPath()+"static/template/";
			String resource =basePath+"order5.docx";//word模板地址
			
			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)导出结果:

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

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

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

SpringBoot+Poi-tl根据Word模板动态生成word(含动态行表格、合并单元格)
SpringBoot+Poi-tl根据Word模板动态生成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的导出方法做如下修改:
SpringBoot+Poi-tl根据Word模板动态生成word(含动态行表格、合并单元格)

导出方法完整代码:

	
	/**
	 * 销售订单信息导出word --- poi-tl(合并单元格(循环列表下的合并行)--商品订单明细、另加一个动态行表格)
	 * @throws IOException 
	 */
	@RequestMapping("/exportDataWord8")
	public void exportDataWord8(HttpServletRequest request,HttpServletResponse response) throws IOException{
		try {
			Map<String, Object> params = new HashMap<>();
			
			// TODO 渲染其他类型的数据请参考官方文档
			
			String basePath=ClassUtils.getDefaultClassLoader().getResource("").getPath()+"static/template/";
			String resource =basePath+"order6.docx";//word模板地址
			
			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(含动态行表格、合并单元格)
SpringBoot+Poi-tl根据Word模板动态生成word(含动态行表格、合并单元格)
SpringBoot+Poi-tl根据Word模板动态生成word(含动态行表格、合并单元格)

三、完整代码

点击此处获取

本文地址:https://blog.csdn.net/qq_26383975/article/details/112238802

相关标签: SpringBoot java