JXL通过AJAX将数据导出到Excel中

这篇博文写的对别人没有什么参考价值,仅仅给自己留个思路。

以前因为时间的原因导数据到Excel中用的是JS,也没有大数据的测试,结果到后来一碰上大数据就宕机。最近终于抽时间好好来琢磨这个问题啦,改从服务器端导数据。

前面的博文中其实也有提到用JXL导数据,但是导出的数据比较少,是直接将需要导出的数据拼接成字符串然后传到后台一个一个弄到Excel中的,大数据的话就不适用了。另外,以前的那个用的直接跳servlet,这回跳不了(因为总会报错——Cannot reset buffer after response has been committed,导致Ajax失败),所以只能用Ajax了。

用AJAX还有个毛病,等分两步:第一步使用AJAX生成Excel文件,并返回Excel的文件路径及名称。第二步:模拟访问该Excel进行下载。

说一下业务吧:

1、导入到Excel中的数据是存在数据库中,直接取,这个容易;

2、但是页面信息如从哪个表取数据、取哪些字段也是存在数据库里面的而且是变动的,这个比较难,需要根据给定的“视图编号”去查表(from )、查条件(where)、查排序(order by),通过JS从页面获取显示的字段信息(select)、需要导入的数据信息(取那几条)并传入后台用来查数据。

难点就在于:找表,找查询条件,找排序信息,找字段,拼接指定的数据信息

1、下面这段JS是触发点,也就是点某个按钮时触发tableList_excel()方法,这个方法首先判断是否有告知从哪儿取数——这个很重要,关系到from、where、order by,其次判断有没有选定要导出来的数据——这个也很重要,至少得告诉我你要导哪些数据吧,最后根据选定的数据条数来判断是使用客户端导数据还是使用服务器端,之所以设置为10条,一是每页显示的是10条,而是10条数据不是很多用JS导不算久,客户等的起。

//将选定数据导出到Excel中
function tableList_excel(obj){
	//1、判断是否指定获取数据的表
	var viewID=null;
	if($(obj).is("[viewID]")){
		viewID=$(obj).attr("viewID");
	}else{
		alert("缺少:viewID属性,无法获取选择参数");return ;
	}
	viewID = jQuery.trim(viewID);
	var rows = $("#table_"+viewID+">tbody>tr>td :checkbox:checked").length;
	//2、判断是否选定数据
	if(rows<=0){//说明没有选数据
		doalert("请选择要导出的数据!");
		return false;
	}
	
	//3、根据选取的行数判断使用服务器导出还是客户端导出
	if(rows>10){//多于10条,使用服务器导出数据
		 exportToExcelForServer(viewID);
		 return false;
	}else{//少于10条时直接用客户端导出
		exportToExcelForClient(viewID,0);
		return false;
	}
	return ;
}

 2、这个是用客户端导的数据,就是用ActiveX插件导,比较简单,一个一个td取值,一个一个单元格放数据,数据较多时浏览器容易卡死。

/**
 * 通过客户端导出数据到Excel中
 * @param viewID:数据源所在的视图ID
 * @param flag:服务器端导出是否出错,默认为0
 * */
function exportToExcelForClient(viewID,flag){
	//若使用客户端判断是否支持ActiveX插件,若是支持使用插件导出,否则用服务器端导出
	try {
		var oXL = new ActiveXObject("Excel.Application"); //创建excel应用程序对象
	}catch(e) {//可能不是IE,也可能是IE没有启用ActiveX控件,使用服务器导出数据
		if(flag==1){//说明服务器端导出出错,且没有启用ActiveX控件,那么提示
			alert("要将该表导出到Excel,您必须安装Excel电子表格软件,同时浏览器须使用“ActiveX 控件”,您的浏览器须允许执行控件。\n请到公共模块-下载中心查找相应帮助文档");
		}else{//说明可以用服务器端导出
			exportToExcelForServer(viewID);  
		}
	    return;
	}
	//使用ActiveX插件导出
	var oWB = oXL.Workbooks.Add(); //创建工作簿
	var oSheet = oWB.ActiveSheet;  //获取当前活动的工作簿
	oSheet.Columns.AutoFit;//设置自动调整列宽
	var $head = $("#table_"+viewID+">thead>tr.tabFirstTr>td:visible");
	var $body = $("#table_"+viewID+">tbody>tr>td :checkbox:checked").parent().parent().parent("tr");
	oSheet.Rows(1).RowHeight = 23;//行高
	//标题行
	var headText = null;
	var checkboxNum="";
	var count=0,count2=0;
	$head.each(function(){
		if($(this).is("[MSelect]")){
			checkboxNum=count;
			return ;//不执行该循环,直接下一个循环
		}
		headText = (isempty($(this).attr("title"))?$(this).text():$(this).attr("title"));
		oSheet.Columns(count+1).ColumnWidth = 23;//列宽
		oSheet.Cells(1,count+1).Font.Bold=true;//加粗
		oSheet.Cells(1,count+1).Font.Size=14;
		//设置单元格底色(1-黑色,2-白色,3-红色,4-绿色,5-蓝色,6-黄色,7-粉红色,8-天蓝色,9-酱土色)
		oSheet.Cells(1,count+1).Interior.ColorIndex = 35;//浅绿色  
		oSheet.Cells(1,count+1).HorizontalAlignment = 3;//水平对齐方式:居中
		oSheet.Cells(1,count+1).VerticalAlignment = 2;//垂直对齐方式:居中
		oSheet.Cells(1,count+1).Borders.Weight = 2; //设置单元格边框*()
		oSheet.Cells(1,count+1).Value = (isempty($(this).attr("alias"))?headText:$(this).attr("alias"));//设置标题的内容
		count++;
	});
	//内容行
	var tdText=null;
	var tdArray=null;
	$body.each(function(m){
		count2=0;
		oSheet.Rows(m+2).RowHeight = 23;//行高
		$(this).children("td:visible").each(function(n){//td的内容
			oSheet.Columns(count2+1).ColumnWidth = 23;//列宽
			if(n==0){//说明是序号列
				tdText=m+1;
			}else{
				if(n==checkboxNum){
					return ;//说明是复选框,直接跳出
				}
				tdText = isempty($(this).attr("title"))?$(this).text():$(this).attr("title");//先取title属性的值,若没有则取text()
				tdArray= tdText.split(",");
				if(tdArray.length==1){
					tdArray= tdText.split(",");
				}
				//处理"当数据用,号隔开,倒入到Excel时,Excel自动用科学技术发表示"的情况
				if(!isempty(tdText) && tdArray.length>1 && (jQuery.trim(tdArray[0]).length==jQuery.trim(tdArray[1]).length)){
					tdText = replaceAll(tdText,",",";");
					tdText = replaceAll(tdText,",",";");
				}
			}
			oSheet.Cells(m+2,count2+1).Interior.ColorIndex = 35;//浅绿色 
			oSheet.Cells(m+2,count2+1).HorizontalAlignment = 3;//水平对齐方式:居中
			oSheet.Cells(m+2,count2+1).VerticalAlignment = 2;//垂直对齐方式:居中
			oSheet.Cells(m+2,count2+1).Borders.Weight = 2; //设置单元格边框*()
			oSheet.Cells(m+2,count2+1).Font.Size=12;//12号字体
			oSheet.Cells(m+2,count2+1).Value = tdText;
			count2++;
		});
	});
	oXL.Visible = true; //设置Excel的属性
	oXL.UserControl = true;
	oSheet = null;
	oWB = null;
	oXL = null;
}
 3、这个是服务器端导数据,用的JXL。第一步获取参数键,这个参数键用来匹配主键参数键提高性能和精确度的;第二步获取标题,其实获取的是绑定字段的序号——这个绑定字段是存在数据库中的,是变动的,因为通过序号可以获取到除了标题之外别的以后可能要用的数据;第三步获取参数集合,也就是要到导出的数据信息。第四步拼接成XML通过AJAX提交导后台处理并返回生成的Excel文件路径及名称,并采用模态进行下载。
/**
 * 通过服务器端导出数据到Excel中
 * @param viewID:数据源所在的视图ID
 * */
function exportToExcelForServer(viewID){
	//1、获取参数键
	var runKey="";
	$("#table_"+viewID+">thead>tr.tabFirstTr").children("td[isPK]").each(function(){
		runKey +=","+$(this).attr("isPK");//获取参数集合
	});
	if(runKey.length>1){
		runKey = runKey.substring(1);
	}else{//弹出提示
		alert("无法获取参数键集合");
		return false;
	}
	
	//2、获取标题
	var titleStr="",headText="",dbStr="",dbText="";
	$("#table_"+viewID+">thead>tr.tabFirstTr").children("td:visible").each(function(){
//		headText = (isempty($(this).attr("title"))?$(this).text():$(this).attr("title"));
//		titleStr +=","+(isempty($(this).attr("alias"))?headText:$(this).attr("alias"));//设置标题的内容
		dbText = $(this).attr("databindId");
		if(!isempty(dbText)){
			dbStr +=","+dbText;
		}
	});
//	titleStr = titleStr.split(",,")[1];//,,是复选框导致的所以可以直接截取
	dbStr=dbStr.substring(1);//将第一个逗号截去
//	alert(dbStr);
	
	//3、获取参数集合
	var datas="<datas>";
	$("#table_"+viewID+">tbody>tr>td :checkbox:checked").each(function(){
		//去含有isPK属性的值
		var tr_obj=$(this).parent().parent().parent();
		datas+="<row>";
		$(tr_obj).find("td[isPK]").each(function(){
			//获取td的内容
			var tdContent=$(this).attr("title");
			//获取isPK的值
			var isPKVal=$(this).attr("isPK");
			datas+="<col key=\""+isPKVal+"\" val=\""+EscapeSymbol(tdContent)+"\"/>";			
		});		
		datas+="</row>";
	});
	datas+="</datas>";
	
	var xml="<tsp><relatedBIDS>"+runKey+"</relatedBIDS><databindid>"+dbStr+"</databindid><viewid>"+viewID+"</viewid>"+datas+"</tsp>";
//	alert(xml);
	var param = {"parametersStr":xml,"time":new Date()};
	param = JSON.stringify(param);//将Object类型的param转成字符串  
//    alert(param);  
    $.ajax({
		url :"fileRouter!exportToExcel.action",
		async :false,
		type :"post",
		dataType :"text",
		data : {"param":param},		
		error : function(C) {
			exportConfirm(viewID);
		},
		success : function(C) {
			if(C.toString()!="false"){//说明是访问成功了,返回的是Excel文件的路径和名称
				//从后台获取Excel文件模拟下载 
			    var urls = "fileRouter!downloadExcelFile.action?nodeid=0&path="+C;  
			    if ($("#bodyFileDown").length <1){  
			        $("body").append("<iframe id='bodyFileDown' src='' ></iframe>");  
			        $("#bodyFileDown").hide();  
			    }  
			    $("#bodyFileDown").attr("src", urls);//设置src属性,iframe通过src自动请求Servlet 
			}else{
				exportConfirm(viewID);//导出失败,询问意见是否使用客户端导出
			}							
		}
	});
}
 4、这个方法是为了防止服务器导出数据失败,到时可以建议采用客户端导数据。因为客户端导数据除了慢之外其他还是比较靠谱的。

相关推荐