精华内容
下载资源
问答
  • java POI对word中的表格动态插入固定数据,以及插入具体的数据 遇到个项目本来是用Execl导出的,相对简单,客户要求用Word导出,并按照他们给的模板进行导出; 从网上百度了一下,然后自己修改下,实现了对word中...

    java POI对word中的表格动态插入固定数据,以及插入不具体的数据

    遇到个项目本来是用Execl导出的,相对简单,客户要求用Word导出,并按照他们给的模板进行导出;
    从网上百度了一下,然后自己修改下,实现了对word中的同一张表格同时进行通过key替换操作,以及从特定的行开始插入数据,根据是需要插入的数据自动增加行等;下面直接上主要代码,都有注释。

    maven依赖包引入

    <dependency>
    	<groupId>org.apache.poi</groupId>
    	<artifactId>poi-ooxml</artifactId>
    </dependency>
    

    工具类

    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Map.Entry;
    import java.util.Set;
    
    import org.apache.poi.POIXMLDocument;
    import org.apache.poi.xwpf.usermodel.XWPFDocument;
    import org.apache.poi.xwpf.usermodel.XWPFParagraph;
    import org.apache.poi.xwpf.usermodel.XWPFRun;
    import org.apache.poi.xwpf.usermodel.XWPFTable;
    import org.apache.poi.xwpf.usermodel.XWPFTableCell;
    import org.apache.poi.xwpf.usermodel.XWPFTableRow;
    
    public class WordUtil {
    	
    	
        /**
         * 根据模板生成新word文档
         * 对表格是进行替换以及插入
         * @param inputUrl 模板存放地址
         * @param outPutUrl 新文档存放地址
         * @param textMap 需要替换的信息集合 
         * @param tableList 需要插入的表格信息集合
         * @return 成功返回true,失败返回false
         */
        public static boolean changWord(String inputUrl, String outputUrl,
                Map<String, String> textMap, List<String[]> tableList) {
            //模板转换默认成功
            boolean changeFlag = true;
            try {
                //获取docx解析对象
                XWPFDocument document = new XWPFDocument(POIXMLDocument.openPackage(inputUrl));
                //解析替换文本段落对象
                WordUtil.changeText(document, textMap);
                //解析替换表格对象
                WordUtil.changeTable(document, textMap, tableList);
                
                //生成新的word
                File file = new File(outputUrl);
                FileOutputStream stream = new FileOutputStream(file);
                document.write(stream);
                stream.close();
            } catch (IOException e) {
                e.printStackTrace();
                changeFlag = false;
            }
            return changeFlag;
    
        }
    
        /**
         * 替换段落文本
         * @param document docx解析对象
         * @param textMap 需要替换的信息集合
         */
        public static void changeText(XWPFDocument document, Map<String, String> textMap){
            //获取段落集合
            List<XWPFParagraph> paragraphs = document.getParagraphs();
            
            for (XWPFParagraph paragraph : paragraphs) {
                //判断此段落时候需要进行替换
                String text = paragraph.getText();
                if(checkText(text)){
                    List<XWPFRun> runs = paragraph.getRuns();
                    for (XWPFRun run : runs) {
                        //替换模板原来位置
                        run.setText(changeValue(run.toString(), textMap),0);
                    }
                }
            }
            
        }
        
        /**
         * 替换表格对象方法
         * @param document docx解析对象
         * @param textMap 需要替换的信息集合
         * @param tableList 需要插入的表格信息集合
         */
        public static void changeTable(XWPFDocument document, Map<String, String> textMap,
                List<String[]> tableList){
            //获取表格对象集合
            List<XWPFTable> tables = document.getTables();
            //获取第一个表格   根据实际模板情况 决定去第几个word中的表格
            XWPFTable table = tables.get(0);
            
            //表格中的内容替换
            List<XWPFTableRow> rows = table.getRows();
            eachTable(rows, textMap);//遍历表格,并替换模板
            
            //向特定位置 行插入数据
            insertTable(table, tableList);
        }
        
        /**
         * 遍历表格
         * @param rows 表格行对象
         * @param textMap 需要替换的信息集合
         */
        public static void eachTable(List<XWPFTableRow> rows ,Map<String, String> textMap){
            for (XWPFTableRow row : rows) {
                List<XWPFTableCell> cells = row.getTableCells();
                for (XWPFTableCell cell : cells) {
                    //判断单元格是否需要替换
                    if(checkText(cell.getText())){
                        List<XWPFParagraph> paragraphs = cell.getParagraphs();
                        for (XWPFParagraph paragraph : paragraphs) {
                            List<XWPFRun> runs = paragraph.getRuns();
                            for (XWPFRun run : runs) {
                                run.setText(changeValue(run.toString(), textMap),0);
                            }
                        }
                    }
                }
            }
        }
        
        /**
         * 为表格插入数据,行数不够添加新行
         * @param table 需要插入数据的表格
         * @param tableList 插入数据集合
         */
        public static void insertTable(XWPFTable table, List<String[]> tableList){
            //创建行,根据需要插入的数据添加新行,不处理表头
        	//判断需要插入的数量
        	if (tableList.size() > 5) {//我的模板预留了五行
        		for (int i=0;i<tableList.size()-4;i++) {
        			insertRow(table,10,14);
        		}
    		} 
            //遍历表格插入数据
            List<XWPFTableRow> rows = table.getRows();
            for(int i = 9; i < tableList.size() + 9; i++){
                XWPFTableRow newRow = table.getRow(i);
                List<XWPFTableCell> cells = newRow.getTableCells();
                for(int j = 0; j < cells.size(); j++){
                    XWPFTableCell cell = cells.get(j);
                    cell.setText(tableList.get(i-9)[j]);
                }
            }
            
        }
        
        /**
         * 判断文本中时候包含$
         * @param text 文本
         * @return 包含返回true,不包含返回false
         */
        public static boolean checkText(String text){
            boolean check  =  false;
            if(text.indexOf("$")!= -1){
                check = true;
            }
            return check;
            
        }
    	/**
    	 * insertRow 在word表格中指定位置插入一行,并将某一行的样式复制到新增行
    	 * @param copyrowIndex 需要复制的行位置
    	 * @param newrowIndex 需要新增一行的位置
    	 * */
    	public static void insertRow(XWPFTable table, int copyrowIndex, int newrowIndex) {
    		// 在表格中指定的位置新增一行
    		XWPFTableRow targetRow = table.insertNewTableRow(newrowIndex);
    		// 获取需要复制行对象
    		XWPFTableRow copyRow = table.getRow(copyrowIndex);
    		//复制行对象
    		targetRow.getCtRow().setTrPr(copyRow.getCtRow().getTrPr());
    		//或许需要复制的行的列
    		List<XWPFTableCell> copyCells = copyRow.getTableCells();
    		//复制列对象
    		XWPFTableCell targetCell = null;
    		for (int i = 0; i < copyCells.size(); i++) {
    			XWPFTableCell copyCell = copyCells.get(i);
    			targetCell = targetRow.addNewTableCell();
    			targetCell.getCTTc().setTcPr(copyCell.getCTTc().getTcPr());
    			if (copyCell.getParagraphs() != null && copyCell.getParagraphs().size() > 0) {
    				targetCell.getParagraphs().get(0).getCTP().setPPr(copyCell.getParagraphs().get(0).getCTP().getPPr());
    				if (copyCell.getParagraphs().get(0).getRuns() != null
    						&& copyCell.getParagraphs().get(0).getRuns().size() > 0) {
    					XWPFRun cellR = targetCell.getParagraphs().get(0).createRun();
    					cellR.setBold(copyCell.getParagraphs().get(0).getRuns().get(0).isBold());
    				} 
    			} 
    		}
    		
    	}
        /**
         * 匹配传入信息集合与模板
         * @param value 模板需要替换的区域
         * @param textMap 传入信息集合
         * @return 模板需要替换区域信息集合对应值
         */
        public static String changeValue(String value, Map<String, String> textMap){
            Set<Entry<String, String>> textSets = textMap.entrySet();
            for (Entry<String, String> textSet : textSets) {
                //匹配模板与替换值 格式${key}
                String key = "${"+textSet.getKey()+"}";
                if(value.indexOf(key)!= -1){
                    value = textSet.getValue();
                }
            }
            //模板未匹配到区域替换为空
            if(checkText(value)){
                value = "";
            }
            return value;
        }
        
        
        
        
        public static void main(String[] args) {
        	//模板文件地址
            String inputUrl = "E:\\beian\\demo1.docx";
            //新生产的模板文件
            String outputUrl = "E:\\beian\\demo3.docx";
            
            Map<String, String> testMap = new HashMap<String, String>();
            testMap.put("type0", "注销");
            testMap.put("application", "票据系统");
            testMap.put("dept", "信息中心");
            testMap.put("unit", "111111");
            testMap.put("type1", "2");
            testMap.put("type2", "3");
            testMap.put("type3", "4");
            testMap.put("type4", "5");
            
            List<String[]> testList = new ArrayList<String[]>();
            testList.add(new String[]{"1","Q1","W1","E1","R1","T1"});
            testList.add(new String[]{"2","Q2","W2","E2","R2","T2"});
            testList.add(new String[]{"3","Q3","W3","E3","R3","T3"});
            testList.add(new String[]{"4","Q4","W4","E4","R4","T4"});
            testList.add(new String[]{"5","Q5","W5","E5","R5","T5"});
            testList.add(new String[]{"6","Q6","W6","E6","R6","T6"});
            testList.add(new String[]{"7","Q7","W7","E7","R7","T7"});
            
            WordUtil.changWord(inputUrl, outputUrl, testMap, testList);
        }
    
    }
    
    

    模板
    在这里插入图片描述

    ${type0}中的内容 为要替换的部分,用text写,然后复制进来, 不然可能无法替换,直接在word中写,会可能被认为一整个对象,无法替换成功

    结果:

    在这里插入图片描述

    参考了这两位大佬的
    https://www.jianshu.com/p/6603b1ea3ad1
    https://blog.csdn.net/qq_36880602/article/details/105750590

    展开全文
  • 所需依赖以及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)导出结果:

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    三、完整代码

    点击此处获取

    展开全文
  • poi 导出 excel 设置 表头固定不动

    千次阅读 2019-06-14 11:43:23
    HSSFSheet sheet = ...//固定第一行十五个列 createFreezePane (API): / * * *创建一个分割(freezepane)。任何现有的冷冻epane或拆分窗格都被覆盖。 * *如果colSplit和rowSplit都为零,则删除现有的冻结窗格 ...

    HSSFSheet sheet = workbook.createSheet(“导出数据”);
    sheet.createFreezePane(15, 1);//固定第一行十五个列

    createFreezePane (API):
    / * *
    *创建一个分割(freezepane)。任何现有的冷冻epane或拆分窗格都被覆盖。


    *
    *如果colSplit和rowSplit都为零,则删除现有的冻结窗格
    *

    • @param colSplit的水平位置。
    • @param rowSplit的垂直位置。
    • /
    • @Override
      public void createFreezePane(int colSplit, int rowSplit) {
      createFreezePane(colSplit, rowSplit, colSplit, rowSplit);
      }

    //sheet.protectSheet(“123456”); //设置编辑密码

    展开全文
  • SpringBoot+Poi-tl根据Word模板动态生成含动态表格word文档。 Poi-tl官方文档:http://deepoove.com/poi-tl/ 实现过程 1.添加必要依赖 <!-- word导出 --> <!-- poi-tl是基于Apache POI的Word模板引擎。...

    SpringBoot+Poi-tl根据Word模板动态生成含动态行表格的word文档。

    Poi-tl官方文档http://deepoove.com/poi-tl/

    一、实现过程

    1.添加必要依赖

        <!-- word导出 -->
    	<dependency>
    	   <groupId>com.deepoove</groupId>
    		<artifactId>poi-tl</artifactId>
    		<version>1.7.3</version>
    	</dependency>
    	<!--  上面需要的依赖-->
         <dependency>
             <groupId>org.apache.poi</groupId>
             <artifactId>poi-ooxml</artifactId>
             <version>4.1.2</version>
         </dependency>
        <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi-ooxml-schemas</artifactId>
                <version>4.1.2</version>
            </dependency>
        <dependency>
             <groupId>org.apache.poi</groupId>
             <artifactId>poi</artifactId>
             <version>4.1.2</version>
         </dependency>
    
    	<!-- 对JSP的支持 -->
    	<dependency>
    		<groupId>javax.servlet</groupId>
    		<artifactId>javax.servlet-api</artifactId>
    	</dependency>
    	<dependency>
    		<groupId>org.apache.tomcat.embed</groupId>
    		<artifactId>tomcat-embed-jasper</artifactId>
    	</dependency>
    	<dependency>
    		<groupId>javax.servlet</groupId>
    		<artifactId>jstl</artifactId>
    	</dependency>
    

    2.新建一个word,编写word模板:

    在这里插入图片描述
    把该模板放到项目中的static/template/文件夹下:
    在这里插入图片描述

    3.编写一个controller 类,导出销售订单信息的接口类,供页面请求

    package com.example.word.controller;
    
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.text.DecimalFormat;
    import java.text.SimpleDateFormat;
    import java.util.ArrayList;
    import java.util.Calendar;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.springframework.util.ClassUtils;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.servlet.ModelAndView;
    
    import com.deepoove.poi.XWPFTemplate;
    import com.deepoove.poi.config.Configure;
    import com.deepoove.poi.data.PictureRenderData;
    import com.deepoove.poi.policy.HackLoopTableRenderPolicy;
    import com.example.word.common.MoneyUtils;
    
    /**
     * 导出Word
     * @author Administrator
     *
     */
    @RequestMapping("/auth/exportWord/")
    @RestController
    public class ExportWordController {
    
    		/**
    	 * 销售订单信息导出word --- poi-tl(包含动态表格)
    	 * @throws IOException 
    	 */
    	@RequestMapping("/exportDataWord3")
    	public void exportDataWord3(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>> detailList=new ArrayList<Map<String,Object>>();
    	        for (int i = 0; i < 6; i++) {
    	        	 Map<String,Object> detailMap = new HashMap<String, Object>();
    	        	 detailMap.put("index", i+1);//序号
    	        	 detailMap.put("title", "商品"+i);//商品名称
    	        	 detailMap.put("product_description", "套");//商品规格
    	        	 detailMap.put("buy_num", 3+i);//销售数量
    	        	 detailMap.put("saleprice", 100+i);//销售价格
    	        	
    	        	 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);
    	             
    	             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+"order1.docx";//word模板地址
    	        //word模板地址获取方式二:优点---相比上一种方式,这种方法不会在linux或者jar上失效
    	      	ClassPathResource classPathResource = new ClassPathResource("static/template/order1.docx");
    			String resource = classPathResource.getURL().getPath();
    	        //渲染表格
    	        HackLoopTableRenderPolicy  policy = new HackLoopTableRenderPolicy();
    	        Configure config = Configure.newBuilder().bind("detailList", policy).build();
    	        XWPFTemplate template = XWPFTemplate.compile(resource, config).render(
    	        		new HashMap<String, Object>() {{
    			        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();
            }
    
    	}
    }
    
    

    需要注意的是:
    方法中的代码:

     FileOutputStream fos = new FileOutputStream(temDir+fileName);//输出路径(下载到指定路径)
    

    exportDataWord3方法中的两行代码:

    //浏览器下载
    response.setContentType("application/force-download");
    response.addHeader("Content-Disposition", "attachment;fileName=" + fileName);
    

    如果想要显示浏览器下载exportDataWord3方法中的这两行代码必须显示

    5.MoneyUtils 工具类

    package com.example.word.common;
    
    
    /**
     * 金额转换工具类
     */
    public class MoneyUtils {
        private static final String UNIT = "万千佰拾亿千佰拾万千佰拾元角分";
        private static final String DIGIT = "零壹贰叁肆伍陆柒捌玖";
        private static final double MAX_VALUE = 9999999999999.99D;
        public static String change(double v) {
            if (v < 0 || v > MAX_VALUE){
                return "参数非法!";
            }
            long l = Math.round(v * 100);
            if (l == 0){
                return "零元整";
            }
            String strValue = l + "";
            // i用来控制数
            int i = 0;
            // j用来控制单位
            int j = UNIT.length() - strValue.length();
            String rs = "";
            boolean isZero = false;
            for (; i < strValue.length(); i++, j++) {
                char ch = strValue.charAt(i);
                if (ch == '0') {
                    isZero = true;
                    if (UNIT.charAt(j) == '亿' || UNIT.charAt(j) == '万' || UNIT.charAt(j) == '元') {
                        rs = rs + UNIT.charAt(j);
                        isZero = false;
                    }
                } else {
                    if (isZero) {
                        rs = rs + "零";
                        isZero = false;
                    }
                    rs = rs + DIGIT.charAt(ch - '0') + UNIT.charAt(j);
                }
            }
            if (!rs.endsWith("分")) {
                rs = rs + "整";
            }
            rs = rs.replaceAll("亿万", "亿");
            return rs;
        }
     
        public static void main(String[] args){
            System.out.println(MoneyUtils.change(12356789.9845));
        }
    }
    
    

    5.jsp部分代码:

    <a href="#" class="easyui-linkbutton" onclick="doExportWord3();" data-options="iconCls:'icon-save'">导出word(包含动态表格)</a>
    function doExportWord3(){
      window.location.href="<%=basePath%>/auth/exportWord/exportDataWord3";
    }
    

    6.导出结果:
    在这里插入图片描述
    在这里插入图片描述

    二、完整代码

    点击此处获取

    三、功能延伸

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

    展开全文
  •  最近项目中有一个这样的需求:导出word 文档,要求这个文档的格式不是固定的,用户可以随便的调整,导出内容中的数据表格列是动态的,例如要求导出姓名和性别,你就要导出这两列的数据,而且这个文档不是导出来...
  • 4.操作完上面的步骤,就已经顺利完成了用WPS把Excel的表头设置成固定不动的所有的操作流程了。我们下拉表格后就可以发现需要锁定的表头不再移动了。 5.如果不想要锁定了的话,可以点击一下“视图...
  • 表格原本的type属性是autofit(自动调整),如果需要固定表格的宽度,需要关闭自动重调尺寸适应内容,java代码为 CTTblLayoutType type = infoTable.getCTTbl().getTblPr().addNewTblLayout(); type.setType...
  • Word中,对于已经有了固定的表头的表格,但是知道表格具体需要多少行时,我们可以根据需要动态的增加,以及单元格 的拆分,合并等操作。以下 是具体的例子代码(对于没有表头的表格,参照于我的另一篇博客): ...
  • 我没有选择使用工具类动态生成表格,而是实现新建一个word模板,然后在其中填充内容,因为我的模板是固定的,无需动态生成。模板如下图,红色实线表示头像需要插入的位置。 2. 方法 首先编辑模板,在头像位置...
  • 利用freemarker 在模板里面写入动态数据,动态表格,图片插入。 以下测试代码图片(image.jpg)和模板(template.xml)是直接放到src目录下面的,可以根据自己需求调整 废话多说,直接上代码: 代码块 ...
  • C#如何操作word去除表格表框。急。还有当表格行列不固定的时候,如何动态后台添加表格
  • 获取数据录入到固定word模板,最后生成新的word文档。 Poi-tl官方文档:http://deepoove.com/poi-tl/ 一、需求 根据word模板,动态填充模板内容,生成新的word。 二、poi-tl介绍 poi-tl(poi template language)...
  •  最近项目中有一个这样的需求:导出word文档,要求这个文档的格式不是固定的,用户可以随便的调整,导出内容中的数据表格列是动态的,例如要求导出姓名和性别,你就要导出这两列的数据,而且这个文档不是导出来之后...
  • [实用]【更新中】Java Apache POI 打印Word文档工具(含文本替换,动态表格功能)基于Apache POI对Word进行操作一、基于Apache POI封装的word文档工具V1.0介绍二、Apache POI 知识1. jar包(maven的,这个多做解释...
  • word嵌入表格,完美解决报表

    千次阅读 热门讨论 2015-12-22 15:35:07
    【背景概要】  项目中,有很多地方涉及到需要打印各种表格,静态的,动态... 在放下报表问题实现其它需求期间,偶然发现,我们可以动态的将表格嵌入到word文件中,利用word将各种表格显示打印。这里用到的就是Aspos
  • 前言 本文使用前端框架React。 最近项目遇到一个需求,需要前端去导出...4.导出表格 使用方法 首先讲一下在代码中怎么使用 首先导入第三方库: import Docxtemplaterfrom 'docxtemplater' import PizZipfrom 'pizzip'
  • 获取数据录入到固定word模板,最后生成新的word文档。 查找多方资料,进行实践,使用easypoi实现了word的导出功能。对其实现做下整理。 easypoi官方文档:http://easypoi.mydoc.io/#category_49974 实现过程: 1....
  •  最近项目中有一个这样的需求:导出word 文档,要求这个文档的格式不是固定的,用户可以随便的调整,导出内容中的数据表格列是动态的,例如要求导出姓名和性别,你就要导出这两列的数据,而且这个文档不是导出来...
  •  * 其中的list 是生成表格填充的内容,map是模板word表格内容替换的集合,file是模板word表格的地址 3. controller 控制台的部分 /** * 功能描述:动态替换docx 表格内容 并下载 * @param id * @...
  • 关于用java编写生成word文档,动态添加数据到word文档的一些心得,经过翻阅了无数的有用的和无用的资料以后,总算找到了一种靠谱的方法1.概述经过反反复复的查阅资料,总算找到了一个靠谱的生成word的方案,这里分享...
  • 需求需求:根据 word 模板,动态填充模板内容,生成新的 word。实现:获取数据库数据,根据 word 模板填充内容,生成新的 word 文档。“应用场景:笔者的应用场景是生成客户合...
  • 最近在使用freemaker做一个word模板,里面包含大量表格、截图、超链接等数据、历时一周多,遇到很多坑,现在想想都后怕,现在简单总结一下,希望给以后的小伙伴提供帮助,少走弯路! 坑一:word开 可能原因: ...
  • 需要从excel表格中抽取数据往word文件中填,同事咨询是否可以用word中的邮件合并功能,心想有这功夫研究还不如自己写代码实现。一共三个问题:1)读取Excel表格数据,2)往word模板文件中写数据,3)生成word文件。 ...
  • 【WPS】表格设置标题固定不滚动

    千次阅读 2019-05-02 11:02:10
    选择开始--冻结窗格--冻结首行 如果想设置多行标题,设置多行固定不滚动,则选择多行,选择开始--冻结窗格--冻结窗格 这样,就可以了,即是滚动到最下面,冻结的窗格还是固定不滚动 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 12,591
精华内容 5,036
关键字:

word表格位置固定不动