`

Ajax提交无法导出Excel

    博客分类:
  • Ajax
阅读更多
Ajax提交无法导出Excel

这几天在做一个报表的导出,用的是Ajax方式提交的,一直下载不了附件。。。

后来在网上找到了一个解决方案,用Iframe的方式进行提交。。。

源代码如下:
js代码:
  //导出报表
function toExport(name, gridcontainer){
if(confirm("确定要导出报表数据?")){
var settMonth=$('#settleMonth').val();
if(settMonth ==''){
alert("请选择帐期!");
return;
}
if (!checkAtLeastOne(gridcontainer.grid.getSelectedRows(), '操作!')) {
return false;
}
var values = gridcontainer.grid.getSelectedCellValues(['REPORT_ID']);
var data=serializeStringWithEncode(values,['REPORT_ID'], ['reportIds']);
var resutId='';
if(data.indexOf("&") > 0){
var arry=new Array();
arry=data.split("&");
for(var i=0;i<arry.length;i++){
var arryObj=arry[i];
if(i < arry.length -1){
resutId=resutId+arryObj.split("=")[1]+"_";
}else{
resutId=resutId+arryObj.split("=")[1];
}
}
}else{
resutId=data.split("=")[1];
}

var url = contextPath+"/localnet/comexport/generExport/exportExcelMethod.action?reportId="+resutId+"&settleMonth="+settMonth+"&random="+Math.random();
var iframe = document.createElement("iframe");
iframe.src = url;
var imgPath=contextPath+"/base/css/images/default/shared/blue-loading.gif";
$.blockUI({
message:"<img src='"+imgPath+"' /><h4>报表正在导出中,请稍后....</h4>",
css:{background:'none',color: '#000',border:'none'},
overlayCSS:{backgroundColor:'#C5E1F0',opacity:'0.4'}
});

if (!/*@cc_on!@*/0) { //if not IE
    iframe.onload = function(){
    $.unblockUI();
    };
} else {
    iframe.onreadystatechange = function(){
    //文件下载是在http请求的interactive也就是浏览器交互阶段。
        if (iframe.readyState == "interactive"){
        $.unblockUI(); 
        }
    };
}

iframe.style.display = 'none';
document.body.appendChild(iframe);

}

}




Java代码:

public String exportExcelMethod() throws Exception{
System.out.println("账期:"+settleMonth +", 报表ID:reportId="+reportId);
initReportIds(reportId);

ServiceResult<RReportDefBean> context = super.getContext();
//压缩文件路径
String zipPath=File.separator + pathOut + File.separator + settleMonth;
//压缩包存放路径
//String zipPakPath=File.separator + pathOut + File.separator + settleMonth+ File.separator;
String zipPakPath=File.separator + pathOut + File.separator;

//获取业务名称,用于导出zip包,这个业务名称应该是业务类型的上级名称
String expName="报表数据";

//List<RReportDefBean> reportDefBeans=reportDefService.getReportDefList(reportDefBean);
//模板路径
//输出路径为/ppmWeb/outtemplet/报表编码/账期
String encoding = System.getProperty("sun.jnu.encoding");

if(reportIds.length>0){
for (int i = 0; i < reportIds.length; i++) {
//读取文件模板到输出目录下
RReportDefBean defBean=new RReportDefBean();
defBean.setReportId(reportIds[i]);
defBean= reportDefService.loadEntity(defBean);
String srcReportName=defBean.getReportName()+".xls";
String desRepotName=defBean.getReportName()+"_"+settleMonth+".xls";

RReportBusinessDefBean businessDefBean =new RReportBusinessDefBean();
businessDefBean.setBusinessCode(defBean.getBusinessCode());
businessDefBean=reportBusinessDefService.loadEntity(businessDefBean);

String srcPath=File.separator + pathIn + File.separator + defBean.getBusinessCode() + File.separator+ new String(srcReportName.getBytes("GBK"),encoding );
//目标模板目录用中文业务名
String outPath=File.separator + pathOut + File.separator + settleMonth  + File.separator + new String(businessDefBean.getBusinessName().getBytes("GBK"),encoding );
File file=new File(ServletActionContext.getServletContext().getRealPath(srcPath));
System.out.println("模板的绝对路径:"+file.getAbsolutePath());
if(file.exists()){
//将模板复制目标目录
copyFileMethod(srcPath, outPath,desRepotName);
File desFile=new File(ServletActionContext.getServletContext().getRealPath(outPath + File.separator + new String(desRepotName.getBytes("GBK"),encoding)));
if(desFile.exists()){
//替换模板中的变量数据
FileInputStream  fInputStream =new FileInputStream(desFile);
HSSFWorkbook hWorkbook=new HSSFWorkbook(fInputStream);
//替换模板中的变量
RReportInstPartTitleBean titleBean=new RReportInstPartTitleBean();
titleBean.setReportId(reportIds[i]);
titleBean.setSettleMonth(Long.valueOf(settleMonth));
ServiceResult<RReportInstPartTitleBean>  serviceResult= reportInstPartTitleService.queryList(titleBean, new Limiter());
if(serviceResult !=null && serviceResult.getResult().size()>0){
List<RReportInstPartTitleBean>  listBeans=serviceResult.getResult();
if(listBeans !=null && listBeans.size()>0){
for (RReportInstPartTitleBean titleBean2 : listBeans) {
long hCell= titleBean2.getHcell();    //纵坐标
long vCell= titleBean2.getVcell();    //横坐标
long sheetNo= titleBean2.getSheetNo();
    long paramId= titleBean2.getParamId();
HSSFSheet sheet = hWorkbook.getSheetAt(new Long(sheetNo).intValue());
HSSFRow row  = sheet.getRow(new Long(vCell).intValue() -1);
if(row ==null){
row  = sheet.createRow(new Long(vCell).intValue()-1);
}
HSSFCell cell = row.getCell(new Long(hCell).intValue()-1);
if(cell ==null){
cell = row.createCell(new Long(hCell).intValue()-1);
}
String paraStr= getChargeParam(settleMonth,titleBean2.getParamId());
String cellOld = cell.getStringCellValue();
if(cellOld !=null && !"".equals(cellOld)){
if(paramId ==1L){
cell.setCellValue(cellOld.replace("#JSZQ#","")+paraStr);
}
if(paramId ==2L){
cell.setCellValue(cellOld.replace("#TJRQ#","")+paraStr);
}
}else {
cell.setCellValue(paraStr);
}

}
}
}else {
System.out.println("报表ID:reportId, 账期:"+settleMonth+" ,对应的变量账期不存在!请核查R_REPORT_PARAM表的配置.......");
}

//写模板实例数据
//这个地方要区分SP的三个动态模板
String excepIds[]={"11010001","11010002","11010003"};
List<String> excepList = Arrays.asList(excepIds);


Map<String, Object> map=new HashMap<String, Object>();
List<ComReportInstBean>  reportInstBeans=null;
if (excepList.contains(reportIds[i])) {
//这三个目前需特殊处理
map.put("reportId",Long.valueOf(reportIds[i]));
map.put("settleMonth", Long.valueOf(settleMonth));
reportInstBeans=comReportInstService.getReportExcepList(map);
System.out.println("报表ID="+reportIds[i] +",按照旧的表结构进行数据提取......");

}else {
map.put("fees", "fees"+settleMonth.substring(4, 6));
map.put("settleYear", Long.valueOf(settleMonth.substring(0, 4)));
map.put("reportId",Long.valueOf(reportIds[i]));
reportInstBeans=comReportInstService.getComReportInstList(map);
}

if(reportInstBeans!=null && reportInstBeans.size()>0)
{
for(ComReportInstBean instBean: reportInstBeans)
{
HSSFSheet hssfSheet=hWorkbook.getSheetAt(Integer.parseInt(instBean.getSheetno().toString()));
HSSFRow row=hssfSheet.getRow(Integer.parseInt(instBean.getVcell().toString())-1);
double fees=instBean.getFees();   //费用字段在bean中最好设置为double类型
//当模板有问题的时候,取到的列可能为空
if(instBean.getSheetno()==0L){
System.out.println("打印信息:::账期:"+settleMonth +"报表ID="+reportId +" ;sheet页="+instBean.getSheetno() +"; 行号="+instBean.getVcell() +" ;列号="+instBean.getHcell() +";fees="+fees);
}

HSSFCell cell=row.getCell(Integer.parseInt(instBean.getHcell().toString()) -1);
if(cell ==null)
{
cell=row.createCell(Integer.parseInt(instBean.getHcell().toString()) -1);
}else {
cell.setCellType(cell.getCellType());
}
//额度要除以100,库表中是以分为单位的,报表中以元为单位
if(fees==0.0){
cell.setCellValue(fees);
}else {
cell.setCellValue(fees / 100);
}
}

fInputStream.close();
FileOutputStream fOutputStream=new FileOutputStream(new File(ServletActionContext.getServletContext().getRealPath(outPath + File.separator +new String(desRepotName.getBytes("GBK"),encoding ))));
//强制Excle执行公式
hWorkbook.setForceFormulaRecalculation(true);
hWorkbook.write(fOutputStream);
fOutputStream.close();
}
else
{
System.out.println("报表ID为"+reportId+",账期为"+settleMonth +",的实例数据不存在.......");
}
}else {
System.out.println("模板复制失败.........");
}

}else {
System.out.println("模板:"+srcReportName+"在目录"+File.separator + pathIn + File.separator + defBean.getBusinessCode() + File.separator+"下不存在,请检查模板....");
}
}

//打包输出
String zipName = expName+ "_" + settleMonth +".zip";
//zipName = new String(zipName.getBytes("GBK"), "ISO8859-1");

String zipFileName =File.separator + zipPakPath  + zipName;
System.out.println("zipFileName路径:"+ServletActionContext.getServletContext().getRealPath(zipFileName));
System.out.println("zipPath路径:"+ServletActionContext.getServletContext().getRealPath(zipPath));
String floder = zipPath;
//第一个参数是打包的文件夹路径, 第二个打包后的文件名(带路径)
ZipUtils.zip(ServletActionContext.getServletContext().getRealPath(floder), ServletActionContext.getServletContext().getRealPath(zipFileName));
outputReport(ServletActionContext.getServletContext().getRealPath(zipFileName),zipName);

}else {
System.out.println("传入的数组参数reportIds,businessCodes的长度为0,请检查参数!");
context.setSuccess(false);

}

return NONE;
}

****************************************************************************************

/*
* 复制文件
* srcPaht :原路径
* desPath :目标路径
*/
public void copyFileMethod(String srcPaht, String desPath,String fileName){
//目录路径可能不存在,则要新建
String encoding = System.getProperty("sun.jnu.encoding");
try {
File file=new File(ServletActionContext.getServletContext().getRealPath(desPath));
if(!file.exists() && !file.isDirectory()){
System.out.println("方法:copyFileMethod 重建目标模板目录......");
file.mkdirs();
}
//目标路径下的文件如果已存在,则要删除

File file2=new File(ServletActionContext.getServletContext().getRealPath(desPath + File.separator + new String(fileName.getBytes("GBK"),encoding)));
if(file2.exists()){
System.out.println("方法:copyFileMethod 删除已经存在的模板实例......");
file2.delete();
}
} catch (UnsupportedEncodingException e1) {
System.out.println("方法copyFileMethod: 删除已经存在的模板实例文件出错......");
e1.printStackTrace();
}

try {
FileInputStream in=new FileInputStream(ServletActionContext.getServletContext().getRealPath(srcPaht));
FileOutputStream out=new FileOutputStream(ServletActionContext.getServletContext().getRealPath(desPath+ File.separator + new String(fileName.getBytes("GBK"),encoding)));


FileChannel inChannel=null;
FileChannel outChannel=null;

inChannel=in.getChannel();
outChannel=out.getChannel();

inChannel.transferTo(0, inChannel.size(), outChannel);
} catch (FileNotFoundException e) {
System.out.println("方法copyFileMethod: 复制模板文件出错......");
e.printStackTrace();
} catch (IOException e) {
System.out.println("方法copyFileMethod: 复制模板文件出错......");
e.printStackTrace();
}
}

/*
*输出文件
*/
public void outputReport(String filePath,String fileName) throws Exception{
System.out.println("导出文件路径:"+filePath +"; 导出文件名:"+fileName);
System.out.println("转换后的导出文件名:"+new String(fileName.getBytes("GBK"), "UTF-8"));
OutputStream ostream = null;
FileInputStream istream = null;
try{
ostream=response.getOutputStream();
byte b[]=new byte[1024];
File downFile = new File(filePath);
//response.setHeader("Content-disposition","attachment;filename="+fileName);
response.setHeader("Content-disposition","attachment;filename="+new String(fileName.getBytes("GBK"), "ISO8859-1"));
response.setContentType("application/zip");
long fileLength=downFile.length();
//String length=String.valueOf(fileLength);
String length=Long.toString(fileLength);
response.setHeader("Content_Length",length);
istream=new FileInputStream(downFile);
int n=0;
while((n=istream.read(b))!=-1){
ostream.write(b,0,n);
}
}catch(Exception e){
e.printStackTrace();
throw e;
}finally{
if(istream!=null){
try {
istream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(ostream!=null){
try {
ostream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}



==================================================下面粘贴一些原理=====================================================
iframe的readyState

最开始让我去研究这个问题是因为最近在做Excel数据导出时碰到的一个问题。导出Excel的基本做法是请求servlet生成一个Excel下载。由于是请求了一个不可见的iframe,所以整个请求过程一直到提示文件下载,除了能看见进度条在跑之外页面几乎没有任何反应,所以我想是不是可以做一个简单的提示正在下载文件之类的。做这个提示的关键就在于捕捉iframe的状态。

最开始大家都会想到用iframe的onload事件去判断iframe是否加载完毕。代码可能会这么写

<iframe id="f" src="demo.docx" style="display:none" onload ="iframe_onload()"  ></iframe>
但是事实上文件下载的iframe有别于contentType为text/plain的iframe。

在IE,Opera,Chrome下onload并没有执行iframe_onload。
在Firefox下可以执行。执行的顺序是先执行iframe_onload,然后再提示文件下载。

上面的小小挫折让我又想到了IE的onreadystatechange事件,代码写成这样:
<iframe id="f" src="demo.docx" style="display:none" border="0" onload ="iframe_onload()" onreadystatechange="iframe_readystatechange();"></iframe>
javascript方法:
        function iframe_onload (){
            alert("done.");
        }
        function iframe_readystatechange(){//IE works
            alert(document.getElementById("f").readyState);//interactive [prompt download file] complete
        }
有趣的是,IE执行的顺序是interavtive ,提示文件下载,complete。

有必要看看readyState的定义了。
readyState的五种状态详解

readyState有五种可能的值:
0 (未初始化): (XMLHttpRequest)对象已经创建,但还没有调用open()方法。
1 (载入):已经调用open() 方法,但尚未发送请求。
2 (载入完成): 请求已经发送完成。
3 (交互):可以接收到部分响应数据。
4 (完成):已经接收到了全部数据,并且连接已经关闭。

The state of the request. The five possible values are 0 = uninitialized, 1 = loading, 2 = loaded, 3 = interactive, and 4 = complete。

可以看出IE能捕捉到下载文件的iframe的interactive状态和complete状态。而且可以看出提示文件下载是在http请求的interactive也就是浏览器交互阶段。

如果把iframe中的src换成一个普通的URL。看到的提示是interactive->complete->loaded。这说明iframe的onload是在http请求的complete之后触发。而且在interactive和complete阶段,可以通过contentWindow.document访问到iframe中的DOM元素(当然,跨域还是不行的,跟ajax一样)。

在interactive阶段能访问到iframe的document。但是按照interactive的定义,正在处理相应数据,可以认为浏览器还在渲染请求到的HTML。渲染没有完毕,应该是不能访问的到iframe中的DOM元素的。

不管怎样,我倒是曾经利用onreadystate的方法改造过IE only的弹出iframe,大家知道用window.open弹出的窗口可以用window.close关闭的。但是如果弹出的iframe层也想用window.close()关闭,基本思路是在iframe的onload时重写iframe的close方法来关闭iframe。这样原来使用window.open打开的页面的代码就不需要修改了。实际上做的时候发现了这么个问题。就是如果window.open方法弹出的页面只有一个<script>window.close()</script>的话。iframe还是不能关闭。这时候可以在iframe的interactive就把iframe.close方法重写。这样,还是可以使用window.close方法关闭弹出层。

总之,利用iframe的onreadystatechange可以做很多的事情,遗憾的是,只有IE能做到这样的效果,其他浏览器iframe没有readyState属性。到目前为止,也没有发现能替代该属性的做法。由于不能兼容其他浏览器,请求隐藏iframe下载文件也变成了在新浏览器窗口下载Excel文件,但是这个过程加深了我对readyState的理解。



参考:http://www.blogjava.net/Hafeyang/archive/2010/12/12/readystate_property_of_iframe.html



@yanggaonanlu.pudongqu.shanghai  2014-07-12 0:23


1
0
分享到:
评论
2 楼 huaye2007 2014-07-12  
zhuyufufu 写道
你不想在下载时跳出新页面跳出新页面

你采用的是流输出的方式导出Excel

生成Excel的请求又没有复杂参数

这样的话就可以用以下简单方法实现:

location.href=生成Excel的请求链接


这样可以兼容多浏览器,也没有关闭新页面的烦恼,只要控制好进度的显示就ok了

恩,是的,window.open有时会自动打开在关闭的。
1 楼 zhuyufufu 2014-07-12  
你不想在下载时跳出新页面跳出新页面

你采用的是流输出的方式导出Excel

生成Excel的请求又没有复杂参数

这样的话就可以用以下简单方法实现:

location.href=生成Excel的请求链接


这样可以兼容多浏览器,也没有关闭新页面的烦恼,只要控制好进度的显示就ok了

相关推荐

    ajax实现excel报表导出

    利用ajax实现excel报表导出【解决乱码问题】,供大家参考,具体内容如下 背景 项目中遇到一个场景,要导出一个excel报表。由于需要token验证,所以不能用a标签;由于页面复杂,所以不能使用表单提交。初步考虑前端...

    Jquery ajax请求导出Excel表格的实现代码

    var exportExcel = export_excel; dataParams[exportExcel] = 1; var params = $.param(dataParams); var url = host+&+params; $('&lt;form method=post action=' + url + '&gt;&lt;/form&gt;').appendTo('...

    java导入导出全部文件jar包,ajax提交form表单返回提示数据

    java导入导出,全部文件jar包,ajax提交form表单后返回提示数据,所有用到的文件,方法,数据,有利于学习,方便运用

    导出动态生成的TABLE到EXCEL文件并下载.zip

    具体看我的博文:...如果table的内容是通过ajax,从后台获取到数据后提交json给前端再循环拼接table表格,再导出到Excel后发现只有表头,没有数据,数据部分是空白一片....这可咋整??

    PHP处理CSV表格文件的常用操作方法总结

    要做在线Excel表格编辑功能,Excel的xls文件格式的解析就是个问题,毕竟这是微软Office的私有专利格式. 所以要做的话还是用通用的csv(Comma Separated ...要实现phpMyAdmin那样细粒度双击单元格编辑,然后AJAX提交也不难,

    高考学校录取查询系统 v12.8.rar

    13.数据库信息自由导出到Excel,生成指定名称的Excel表,并可下载回本地查看或者打印,方便信息的查看\转移  \打印\统计\修改。 14.后台可以按指定的考生姓名或准考证号查询所有考生的信息。 15.管理员可以查询...

    购物商城源码 ShoppingMall.rar

    简单购物商城源码 源码描述: 一、源码介绍 ... 后台用户管理 可以导出excel文件 和插入excel文件 试用网站网址:前台:http://taofenboys.wang 后台: http://taofenboys.wang/AdminCenter/Login

    HS网络考试系统1.1(试用版)

    基于RKWeb1.1模板开发的网络考试应用系统,大量采用Ajax技术,支持自动题库抽题组卷,模拟考试, 题库试题Excel导入,印刷卷WORD导出,试卷自动打分等特色功能,具有组卷形式灵活,考试做题提交速度快等特点. 注意事项: ...

    房地产销售管理系统

    方便快捷,支持通过Excel文件批量导入导出各种数据,实现与第三方软件的无缝连接; 针对各种房地产公司的房产销售情况进行量身定做,对房产销售各个环节,节点实时控制;从而提高 公司的运营效率,特别是提高公司...

    房地产销售管理系统V3.0

    方便快捷,支持通过Excel文件批量导入导出各种数据,实现与第三方软件的无缝连接; 针对各种房地产公司的房产销售情况进行量身定做,对房产销售各个环节,节点实时控制;从而提高 公司的运营效率,特别是提高公司...

    oqss在线表单引擎2.5版

    产品简介 OQSS是智能的web表单引擎,专业的问卷调研调查软件,后台程序运行于web服务器,前台使用浏览器进行操作,同时也是在线的web表单...数据可导出为Excel文件 OQSS架构 B/S结构,.Net+AJAX+DB 内核:表单开发引擎

    ExtAspNet_v2.3.2_dll

    -使得Asp.net的控件ImageButton具有和Asp.net的Button控件类似的行为(Ajax提交)(feedback:261629698)。 +TabStrip增加GetAddTabReference和GetRemoveTabReference两个函数,用来向TabStrip控件动态增加删除Tab。...

    OQSS 在线问卷调查系统 v5.0.rar

    产品简介 OQSS是智能的web表单引擎,专业的问卷调研调查软件,后台程序运行于web服务器,前台使用...数据可导出为Excel文件 OQSS架构 B/S结构,.Net AJAX DB 内核:表单开发引擎 默认用户名hello@163.com 密码hello

    ExtAspNet v2.2.1 (2009-4-1) 值得一看

    -增加示例-如何将Grid控件导出为Excel(data\grid_excel_run.aspx)(feedback:503684912)。 -如果TreeNode的属性Enabled="false",则此项变灰并且不会被选中(feedback:your568)。 -修正TreeNode的属性NavigateUrl不...

    第三代移动WEB内核小程序风口-逐浪CMS2 x3.9.3全面发布

    ■增加:数据表自由导出为Excel(扩展--数据导出为Excel),自由导出您的任何意表单数据,对于站长业说可以更好的管理自主数据。 ■建站:版块表单功能,提交的表单后台存储 ■建站:模板增加预览功能(PC,iPad,iPhone) ...

    JavaScript完全自学宝典 源代码

    ajaxmodel.war Ajax实例应用的项目文件(可直接在Tomcat中发布运行)。 \ajaxmodel\amel\html\firstAjax.jsp 显示XMLHttpRequest对象状态。 \ajaxmodel\amel\html\userReg.html 完成验证的客户端页面。...

    蝙蝠在线考试系统v2.2.6 JSF2+SPRING+JPA

    蝙蝠在线考试系统基于JSF2、Spring3、JPA2等JAVA技术构建,系统使用MYSQL数据库,可以部署于WINDOWS、LINUX、UNIX等各种操作系统,内置了无处不在的AJAX能力,简洁易用,支持单选题、多选题、填空题、判断题、问答题...

    asp.net知识库

    SubmitOncePage:解决刷新页面造成的数据重复提交问题 SharpRewriter:javascript + xml技术利用#实现url重定向 采用XHTML和CSS设计可重用可换肤的WEB站点 asp.net的网址重定向方法的比较:面向搜索引擎友好 也谈 ...

    蝙蝠在线考试系统 2.2.8.rar

    蝙蝠在线考试系统是一个基于JSF2 Spring3 JPA2等JAVA技术构建的考试系统,使用MYSQL数据库,可以部署于WINDOWS、LINUX、UNIX等各种操作系统,内置了无处不在的AJAX能力,简洁易用,支持单选题、多选题、填空题、判断...

    商用版本文本编辑器DotNetTextBoxV6.0.8Source 源码

    (此功能测试稳定后会改为默认功能,即控件默认状态下输出的就是符合XHTML标准的代码,现在暂时请用xhtml属性来开启转换) 2008/6/23 Version 5.0.6 For VS2005/2008 Updates: 1)修正控件Length属性统计的字符数包含...

Global site tag (gtag.js) - Google Analytics