`

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表格的实现代码

    以上知识点覆盖了jQuery、AJAX、前端与后端交互、数据请求和处理、页面动态操作、以及代码的场景应用等多个方面,能够为开发者提供关于使用jQuery实现AJAX请求导出Excel表格功能的全面理解和实现细节。

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

    在Java开发中,数据的导入导出是一项常见任务,尤其涉及到与前端交互时,如使用Ajax提交form表单。这个场景通常应用于数据处理、报表生成、数据库操作等。本话题将详细探讨Java如何进行文件的导入导出,特别是Excel...

    jsp页面导出excel

    在JSP页面上,你可以使用表单提交或者JavaScript AJAX请求触发导出操作。例如,一个简单的表单提交: ```jsp 导出Excel ``` 5. **安全性和性能优化** 当处理大量数据时,注意内存管理和性能优化。可以...

    Java表格数据导出Excel&Excel数据导入到数据库

    在前端,用户选择文件后,`ajaxFileUpload.js`通过Ajax技术向服务器发送请求,而不是传统的表单提交方式,这样可以避免页面刷新。它使用XMLHttpRequest对象实现异步通信,并且可能使用了FormData对象来封装文件,...

    jquery导出Excel.rar

    在实现Excel导出的过程中,通常会涉及到Ajax请求,这是jQuery库的一个核心特性。使用$.ajax()方法,我们可以异步发送HTTP请求到服务器,获取或者提交数据。例如,我们可以发送一个POST请求,将需要导出的数据发送到...

    C#-Excel导入导出

    在给定的压缩包文件中,"jquery-1.7.2.js"和"jquery.form.js"是JavaScript库,它们可能用于前端与后端C#服务器进行异步交互,比如在导入导出Excel时,使用AJAX提交表单,实现无刷新页面效果。jQuery Form插件提供了...

    thinkphp5整合excel导入导出

    在开发Web应用时,数据处理是一项重要任务,尤其是在企业级应用中,经常需要与Excel文件进行交互,如导入数据、导出数据等。ThinkPHP5作为国内广泛应用的PHP框架,提供了一种方便的方式来实现这样的功能。本文将详细...

    asp+excel+ajax成绩查询系统

    在成绩查询系统中,Ajax可能用于异步提交查询请求,快速返回结果,减少用户等待时间。JavaScript库如jQuery的Ajax函数可以轻松实现这一功能。 4. **C#**:虽然标题中没有明确提及,但在ASP.NET框架下,C#是常用的...

    基于Web的问卷调查统计结果写入导出Excel小实例_问卷系统_问卷调查_

    - **AJAX**:无刷新提交,提高用户体验,防止页面刷新导致数据丢失。 - **服务器端验证**:确保接收到的数据有效且符合预期,防止恶意输入。 4. **问卷统计**: - **数据分析**:对收集到的答案进行统计,计算每...

    jsp导出excel

    1. **用户交互**:用户在网页上点击“导出”按钮,触发一个AJAX请求或者直接提交表单到服务器。 2. **服务器处理**:在Servlet中,接收到请求后,利用Apache POI库创建Excel文件。这包括创建HSSFWorkbook对象,根据...

    jxl以及jquery的form提交

    例如,你可以创建一个表单让用户选择Excel文件,然后使用`jQuery.form`进行AJAX提交,后端使用`jxl`读取和处理文件内容,最后返回处理结果。 总之,`jxl`和`jQuery.form`分别是Java和前端JavaScript领域处理Excel...

    Excel导入导出工具类

    在前端(JS代码),用户交互部分通常包括选择文件、提交表单以及显示导入/导出进度。可以使用HTML5的File API来获取用户选择的文件,通过Ajax发送到后端。对于导出,后端生成Excel文件后,通常会以流的形式返回,...

    Ext增删改查和excel导出

    在"Ext增删改查和excel导出"这个主题中,我们将探讨如何在ExtJS应用中实现数据的CRUD操作(创建、读取、更新、删除)以及如何将数据导出为Excel格式。 1. 创建(Create) 在ExtJS中,可以使用GridPanel或FormPanel...

    Java导出Excel的各种尝试

    当尝试使用Ajax异步请求导出Excel时,由于Ajax默认处理JSON或文本数据,而无法直接处理二进制文件流,如Excel文件。浏览器无法识别这种请求为下载操作,因此导致导出失败。为解决此问题,可以尝试使用`window....

    struts2实现excel导出

    在前端(如JSP页面),创建一个表单或者使用Ajax来提交请求。确保请求参数能够携带需要导出的List数据。 通过以上步骤,你就可以在Struts2应用中实现Excel导出了。需要注意的是,实际项目中可能需要处理更复杂的...

    ASP.NET-[其他类别]仿Google查询并导出Excel源码.zip

    这涉及到HTML、CSS和JavaScript的交互,可能使用AJAX异步提交搜索请求。 - 数据获取:模拟搜索可能通过爬虫技术抓取网页内容,或者使用现成的API(如Google Custom Search API)进行搜索,但请注意,未经授权的谷歌...

    domino xpags 开发 Excel导入导出完整例子

    在XPages中,可以利用JavaScript库,如js-xlsx,来读取和解析Excel文件,然后将数据提交到服务器进行处理。 总结来说,这个压缩包提供的内容涵盖了使用Lotus Domino XPAGS进行Excel导入导出的关键技术和步骤,包括...

Global site tag (gtag.js) - Google Analytics