首页 > 代码库 > 在ssh框架中使用poi正确导出具有比较高级固定格式的excel 整体过程,查询导出前后台下载
在ssh框架中使用poi正确导出具有比较高级固定格式的excel 整体过程,查询导出前后台下载
(一) 接需求 : 需求相关 (贴图 )
生成三核对文件
1、新增三核对菜单页面中,增加生成三核对文件功能按钮,弹窗可根据变电站、电压等级查询定值单。
2、定值单信息以表格形式展示,根据选择情况,生成三核对文件。
整体就是这样的一个需求,分sheet,合并单元格,设置各种单元格格式,要有序号。
(二)吐槽
新手,什么都不会,同事直接给了这么一个僵硬的需求,哈哈我当时整个人都是懵逼的。一会总结说。
(三)具体流程
全部代码,控制层,service,前台,全都贴在最下面。
1 数据库查询
2将信息导出为datatable格式(公司框架)
3将datatable格式转化为workbook(循环遍历) 使用poi 导出excel
4workbook生成多SHEET以及合并单元格,单元格赋值,转换style
5生成workbook后 弹出下载页面 能够传到浏览器界面提供下载 (有关springweb框架前后台传参数取值问题 )
6中间出现的一些小问题 (全局变量设置 )
(四)代码实现与实现过程问题与解决
1 数据库查询
要生成一个这样一个excel表格,而我们的信息还没有获取到,这时应该考虑如何根据通过前台传过来的参数进行一次查询。(参数为一个,就是能够获得一个能关联到三个表的guid(有一个是无主键视图))
而在查询过程中也遇到了一些问题。
1. 游标的使用
把查询想的太过简单,关联三个表的问题研究一会就解决了,但是又出现新的问题,首先数据库查询出的信息并不满足我想要的信息,因为在需求中,那个执行日期执行人和核对日期核对人在我的数据库查询语句中是无法实现的,因为他们两个是一个并行的行,只有一个guid的话,在我的查询语句中注定只能查出不是执行日期就是核对日期的列。也就是说执行日期核对日期都只是一列中的值,不能并存,只能查出一条。
解决: 网上查了下,使用了一个比较坏的方法: 建立一个游标临时表,先通过一部分限制条件单独将执行日期执行人核对日期核对人查出如下
这个就是游标的一种用法,查出这样的数据后,建立游标,使用forward-only进行顺序读取, 也就是将这两行两列的数据从左至右读取并依次存入name2356中,这样我们就可以为所欲为了,因为这样我们可以安排name2356到任何地方,他们中一直都存着我之前给他们赋予的值,因为它们在一个临时表中,这样在下面放入数据库信息时,我再给它们用as重新命名并且进行拼接,可以直接安放到另一个查询语句中。 这样就解决了将不同行的某些信息放入同一行中的问题。
2.字符串的拼接。
表格中的信息部分我只能查到单独的信息,比如执行人和执行日期,这两个是两列,如何拼起来让他们变成一列。
查了一下,这个还是很好解决,使用+和as就可以解决。之前还以为多难。。。。
3.一个guid 与 变电站转化。
仔细看之前的表格需求,是分sheet的,是以变电站为一个sheet的形式,那么,我们应当如何做呢。就是分数据源来进行查询。
传过来的参数只有guid一个字符串,但是我可以通过guid来查出这些guid中的信息都是哪几个变电站的。
1 public List getSubName(String guiddd){2 StringBuffer sql = new StringBuffer();3 List list = new ArrayList();4 sql.append("SELECT DISTINCT CAST(SUBSTATION AS VARCHAR) AS SUBSTATION FROM US_APP.TB_DZD_INFORMATION "+"WHERE GUID IN ("+guiddd+")" );5 list = genericDao.getDataWithSQL(sql.toString());6 return list;7 }
在这样的数据库查询语句中,使用in是如何使用的呢,毕竟in‘1,2,3‘这样的格式,和字符串格式还是有点差距。
那么就是用 1 String guiddd = "‘"+guid.replaceAll(",", "‘,‘")+"‘";//转换为能够被数据查询语句查询的字符串 这样,guiddd就能够使用啦。
我这个逻辑比较乱,如下图,这样就完成了分数据源查询,也就可以分sheet了。
具体数据库查询如下。
1 PlatformConfigUtil.getString("dbtype"); 2 StringBuffer sql = new StringBuffer(); 3 sql.append("DECLARE " 4 + "@NAME2 NVARCHAR (300)," 5 + "@NAME3 NVARCHAR (300)," 6 + "@NAME5 NVARCHAR (300)," 7 + "@NAME6 NVARCHAR (300)"); 8 sql.append("DECLARE CUR CURSOR" 9 + " forward_only "10 + "FOR SELECT "11 + "TASKACTOR,ENDTIME "12 + "FROM US_SYS.TV_WF_TASKLOG "13 + "WHERE PROCESSINSTANCE = (");14 sql.append("SELECT PROCESSINSTANCE_ "15 + "FROM US_SYS.JBPM_VARIABLEINSTANCE "16 + "WHERE STRINGVALUE_= ? "// 此处问号17 + " AND NAME_ = ‘orderNo‘)");//问号~~~18 sql.append("AND (TASKNAME LIKE ‘执行‘"19 + " OR TASKNAME LIKE ‘核对‘) "20 + "AND ENDTIME IS NOT NULL ");21 sql.append("OPEN CUR ");22 sql.append("FETCH NEXT FROM CUR INTO"23 + " @NAME2,@NAME3 ");24 sql.append("FETCH NEXT FROM CUR INTO "25 + " @NAME5,@NAME6 ");26 sql.append("CLOSE CUR ");27 sql.append(" DEALLOCATE CUR ");28 sql.append(" SELECT ");29 sql.append(" ROW_NUMBER() OVER (ORDER BY GUID) AS ‘RowNumber‘,CAST(T1.SUBSTATION AS VARCHAR(500)) AS SUBSTATION, "30 + "CAST(T1.EQUIPMENT AS VARCHAR(500)) AS EQUIPMENT, "//设备名称31 + "CAST(T1.EQUIPMENTVERSION AS VARCHAR(500)) AS EQUIPMENTVERSION, "//保护型号32 + "CAST(T1.DZDINDEX AS VARCHAR(500)) AS DZDINDEX, " //定值单编号33 + "CAST(T1.BRANCHID AS VARCHAR(500)) AS BRANCHID, "//版本34 + "CAST(@NAME2 AS VARCHAR(500)) + "35 + "CAST(@NAME3 AS VARCHAR(500)) AS ENDTIME1, "36 + "CAST(@NAME5 AS VARCHAR(500)) + "37 + "CAST(@NAME6 AS VARCHAR(500)) AS ENDTIME2 " ); 38 sql.append(" FROM ");39 sql.append( " US_APP.TB_DZD_INFORMATION T1, ");40 sql.append(" US_SYS.TV_WF_TASKLOG T, ");41 sql.append(" US_SYS.JBPM_VARIABLEINSTANCE V ");42 sql.append(" WHERE ");43 sql.append("T1.ISDELETE = 0 ");44 sql.append(" AND T1.GUID = V.STRINGVALUE_ ");45 sql.append(" AND T.PROCESSINSTANCE = V.PROCESSINSTANCE_ ");46 sql.append(" AND (T.TASKNAME = ‘执行‘ ) ");47 sql.append(" AND T1.GUID = ? " ); 48 dataTablec = genericDao.getDataIntoDataTable(sql.toString(), new Object[]{guida[j],guida[j]});49 dataTable.appendRow(dataTablec.getRow(0));
2将信息导出为datatable格式(公司框架)
这样查出了信息之后其实也顺便将信息放入一个datatable中了,这个datatable好像是c#中的一种封装好的, 公司平台也给它用java封装了一个类。
这样每个datatable中其实包含了一个sheet的信息,一会对这个对象进行上下的循环遍历就能够存入信息主体啦。
说的很轻松他妈的看这个datatable的源码看了我好久,太菜了。
3将datatable格式转化为workbook(循环遍历)
这样是一个sheet,使用poi 包可以通过建立一个workbook(一个完整的excel表格)
我是这样做的,就是先在循环外围建立一个workbook,然后在sub循环中建立sheet,guid循环,也就建立了sub.length个sheet,一个sheet中也包含了一个sub中的所有信息,这个work中包含了所有全部sheet。 (sheet的name就是查询出的subname)
W
我是不是搞复杂了。。。
4workbook生成多SHEET以及合并单元格,单元格赋值,转换style
到这里就是一个比较繁琐的事情了,因为在需求中有五种格式一上,还有单元格的样式问题。
先说sheet导入时单个sheet其实是这个样子(下面是样式),有特别多不符合要求的地方,这里还没有分sheet,此刻就先让整个数据信息向下平移两个单元格留出标题以及序号的位置,然后向右平移留出一个序号位置。
具体工具类的设定就不说了,比较简单。
重点说一下合并单元格以及合并单元格的赋值与设定cellstyle是如何操作的。
下面的代码就是先使用这个合并单元格,
CellRangeAddress(起始行,结束行,起始列,结束列);
CellRangeAddress craa = new CellRangeAddress(rownumber,rownumber,0,5);
像我这样创建的话,这个单元格就是rownumber的第一个单元格了,因为起始列是0.
但是现在其实sheet中并没有改变这个单元格。
必须要用
sheet.addMergedRegion(craa);
这个语句来进行sheet单元格的添加。
添加后,需要
HSSFRow roww = sheet.createRow(rownumber);
HSSFCell cellw = roww.createCell((short)0);
在sheet中找到对应行以及对应单元格位置。以上。 这样,单元格与合并单元格就对应啦。
就可以和正常单元格一样给它赋值设定style或是干什么了~~~。
下面代码,没有格式,我在下面会加上所有代码。
1 int rownumber = dataRows.size()+3 ; 2 HSSFRow roww = sheet.createRow(rownumber); 3 HSSFRow rowwq = sheet.createRow(rownumber+1); 4 roww.setHeight((short) 600);// 设定行的高度 5 roww.setRowStyle(cellStyle); 6 rowwq.setHeight((short) 600);// 设定行的高度 7 rowwq.setRowStyle(cellStyle); 8 CellRangeAddress craa = new CellRangeAddress(rownumber,rownumber,0,5); 9 CellRangeAddress craaa = new CellRangeAddress(rownumber,rownumber,6,12);10 CellRangeAddress craab = new CellRangeAddress(rownumber+1,rownumber+1,0,5);11 CellRangeAddress craabb = new CellRangeAddress(rownumber+1,rownumber+1,6,12);12 sheet.addMergedRegion(craa); 13 HSSFCell cellw = roww.createCell((short)0);14 cellw.setCellValue("继保整定核对日期及核对人:");15 sheet.addMergedRegion(craaa); 16 HSSFCell celle = roww.createCell((short)6);17 celle.setCellValue("变电运行核对日期及核对人:");18 sheet.addMergedRegion(craab); 19 HSSFCell cellr = rowwq.createCell((short)0);20 cellr.setCellValue("调度核对日期及核对人:");21 sheet.addMergedRegion(craabb); 22 HSSFCell cellt = rowwq.createCell((short)6);23 cellt.setCellValue("检修继保班核对日期及核对人:");24 int rowss = dataRows.size() + 5; //rowss为datatable行数25 HSSFRow rowq = sheet.createRow(rowss);//sheet创建行26 rowq.setHeight((short) 300);// 设定行的高度27 rowq.setRowStyle(cellStyle);28 CellRangeAddress cra=new CellRangeAddress(rowss,rowss+10,0,columns.size()-1);//合并单元格的首行、最后一行、首列、最后一列。29 sheet.addMergedRegion(cra); 30 HSSFCell cellq = rowq.createCell((short)0);31 cellq.setCellValue(Constants.CHECKMANAGEMENT_CHECKDZDSTANDARD);32 cellq.setCellStyle(cellStyley);33 cellw.setCellStyle(cellStyleq);34 celle.setCellStyle(cellStyleq);35 cellr.setCellStyle(cellStyleq);36 cellt.setCellStyle(cellStyleq);37 CellRangeAddress crm = new CellRangeAddress(0,0,0,columns.size()-1);//表头大标题38 HSSFRow rowm = sheet.createRow(0);//sheet创建行39 rowm.setHeight((short) 1000);// 设定行的高度40 rowm.setRowStyle(cellStylem);41 sheet.addMergedRegion(crm);42 HSSFCell cellm = rowm.createCell((short)0);43 cellm.setCellValue("台州电网继电保护及安全自动装置整定单核对表");44 cellm.setCellStyle(cellStylem);
1 int rownumber = dataRows.size()+3 ; 2 HSSFRow roww = sheet.createRow(rownumber); 3 HSSFRow rowwq = sheet.createRow(rownumber+1); 4 roww.setHeight((short) 600);// 设定行的高度 5 roww.setRowStyle(cellStyle); 6 rowwq.setHeight((short) 600);// 设定行的高度 7 rowwq.setRowStyle(cellStyle); 8 CellRangeAddress craa = new CellRangeAddress(rownumber,rownumber,0,5); 9 CellRangeAddress craaa = new CellRangeAddress(rownumber,rownumber,6,12);10 CellRangeAddress craab = new CellRangeAddress(rownumber+1,rownumber+1,0,5);11 CellRangeAddress craabb = new CellRangeAddress(rownumber+1,rownumber+1,6,12);12 sheet.addMergedRegion(craa); 13 HSSFCell cellw = roww.createCell((short)0);14 cellw.setCellValue("继保整定核对日期及核对人:");15 sheet.addMergedRegion(craaa); 16 HSSFCell celle = roww.createCell((short)6);17 celle.setCellValue("变电运行核对日期及核对人:");18 sheet.addMergedRegion(craab); 19 HSSFCell cellr = rowwq.createCell((short)0);20 cellr.setCellValue("调度核对日期及核对人:");21 sheet.addMergedRegion(craabb); 22 HSSFCell cellt = rowwq.createCell((short)6);23 cellt.setCellValue("检修继保班核对日期及核对人:");24 int rowss = dataRows.size() + 5; //rowss为datatable行数25 HSSFRow rowq = sheet.createRow(rowss);//sheet创建行26 rowq.setHeight((short) 300);// 设定行的高度27 rowq.setRowStyle(cellStyle);28 CellRangeAddress cra=new CellRangeAddress(rowss,rowss+10,0,columns.size()-1);//合并单元格的首行、最后一行、首列、最后一列。29 sheet.addMergedRegion(cra); 30 HSSFCell cellq = rowq.createCell((short)0);31 cellq.setCellValue(Constants.CHECKMANAGEMENT_CHECKDZDSTANDARD);32 cellq.setCellStyle(cellStyley);33 cellw.setCellStyle(cellStyleq);34 celle.setCellStyle(cellStyleq);35 cellr.setCellStyle(cellStyleq);36 cellt.setCellStyle(cellStyleq);37 CellRangeAddress crm = new CellRangeAddress(0,0,0,columns.size()-1);//表头大标题38 HSSFRow rowm = sheet.createRow(0);//sheet创建行39 rowm.setHeight((short) 1000);// 设定行的高度40 rowm.setRowStyle(cellStylem);41 sheet.addMergedRegion(crm);42 HSSFCell cellm = rowm.createCell((short)0);43 cellm.setCellValue("台州电网继电保护及安全自动装置整定单核对表");44 cellm.setCellStyle(cellStylem);
然后序号问题我就做的比较蠢了,向下平移两格后第二行我直接设置column.size()的个数递增设置列序号。。。。。。。
竖向序号的话就直接在数据库中加了点东西,因为用的是sql server,所以有现成的东西。
ROW_NUMBER() OVER (ORDER BY GUID) AS ‘RowNumber‘
这个可以增加行序号~
5生成workbook后 弹出下载页面 能够传到浏览器界面提供下载 (有关springweb框架前后台传参数取值问题 )
有关这个前后台传递参数的问题我搞了三天吧,从最开始傻了吧唧直接指定固定位置后台直接保存,到前台传递参数后台接受并操作,操作后response回前台弹出窗口并进行下载。问别人问到他烦哈哈哈哈哈妈的真是没爱。
1 var openPostWindow = function(url,params){ 2 debugger 3 var form = $("<form>"); 4 form.attr("style","display:none"); // not success 5 form.attr("action", url); 6 form.attr("target","_blank"); // not success 7 form.attr("method","post"); 8 form.attr("action",url); 9 for(var param in params){10 var inputField = $("<input>");11 inputField.attr("type","text");12 inputField.attr("name",param);13 inputField.attr("value",params[param]);14 form.append(inputField); //把参数值以表单形式传递 !! 获取参数值15 }16 $("body").append(form);17 form.submit();18 form.remove();19 20 }
首先,所用框架决定,我要是想弹出下载的话,应该有固定的参数格式。我的参数格式是参照springweb传递参数的格式设定的。这里就不是java的问题了,是js jq的问题,他们应当能够给我后台传回我所需要我能操作的参数。
这里贴一段js代码。前台单击按钮,首先将要获取的东西一一获取,然后设定url,然后设定参数,然后提交到openpostwindow中,在这个方法里面,新建一个form表单,传过来几个参数,我就新建几个inputfield ,不过这些都是隐藏着进行的,用户看不到,然后使用for in 依次给inputfield赋值,name和value,皆对应相应的参数值,
比如我的,就是name就是我自己传过来设定的那个名字,substationa
value则是我subtation实际传过来的值,即"白云变"
这样 ,form中包含着三个inputfield,而这三个控件则拥有其自己的名字和值, 然后进行提交表单,就可以进入后台,后台中是这样的定义的。
1 public String cdzdExcel(@RequestParam(value ="http://www.mamicode.com/substationaa" , required = false) String substationaa,2 @RequestParam(value ="http://www.mamicode.com/voltageaa", required = false)String voltageaa,3 @RequestParam(value ="http://www.mamicode.com/guid", required = false) String guid4 ) {
这样,就ok啦,前台获取的参数,通过提交表单,传入后台参数,后台可以对这个进行操作了。required = false 是传入的参数可以为空的意思~~~
这个应该算是注解模式吧,使用的时候必须debug慢慢看,前后台都要debug,不然不行。
调试这个时候总是要出现 error400的 ,不是你的url有问题,就是你的传参有问题,一般我都是传参有问题。
1 { 2 type:"button", 3 text :"生成", 4 iconCls : ‘icon-plus-circle‘, 5 csstype : ‘primary‘,//背景色 6 onClick:function(){ 7 var voltagea = F1WidgetMgr.get(‘voltage‘).getText();//获取下拉框内电压参数 8 var substationa = F1WidgetMgr.get(‘substation‘).getText();//获取变电站参数 9 // $(‘#grid‘).bpgrid(‘exportExcel‘);10 var rows = $("#grid").bpgrid(‘getSelected‘);//bdz? 11 if(rows.length == 0){12 artDialog.alert("请选择数据进行操作!");13 return;14 }15 var valueForme = [];16 var i = 0;17 for(i;i<=(rows.length-1);i++){18 valueForme.push(rows[i].GUID);19 }20 var valueFormm = valueForme.toString();//将valueform转为字符串比较容易转入后台21 // alert(substationa); 要是有太多需要生成就直接把页数调成22 var url = "checkManagement/cdzdExcel/importsExcel.do";23 // var url = "ui/grid/export.do";把valueForm24 // 25 // var options = $(‘#gridpanel‘).data().f1Searchgrid.options;26 // var params = {27 // service : options.service,28 // filterStr : options.filterStr29 // 30 // }31 32 var params = {33 substationaa : substationa,34 voltageaa : voltagea,35 guid : valueFormm36 };37 openPostWindow(url,params);38 39 // alert("11");
1 var openPostWindow = function(url,params){ 2 debugger 3 var form = $("<form>"); 4 form.attr("style","display:none"); // no success 5 form.attr("action", url); 6 form.attr("target","_blank"); // no success 7 form.attr("method","post"); 8 form.attr("action",url); 9 for(var param in params){10 var inputField = $("<input>");11 inputField.attr("type","text");12 inputField.attr("name",param);13 inputField.attr("value",params[param]);14 form.append(inputField); //把参数值以表单形式传递 !! 获取参数值15 }16 $("body").append(form);17 form.submit();18 form.remove();19 20 }
前后台传参结束了,后台操作也结束了,现在生成的这个workbook放到哪里呢。~~~
这么放,重点看几行,
OutputStream out = response.getOutputStream();20 response.setCharacterEncoding("UTF-8");21 response.setContentType("application/x-msdownload");//设置向浏览器端传送的文件格式22 response.setHeader("Content-disposition", "attachment; filename="23 + URLEncoder.encode(fileName, "utf-8"));
22+23行代码就是关键,以这个格式设置的话,便会弹出下载。 写完记得关文件流。
这个代码还存到了c盘,如果没有c盘还会报错。
不想存的话可以直接删了。
1 /** 获取excel数据 */ 2 HSSFWorkbook workbook = CdzdsuperImportExcelServiceImpl.getExcel(guidd,sub,userModel); 3 /** 输出流文件 */ 4 HttpServletResponse response = (HttpServletResponse) ThreadLocalUtils 5 .getObjectFromThreadLocal("response"); 6 try { 7 // 表名 8 String tableName = "变电站定值单三核对表"; 9 String path = "c:\\";10 SimpleDateFormat sdf = new SimpleDateFormat("yyyy");11 Date date = new Date();12 String formatDate = sdf.format(date);13 // 文件名14 String fileName = formatDate + "年"+voltageaa + substationaa + tableName 15 + ".xls";16 path += fileName;17 FileOutputStream fileOut = new FileOutputStream(path); 18 response.reset();19 OutputStream out = response.getOutputStream();20 response.setCharacterEncoding("UTF-8");21 response.setContentType("application/x-msdownload");//设置向浏览器端传送的文件格式22 response.setHeader("Content-disposition", "attachment; filename="23 + URLEncoder.encode(fileName, "utf-8"));24 workbook.write(fileOut); 25 fileOut.flush();26 fileOut.close();27 workbook.write(out); 28 out.flush();29 out.close();30 } catch (Exception e) {31 throw new MessageException("下载出现错误", e);32 }33 return json.toJson(new ValidateMessage(true, "111"));
(五)总结
这个是我自己做出来的效果。代码会在下面。
总结
现在是总结和吐槽时间。
这个功能其实想想不难,难住我的是刚接触java直接用框架再加上公司平台,我直接懵逼,期间自我否定,有点怨天尤人,让我耽误了很多时间。
刚开始我是真的觉得自己做不出来,几乎什么都不懂,然后这个功能身边一个组的同事也都不太懂。。。我问人都没地方问。。。真的太折磨了。。。
数据库由于应用不熟练不懂游标 ,一路查一路搞过来,数据库应该注意的是在java语句中一定要注意空格,注意一些字符的长度,我被guid坑了好久,因为默认字符长度太短我的guid总是少了两个字符,找了好久查询不出来的问题。游标懂了一些,拼接懂了一点,表的联合懂了一点。
前后台那里问人加研究,debug太重要了,一步一步,de的我头发哗哗掉。
poi操作excel ,我从听都没听过到做出这么一个比较规整美观的表格我还是很有成就感的,多亏了博客园的诸多博客以及百度啦,需要改进的地方就是自己不太想去深入的理解,总是去试,因为这样不用思考,这样太蠢了,,100多个尝试文档。。也是智障。。。。
最重要的是,做事绝不可以敷衍了事了,工作不满足用户需求,就是你自己的锅,活在手里,决不能逃避,逃也是你的,不会做还是你的,没有人会管你。
凡事先debug再问人,先把手里信息弄懂,这样问人,别人说的话你才懂,你问别人的问题,才有分量。
时间不等人,努力。。。。
以下为各层代码
1 package com.jb.f1.checkManagement.taizhou.controller; 2 import java.io.FileOutputStream; 3 import java.io.OutputStream; 4 import java.net.URLEncoder; 5 import java.text.SimpleDateFormat; 6 import java.util.ArrayList; 7 import java.util.Date; 8 import java.util.List; 9 10 import javax.annotation.Resource;11 import javax.servlet.http.HttpServletResponse;12 import javax.servlet.http.HttpSession;13 14 import org.apache.poi.hssf.usermodel.HSSFWorkbook;15 import org.springframework.stereotype.Controller;16 import org.springframework.web.bind.annotation.RequestMapping;17 import org.springframework.web.bind.annotation.RequestParam;18 import org.springframework.web.bind.annotation.ResponseBody;19 20 import com.jb.core.constant.ICnsView;21 import com.jb.data.DataTable;22 import com.jb.exception.MessageException;23 import com.jb.f1.checkManagement.taizhou.service.impl.CdzdImportExcelServiceImpl;24 import com.jb.f1.kernel.util.ThreadLocalUtils;25 import com.jb.model.UserModel;26 import com.jb.util.json.JsonBinder;27 import com.jb.workflow.data.ValidateMessage;28 /**29 * 30 * @author zyb31 *2016年8月25日32 *com.jb.f1.checkManagement.taizhou.controller33 */34 35 @Controller36 @RequestMapping("/cdzdExcel")37 public class CdzdsuperImportExcelController {38 @Resource(name = "CdzdsuperImportExcelServiceImpl")39 private com.jb.f1.checkManagement.taizhou.service.impl.CdzdsuperImportExcelServiceImpl CdzdsuperImportExcelServiceImpl ;40 /** 转换器 */41 protected JsonBinder json = JsonBinder.getJsonBinder();42 @RequestMapping("importsExcel.do")43 @ResponseBody44 public String cdzdExcel(@RequestParam(value ="http://www.mamicode.com/substationaa" , required = false) String substationaa,45 @RequestParam(value ="http://www.mamicode.com/voltageaa", required = false)String voltageaa,46 @RequestParam(value ="http://www.mamicode.com/guid", required = false) String guid47 ) {48 HttpSession session = (HttpSession) ThreadLocalUtils.getObjectFromThreadLocal("session"); 49 UserModel userModel = (UserModel) session.getAttribute(ICnsView.LOGIN_USERMODEL);50 String[] guidd =new String[]{};51 guidd = guid.split(","); //转换为字符数组52 String guiddd = "‘"+guid.replaceAll(",", "‘,‘")+"‘";//转换为能够被数据查询语句查询的字符串53 List sublist = new ArrayList();54 String[] sub =new String[]{};55 //1 guid获取sublist56 sublist = CdzdsuperImportExcelServiceImpl.getSubName(guiddd);57 String[] array =new String[sublist.size()];58 sub = (String[]) sublist.toArray(array);// 字符数组59 //2 guidd sub 这两个返回workbook60 /** 获取excel数据 */61 HSSFWorkbook workbook = CdzdsuperImportExcelServiceImpl.getExcel(guidd,sub,userModel);62 /** 输出流文件 */63 HttpServletResponse response = (HttpServletResponse) ThreadLocalUtils64 .getObjectFromThreadLocal("response");65 try {66 // 表名67 String tableName = "变电站定值单三核对表";68 String path = "c:\\";69 SimpleDateFormat sdf = new SimpleDateFormat("yyyy");70 Date date = new Date();71 String formatDate = sdf.format(date);72 // 文件名73 String fileName = formatDate + "年"+voltageaa + substationaa + tableName 74 + ".xls";75 path += fileName;76 FileOutputStream fileOut = new FileOutputStream(path); 77 response.reset();78 OutputStream out = response.getOutputStream();79 response.setCharacterEncoding("UTF-8");80 response.setContentType("application/x-msdownload");//设置向浏览器端传送的文件格式81 response.setHeader("Content-disposition", "attachment; filename="82 + URLEncoder.encode(fileName, "utf-8"));83 workbook.write(fileOut); 84 fileOut.flush();85 fileOut.close();86 workbook.write(out); 87 out.flush();88 out.close();89 } catch (Exception e) {90 throw new MessageException("下载出现错误", e);91 }92 return json.toJson(new ValidateMessage(true, "111"));93 94 }95 96 97 }
1 package com.jb.f1.checkManagement.taizhou.service.impl; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 import javax.annotation.Resource; 7 8 import org.apache.commons.lang.StringUtils; 9 import org.apache.poi.hssf.usermodel.HSSFCell; 10 import org.apache.poi.hssf.usermodel.HSSFCellStyle; 11 import org.apache.poi.hssf.usermodel.HSSFFont; 12 import org.apache.poi.hssf.usermodel.HSSFRow; 13 import org.apache.poi.hssf.usermodel.HSSFSheet; 14 import org.apache.poi.hssf.usermodel.HSSFWorkbook; 15 import org.apache.poi.hssf.util.CellRangeAddress; 16 import org.apache.poi.hssf.util.HSSFColor; 17 import org.springframework.stereotype.Service; 18 import org.springframework.transaction.annotation.Propagation; 19 import org.springframework.transaction.annotation.Transactional; 20 21 import com.jb.config.util.PlatformConfigUtil; 22 import com.jb.dao.GenericDao; 23 import com.jb.data.DataColumn; 24 import com.jb.data.DataColumnCollection; 25 import com.jb.data.DataRow; 26 import com.jb.data.DataRowCollection; 27 import com.jb.data.DataTable; 28 import com.jb.f1.checkManagement.util.Constants; 29 import com.jb.model.UserModel; 30 import com.jb.util.POIExcelUtil; 31 32 33 @Service("CdzdsuperImportExcelServiceImpl") 34 @Transactional 35 public class CdzdsuperImportExcelServiceImpl { 36 @Resource(name="genericDao") 37 private GenericDao genericDao; 38 @Transactional(value = "http://www.mamicode.com/transactionManager", propagation = Propagation.REQUIRED) 39 @SuppressWarnings("deprecation") 40 public HSSFWorkbook getExcel(String[] guidd , String[] sub, UserModel userModel) { // 参数多加sub list 41 HSSFWorkbook workbook = POIExcelUtil.createNewHSSFWorkbook(); 42 String guid=StringUtils.join(guidd, ","); 43 String guiddd = "‘"+guid.replaceAll(",", "‘,‘")+"‘";//转换为能够被数据查询语句查询的字符串 44 for(int i=0;i<sub.length;i++){ 45 DataTable dataTablec=null; 46 DataTable dataTable = new DataTable(); 47 StringBuffer sql1 = new StringBuffer(); 48 List lista = new ArrayList(); 49 String[] guida =new String[]{}; 50 sql1.append("SELECT CAST(GUID AS VARCHAR(500)) AS GUID FROM US_APP.TB_DZD_INFORMATION WHERE SUBSTATION = ? AND GUID IN ("+guiddd+")" ); 51 lista = genericDao.getDataWithSQL(sql1.toString(),new Object[]{sub[i]}); 52 String[] array =new String[lista.size()]; 53 guida = (String[]) lista.toArray(array); 54 for(int j=0;j<guida.length;j++){ 55 PlatformConfigUtil.getString("dbtype"); 56 StringBuffer sql = new StringBuffer(); 57 sql.append("DECLARE " 58 + "@NAME2 NVARCHAR (300)," 59 + "@NAME3 NVARCHAR (300)," 60 + "@NAME5 NVARCHAR (300)," 61 + "@NAME6 NVARCHAR (300)"); 62 sql.append("DECLARE CUR CURSOR" 63 + " forward_only " 64 + "FOR SELECT " 65 + "TASKACTOR,ENDTIME " 66 + "FROM US_SYS.TV_WF_TASKLOG " 67 + "WHERE PROCESSINSTANCE = ("); 68 sql.append("SELECT PROCESSINSTANCE_ " 69 + "FROM US_SYS.JBPM_VARIABLEINSTANCE " 70 + "WHERE STRINGVALUE_= ? "// 此处问号 71 + " AND NAME_ = ‘orderNo‘)");//问号~~~ 72 sql.append("AND (TASKNAME LIKE ‘执行‘" 73 + " OR TASKNAME LIKE ‘核对‘) " 74 + "AND ENDTIME IS NOT NULL "); 75 sql.append("OPEN CUR "); 76 sql.append("FETCH NEXT FROM CUR INTO" 77 + " @NAME2,@NAME3 "); 78 sql.append("FETCH NEXT FROM CUR INTO " 79 + " @NAME5,@NAME6 "); 80 sql.append("CLOSE CUR "); 81 sql.append(" DEALLOCATE CUR "); 82 sql.append(" SELECT "); 83 sql.append(" ROW_NUMBER() OVER (ORDER BY GUID) AS ‘RowNumber‘,CAST(T1.SUBSTATION AS VARCHAR(500)) AS SUBSTATION, " 84 + "CAST(T1.EQUIPMENT AS VARCHAR(500)) AS EQUIPMENT, "//设备名称 85 + "CAST(T1.EQUIPMENTVERSION AS VARCHAR(500)) AS EQUIPMENTVERSION, "//保护型号 86 + "CAST(T1.DZDINDEX AS VARCHAR(500)) AS DZDINDEX, " //定值单编号 87 + "CAST(T1.BRANCHID AS VARCHAR(500)) AS BRANCHID, "//版本 88 + "CAST(@NAME2 AS VARCHAR(500)) + " 89 + "CAST(@NAME3 AS VARCHAR(500)) AS ENDTIME1, " 90 + "CAST(@NAME5 AS VARCHAR(500)) + " 91 + "CAST(@NAME6 AS VARCHAR(500)) AS ENDTIME2 " ); 92 sql.append(" FROM "); 93 sql.append( " US_APP.TB_DZD_INFORMATION T1, "); 94 sql.append(" US_SYS.TV_WF_TASKLOG T, "); 95 sql.append(" US_SYS.JBPM_VARIABLEINSTANCE V "); 96 sql.append(" WHERE "); 97 sql.append("T1.ISDELETE = 0 "); 98 sql.append(" AND T1.GUID = V.STRINGVALUE_ "); 99 sql.append(" AND T.PROCESSINSTANCE = V.PROCESSINSTANCE_ ");100 sql.append(" AND (T.TASKNAME = ‘执行‘ ) ");101 sql.append(" AND T1.GUID = ? " ); 102 dataTablec = genericDao.getDataIntoDataTable(sql.toString(), new Object[]{guida[j],guida[j]});103 dataTable.appendRow(dataTablec.getRow(0));104 }105 dataTable.appendColumn("序号");106 dataTable.appendColumn("变电站");107 dataTable.appendColumn("设备名称");108 dataTable.appendColumn("保护型号"); 109 dataTable.appendColumn("定值单编号"); 110 dataTable.appendColumn("版本号"); 111 dataTable.appendColumn("定值单执行日期及执行人");112 dataTable.appendColumn("定值单核对日期及核对人");113 dataTable.appendColumn("继保整定核对");114 dataTable.appendColumn("调度核对");115 dataTable.appendColumn("变电运行核对");116 dataTable.appendColumn("检修继保核对");117 dataTable.appendColumn("备注(填写出入情况)");118 // 这里一个sub。length循环119 HSSFSheet sheet = workbook.createSheet(sub[i]);//这里creat参数为sub120 121 sheet.setColumnWidth(0, 2500); 122 sheet.setColumnWidth(1, 3500); 123 sheet.setColumnWidth(2, 3500); 124 sheet.setColumnWidth(3, 2500); 125 sheet.setColumnWidth(4, 3500); 126 sheet.setColumnWidth(5, 3500); 127 sheet.setColumnWidth(6, 7500); 128 sheet.setColumnWidth(7, 7500); 129 sheet.setColumnWidth(8, 2500); 130 sheet.setColumnWidth(9, 2500); 131 sheet.setColumnWidth(10, 2500); 132 sheet.setColumnWidth(11, 2500);133 sheet.setColumnWidth(12, 4500);134 List<String> columnNames = new ArrayList<String>();135 /** 构造表头 */136 DataColumnCollection columns = dataTable.getColumns();//dat137 int s = 0;138 for (int k = 0; k < columns.size(); k++) {139 DataColumn dataColumn = columns.get(k);140 String columnName = dataColumn.getCaption() == null ? dataColumn141 .getColumnName() : dataColumn.getCaption();142 // 去掉不打印的和隐藏字段143 if (dataColumn.getHidden() == true||"OBJ_CAPTION".equals(dataColumn144 .getColumnName())||"GUID".equals(dataColumn145 .getColumnName())) {146 continue;147 } else {148 DataColumn raleColumn = columns.get(dataColumn.getColumnName()149 + "_DSPVALUE");150 if (raleColumn != null) {151 raleColumn.setCaption(dataColumn.getCaption());152 continue;153 }154 }155 156 if (dataColumn.getColumnName().indexOf("_DSPVALUE") != -1) {157 DataColumn raleColumn = columns.get(dataColumn.getColumnName()158 .replace("_DSPVALUE", ""));159 if (raleColumn != null && !raleColumn.isPrint()) {160 continue;161 } else {162 columnName = columnName.replace("_DSPVALUE", "");163 }164 }165 HSSFFont font = workbook.createFont();166 font.setFontName("宋体");167 font.setFontHeightInPoints((short) 12);//设置字体大小168 HSSFFont fontr = workbook.createFont();//字体样式2169 fontr.setFontName("宋体");170 fontr.setFontHeightInPoints((short) 12);//设置字体大小171 fontr.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); 172 HSSFCellStyle columnHeadStyle = workbook.createCellStyle();173 columnHeadStyle.setWrapText(true);//设置自动换行174 columnHeadStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);175 columnHeadStyle.setFillForegroundColor(HSSFColor.LEMON_CHIFFON.index);176 HSSFCellStyle setBorder = workbook.createCellStyle();177 setBorder.setAlignment(HSSFCellStyle.ALIGN_CENTER);178 columnHeadStyle.setFont(fontr); 179 columnHeadStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);// 左右居中 180 columnHeadStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);// 上下居中 181 columnHeadStyle.setLocked(true); 182 columnHeadStyle.setWrapText(true); 183 columnHeadStyle.setLeftBorderColor(HSSFColor.BLACK.index);// 左边框的颜色 184 columnHeadStyle.setBorderLeft((short) 1);// 边框的大小 185 columnHeadStyle.setRightBorderColor(HSSFColor.BLACK.index);// 右边框的颜色 186 columnHeadStyle.setBorderRight((short) 1);// 边框的大小 187 columnHeadStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN); // 设置单元格的边框为粗体 188 columnHeadStyle.setBottomBorderColor(HSSFColor.BLACK.index); // 设置单元格的边框颜色 189 DataRowCollection dataRowss = dataTable.getRows();190 POIExcelUtil.setCellValueDefaultNoSave(workbook, sheet.getSheetName(), 2, s++,191 columnName, columnHeadStyle); //此处设置表头位置192 columnNames.add(dataColumn.getColumnName());193 194 }195 /** 构造内容 */196 DataRowCollection dataRows = dataTable.getRows();197 HSSFCellStyle cellStyle = workbook.createCellStyle();198 HSSFFont font = workbook.createFont();//字体样式1199 font.setFontName("宋体");200 font.setFontHeightInPoints((short) 14);//设置字体大小201 202 HSSFFont fontq = workbook.createFont();//字体样式2203 fontq.setFontName("宋体");204 fontq.setFontHeightInPoints((short) 12);//设置字体大小205 fontq.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); 206 207 HSSFFont fontm = workbook.createFont();//字体样式3208 fontm.setFontName("宋体");209 fontm.setFontHeightInPoints((short) 22);//设置字体大小210 fontm.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); 211 212 HSSFFont fonty = workbook.createFont();//字体样式3213 fonty.setFontName("宋体");214 fonty.setFontHeightInPoints((short) 12);//设置字体大小215 216 cellStyle.setWrapText(true);//设置自动换行217 cellStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);218 cellStyle.setFillForegroundColor(HSSFColor.WHITE.index);219 HSSFCellStyle setBorder = workbook.createCellStyle();220 setBorder.setAlignment(HSSFCellStyle.ALIGN_CENTER);221 cellStyle.setFont(font); 222 cellStyle.setWrapText(true);//设置自动换行223 cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);// 左右居中 224 cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);// 上下居中 225 cellStyle.setLocked(true); 226 cellStyle.setWrapText(true); 227 cellStyle.setLeftBorderColor(HSSFColor.BLACK.index);// 左边框的颜色 228 cellStyle.setBorderLeft((short) 1);// 边框的大小 229 cellStyle.setRightBorderColor(HSSFColor.BLACK.index);// 右边框的颜色 230 cellStyle.setBorderRight((short) 1);// 边框的大小 231 cellStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN); // 设置单元格的边框为粗体 232 cellStyle.setBottomBorderColor(HSSFColor.BLACK.index); // 设置单元格的边框颜色 233 234 HSSFCellStyle cellStyleq = workbook.createCellStyle();235 cellStyleq.setWrapText(true);//设置自动换行236 cellStyleq.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);237 cellStyleq.setFillForegroundColor(HSSFColor.WHITE.index);238 cellStyleq.setAlignment(HSSFCellStyle.ALIGN_LEFT);// 左右居左239 cellStyleq.setFont(font); 240 cellStyleq.setWrapText(true);//设置自动换行241 cellStyleq.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);// 上下居 242 cellStyleq.setLocked(true); 243 cellStyleq.setWrapText(true); 244 cellStyleq.setLeftBorderColor(HSSFColor.BLACK.index);// 左边框的颜色 245 cellStyleq.setBorderLeft((short) 1);// 边框的大小 246 cellStyleq.setRightBorderColor(HSSFColor.BLACK.index);// 右边框的颜色 247 cellStyleq.setBorderRight((short) 1);// 边框的大小 248 cellStyleq.setBorderBottom(HSSFCellStyle.BORDER_THIN); // 设置单元格的边框为粗体 249 cellStyleq.setBottomBorderColor(HSSFColor.BLACK.index); // 设置单元格的边框颜色 250 cellStyleq.setFont(fontq); //字体251 252 HSSFCellStyle cellStyley = workbook.createCellStyle();253 cellStyley.setWrapText(true);//设置自动换行254 cellStyley.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);255 cellStyley.setFillForegroundColor(HSSFColor.WHITE.index);256 cellStyley.setAlignment(HSSFCellStyle.ALIGN_LEFT);// 左右居左257 cellStyley.setWrapText(true);//设置自动换行258 cellStyley.setVerticalAlignment(HSSFCellStyle.ALIGN_LEFT);// 上下居 259 cellStyley.setLocked(true); 260 cellStyley.setWrapText(true); 261 cellStyley.setLeftBorderColor(HSSFColor.BLACK.index);// 左边框的颜色 262 cellStyley.setBorderLeft((short) 1);// 边框的大小 263 cellStyley.setRightBorderColor(HSSFColor.BLACK.index);// 右边框的颜色 264 cellStyley.setBorderRight((short) 1);// 边框的大小 265 cellStyley.setBorderBottom(HSSFCellStyle.BORDER_THIN); // 设置单元格的边框为粗体 266 cellStyley.setBottomBorderColor(HSSFColor.BLACK.index); // 设置单元格的边框颜色 267 cellStyley.setFont(fonty); //字体268 269 HSSFCellStyle cellStylem = workbook.createCellStyle();//第三个样式270 271 cellStylem.setWrapText(true);//设置自动换行272 cellStylem.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);273 cellStylem.setFillForegroundColor(HSSFColor.WHITE.index);274 cellStylem.setAlignment(HSSFCellStyle.ALIGN_CENTER);// 左右居中275 cellStylem.setFont(font); 276 cellStylem.setWrapText(true);//设置自动换行277 cellStylem.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);// 上下居中 278 cellStylem.setLocked(true); 279 cellStylem.setWrapText(true); 280 cellStylem.setLeftBorderColor(HSSFColor.BLACK.index);// 左边框的颜色 281 cellStylem.setBorderLeft((short) 1);// 边框的大小 282 cellStylem.setRightBorderColor(HSSFColor.BLACK.index);// 右边框的颜色 283 cellStylem.setBorderRight((short) 1);// 边框的大小 284 cellStylem.setBorderBottom(HSSFCellStyle.BORDER_THIN); // 设置单元格的边框为粗体 285 cellStylem.setBottomBorderColor(HSSFColor.BLACK.index); // 设置单元格的边框颜色 286 cellStylem.setFont(fontm); //字体287 HSSFRow rowy = sheet.createRow(1);//sheet创建行288 rowy.setHeight((short) 500);// 设定行的高度289 rowy.setRowStyle(cellStyle);290 for(int y=0;y<columns.size();y++){291 HSSFCell celly = rowy.createCell((short)y);292 celly.setCellValue(y+1);293 celly.setCellStyle(cellStyle);294 }295 296 for (int p = 0; p < dataRows.size(); p++) {297 DataRow dataRow = dataRows.get(p);298 for (int l = 0; l < columnNames.size(); l++) {299 if (dataRow.getValue(columnNames.get(l)) != null) {300 301 POIExcelUtil.setCellValueDefaultNoSave(workbook, sheet.getSheetName(),302 p+3 , l, dataRow.getValue(columnNames.get(l))303 .toString(), cellStyle);//l+1可以向右平移一个单位304 } else {305 POIExcelUtil.setCellValueDefaultNoSave(workbook,sheet.getSheetName(),306 p+3 , l, "", cellStyle);307 }308 }309 }310 311 312 int rownumber = dataRows.size()+3 ;313 HSSFRow roww = sheet.createRow(rownumber);314 HSSFRow rowwq = sheet.createRow(rownumber+1);315 roww.setHeight((short) 600);// 设定行的高度316 roww.setRowStyle(cellStyle);317 rowwq.setHeight((short) 600);// 设定行的高度318 rowwq.setRowStyle(cellStyle);319 CellRangeAddress craa = new CellRangeAddress(rownumber,rownumber,0,5);320 CellRangeAddress craaa = new CellRangeAddress(rownumber,rownumber,6,12);321 CellRangeAddress craab = new CellRangeAddress(rownumber+1,rownumber+1,0,5);322 CellRangeAddress craabb = new CellRangeAddress(rownumber+1,rownumber+1,6,12);323 sheet.addMergedRegion(craa); 324 HSSFCell cellw = roww.createCell((short)0);325 cellw.setCellValue("继保整定核对日期及核对人:");326 sheet.addMergedRegion(craaa); 327 HSSFCell celle = roww.createCell((short)6);328 celle.setCellValue("变电运行核对日期及核对人:");329 sheet.addMergedRegion(craab); 330 HSSFCell cellr = rowwq.createCell((short)0);331 cellr.setCellValue("调度核对日期及核对人:");332 sheet.addMergedRegion(craabb); 333 HSSFCell cellt = rowwq.createCell((short)6);334 cellt.setCellValue("检修继保班核对日期及核对人:");335 int rowss = dataRows.size() + 5; //rowss为datatable行数336 HSSFRow rowq = sheet.createRow(rowss);//sheet创建行337 rowq.setHeight((short) 300);// 设定行的高度338 rowq.setRowStyle(cellStyle);339 CellRangeAddress cra=new CellRangeAddress(rowss,rowss+10,0,columns.size()-1);//合并单元格的首行、最后一行、首列、最后一列。340 sheet.addMergedRegion(cra); 341 HSSFCell cellq = rowq.createCell((short)0);342 cellq.setCellValue(Constants.CHECKMANAGEMENT_CHECKDZDSTANDARD);343 cellq.setCellStyle(cellStyley);344 cellw.setCellStyle(cellStyleq);345 celle.setCellStyle(cellStyleq);346 cellr.setCellStyle(cellStyleq);347 cellt.setCellStyle(cellStyleq);348 CellRangeAddress crm = new CellRangeAddress(0,0,0,columns.size()-1);//表头大标题349 HSSFRow rowm = sheet.createRow(0);//sheet创建行350 rowm.setHeight((short) 1000);// 设定行的高度351 rowm.setRowStyle(cellStylem);352 sheet.addMergedRegion(crm);353 HSSFCell cellm = rowm.createCell((short)0);354 cellm.setCellValue("台州电网继电保护及安全自动装置整定单核对表");355 cellm.setCellStyle(cellStylem);356 // for(int m=0;m<=12;m++ ){357 // 358 // 359 // }360 361 362 363 }364 return workbook;365 }366 @Transactional(value = "http://www.mamicode.com/transactionManager", propagation = Propagation.REQUIRED)367 public List getSubName(String guiddd){368 StringBuffer sql = new StringBuffer();369 List list = new ArrayList();370 sql.append("SELECT DISTINCT CAST(SUBSTATION AS VARCHAR) AS SUBSTATION FROM US_APP.TB_DZD_INFORMATION "+"WHERE GUID IN ("+guiddd+")" );371 list = genericDao.getDataWithSQL(sql.toString());372 return list;373 }374 375 376 377 378 }
view层在前面拉,我就不重复了~~
希望有人给我留言指点一下~~谢谢谢~
在ssh框架中使用poi正确导出具有比较高级固定格式的excel 整体过程,查询导出前后台下载