`

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、这个方法是为了防止服务器导出数据失败,到时可以建议采用客户端导数据。因为客户端导数据除了慢之外其他还是比较靠谱的。
/***
 * 导出确认提示框
 * viewID:参数键名称
 * */
function exportConfirm(viewID){
	if(confirm("服务器端导出失败!试图尝试用客户端导出,导出较慢,是否继续?")){
		exportToExcelForClient(viewID,1);
	}
}
 5、exportToExcel()方法就是根据传递过来的参数用来生成Excel文件的,它只负责生成Excel文件,并不提供下载。生成的Excel背景色是护眼色,有边框,12号字体,有sheet名,有标题,有自动生成的序号,看着还挺舒服。
/**
 * 将选定数据导出到Excel中
 * */
public void exportToExcel() throws Exception{
	HttpServletRequest request = ServletActionContext.getRequest();
	HttpServletResponse response = ServletActionContext.getResponse();
	Object userInfo = request.getSession().getAttribute("userInfo");
	SUser user=null;
	if(userInfo==null){
		throw new TspException("获取用户信息失败:userInfo=null");
	}else{
		user = (SUser)userInfo;
	}
	
	String param = "1"; 
	String result="false";
    //获取传递过来的参数值  
    if(null!=request.getParameter("param") && !"".equals(request.getParameter("param"))){  
        param = request.getParameter("param");  
    }  
    param = new String(param.getBytes("ISO8859-1"),"UTF-8");//解决乱码的问题  
    if(!param.equals("1")){//说明有传递参数  
        JSONObject jsobj = JSONObject.fromObject(param);  
        String parametersStr = jsobj.getString("parametersStr");//参数  
        //String dbStr = jsobj.getString("dbStr");//数据绑定编号
        //String titleStr = jsobj.getString("titleStr");//标题
        
        try {  
        	Parameters paramters=getParameters(parametersStr);//解析传递过来的XML
        	List<Object[]> dataList = dataEngine.getTableData(paramters,user,1);//拼接SQL获取查询结果
        	if(dataList!=null && dataList.size()>0){            	
        		String fileName = System.currentTimeMillis()+".xls";//以当前时间作为Excel的名称:2003版本的  
                File saveDir = initFileDir();//获取Excel文件导出后保存路径
//	            	System.out.println(saveDir+ java.io.File.separator + fileName);  
                String filePath = saveDir+ java.io.File.separator + fileName;
                File excel = new File(filePath);  
                 
                //工作簿名称 list
                WritableWorkbook workBook = Workbook.createWorkbook(excel);//创建可写入的Excel工作薄  
                Object [] sheetName= dataList.get(dataList.size()-1); 
                WritableSheet sheet = workBook.createSheet(sheetName[0].toString(), 0);//生成名为“当前视图名称”的工作表,参数0表示这是第一页,1表示第二页,以此类推  
                  
                /** 
                 * 定义excel主标题的格式 
                 */  
                WritableFont title2 = new WritableFont(WritableFont.ARIAL,12,WritableFont.BOLD);//加粗  
                WritableCellFormat titlewcf = new WritableCellFormat(title2); // 单元格定义  
                titlewcf.setAlignment(jxl.format.Alignment.CENTRE); //设置对齐方式  
                titlewcf.setBorder(Border.ALL, BorderLineStyle.THIN);//设置边框样式  
                titlewcf.setBackground(Colour.LIGHT_GREEN);//设置背景色  
                  
                /** 
                 * 定义excel列标题的格式 
                 */  
                WritableFont wf = new WritableFont(WritableFont.ARIAL,14,WritableFont.BOLD);//加粗  
                WritableCellFormat wcf = new WritableCellFormat(wf); // 单元格定义  
                wcf.setAlignment(jxl.format.Alignment.CENTRE); // 设置对齐方式  
                wcf.setBorder(Border.ALL, BorderLineStyle.THIN);//设置边框样式  
                wcf.setBackground(Colour.LIGHT_GREEN);//设置背景色  
                  
                /** 
                 * 定义excel内容的格式 
                 */  
                WritableFont comtent = new WritableFont(WritableFont.ARIAL,10,WritableFont.NO_BOLD);//常规  
                WritableCellFormat comtent_c = new WritableCellFormat(comtent); // 单元格定义  
                comtent_c.setAlignment(jxl.format.Alignment.CENTRE); // 设置对齐方式  
                comtent_c.setBorder(Border.ALL, BorderLineStyle.THIN);//设置边框样式  
                comtent_c.setBackground(Colour.LIGHT_GREEN);//设置背景色  
                 
                String objStr="";
                //遍历“标题”内容并添加到Excel中
                Object [] title = dataList.get(dataList.size()-2);//倒数第一个是sheet名称,倒数第二个才是标题,所以需要减去2  
            for(int i=0;i<title.length;i++){  
                sheet.setColumnView(i, 23);//设置列宽
                sheet.setRowView(0, 20*23,false);//设置单元格的高度,目前为23,高度大概得设置成Excel里面行高的20倍才能达到相应的效果
                objStr=(title[i]==null?"":title[i].toString());
                Label label=new Label(i,0,objStr,wcf);//在第一行中添加文本类单元格  
                sheet.addCell(label);  
            }  
                  
                //遍历list中的内容并添加到Excel中
                for(int i=0;i<dataList.size()-2;i++){  
                	Object [] objs= dataList.get(i);  
                    for(int j=0;j<objs.length;j++){
                         sheet.setRowView(i+1, 20*23,false);//行高
                    	objStr=objs[j]==null?"":objs[j].toString();
//	                    	System.out.println(i+"        "+j+"    "+objStr);
                    	//添加序号列
                    	Label orderLabel = new Label(0,i+1,new Integer(i+1).toString(),comtent_c);//第一列为序号列
                        sheet.addCell(orderLabel); 
                        
                    	Label label = new Label(j+1,i+1,objStr,comtent_c);//从第二行开始添加单元格,第一行是标题  
                        sheet.addCell(label);  
                    }  
                }  
                //在Excel中写入数据并关闭文件  
                workBook.write();  
                workBook.close();  
                
                result=filePath;
        	}
        } catch (Exception e) {  
            e.printStackTrace();  
        }finally{
			response.setCharacterEncoding("UTF-8");
			response.setContentType("text/html");
			response.setHeader("Pragma", "No-cache");
			response.setHeader("Cache-Control", "no-cache");
			response.setHeader("Cache-Control", "no-store");
			response.setDateHeader("Expires", 0);
			response.getWriter().write(result);
			response.getWriter().flush();
			response.getWriter().close();
		}  
    } 
}
 

6、以下方法用来下载文件。值得注意的是:

a、一定要设置头文件,否则系统会自动将文件以txt的形式下载

b、总是会报错(具体问题忘记了),但是不影响系统运行(这也就是为什么要分两步走的原因,报错导致Ajax失败不能继续执行)

/**
 * 下载指定Excel文件
 * */
public void downloadExcelFile(){
	HttpServletRequest request = ServletActionContext.getRequest();
	HttpServletResponse response = ServletActionContext.getResponse();
    String path = null;
    if(null!=request.getParameter("path") && !"".equals(request.getParameter("path"))){  
    	path = request.getParameter("path");  
    }
    try{
        File excel = new File(path);
        FileInputStream in = new FileInputStream(excel);
//这个头文件很关键,必须告知filename,否则系统会自动将文件以txt的形式下载,且文件名称为请求的Servlet/Action名称(如文件名称:ExcelServlet.txt)  
        response.setHeader("Content-Disposition", "attachment; filename="+ new String(excel.getName().getBytes("GB2312"),"ISO-8859-1"));
        //response.reset();//解决:getWriter() has already been called for this response的问题  
        OutputStream outputStream = response.getOutputStream();  
        int i = 0;  
        byte b[] = new byte[1024];  
        while ((i = in.read(b)) != -1) {//读取Excel文件  
            outputStream.write(b, 0, i);//写入到页面提供下载  
        }  
        outputStream.flush();  
        outputStream.close();  
        outputStream=null;  
        response.flushBuffer(); 
    }catch(Exception e){
    	e.printStackTrace();
    }
}
 7、这三个方法是辅助方法,第一个方法用来解析前台传递过来的XML文件并填充到各个属性中;第二个方法用来初始化文件目录,首先从配置文件中获取文件目录,若有配置就采用配置的目录,否则手动指定目录,然后判断指定的目录是否存在,若不存在就新建目录,若存在先删除目录下指定的文件,也就是第三个方法的功能,它主要用来删除今天以前的文件,因为每次导数据都会生成一个Excel文件,时间久了占用的空间会很大,所以每次导之前都自动删除掉以前的文件避免空间不足的问题。
/***
*解析字符串并返回Parameters对象,可以通过访问该对象的属性值获取从前台传递过来的对应参数
*@param parametersStr:字符串类型的XML
*/
public Parameters getParameters(String parametersStr) {
	logger.debug(parametersStr);
	return ParametersUitls.getParametersByStrForXML(parametersStr);
}

/** 
 * 导出数据时,先判断指定目录是否存在,若不存在则新建 
 * 若存在,则删除指定目录下的文件,避免每次下载都生成文件导致硬盘容量不够 
 */  
public File initFileDir() {  
	String savePath = WebAppConfig.app("excelDir");//从配置文件中获取保存Excel的目录
	savePath=savePath.trim();
	if(savePath==null || savePath.equals("null") || savePath.length()<=0 ){
		savePath = "D:"+java.io.File.separator+"bfp"+java.io.File.separator+"ed";//手动拼接文件目录
	}
    File saveDir = new File(savePath);    
    if(!saveDir.exists() || !saveDir.isDirectory()){//指定目录不存在则新建   
        saveDir.mkdir();    
    }else{//若是已经存在,那么删除里面的内容,避免每次下载都生成文件导致硬盘容量不够  
      deleteFiles(saveDir);  
        //saveDir.mkdir();   
    } 
    return saveDir;
}  
  
/** 
 * 删除文件 
 * @param file:File类型,指定要删除的文件 
 * */  
private void deleteFiles(File file){
	Calendar cal = Calendar.getInstance();
	Calendar cal2 = Calendar.getInstance();
	cal2.setTime(new Date());//设置当前时间
	int day1=0,day2=0;
    if(file.isDirectory()){  
        File[] files = file.listFiles();//获取指定目录下的所有文件  
            for(int i=0;i<files.length;i++){
                cal.setTimeInMillis(files[i].lastModified()); //获取文件的最后修改时间并设置为Calendar的前时间值
                if(cal2.get(Calendar.YEAR)-cal.get(Calendar.YEAR)>0){//說明是以前的文件,那麼直接刪除
                	//System.out.println("修改时间[1] " + cal.getTime().toLocaleString());
                	//System.out.println("修改时间[2] " + cal2.getTime().toLocaleString());
                	deleteFiles(files[i]);
                }else{//說明是今年或以後的文件
//                    	 System.out.println("修改时间[3] " + cal.getTime().toLocaleString());
//                    	 System.out.println("修改时间[4] " + cal2.getTime().toLocaleString());
                	 day1= cal.get(Calendar.DAY_OF_YEAR);
                     day2 = cal2.get(Calendar.DAY_OF_YEAR);
                      if((day2-day1)>0){//說明是今天之前的文件
                    	  deleteFiles(files[i]);
                      }
                }
             }  
    }  
    file.delete();//删除文件  
}
 8、以下是拼接SQL获取数据集合的方法,需要说明的一点:系统里面在获取选定的数据时有两种处理方式,一种找当前表的主键一旦找到即用主键信息进行查找,若找不到就采用其他字段联合起来查询。
/**
 * 根据传递的参数获取需要导出到Excel中的数据
 * @param params:包括参数键值和需要显示的数据绑定ID
 * @param userinfo:当前登录人ID
 * @param flag:查询标记 1-模糊查询 0-精确查询
 * */
public List<Object[]> getTableData(Parameters params, SUser userinfo,int flag) throws Exception{
	List<Object[]> list=null;
	SView view = viewdao.findById(Integer.parseInt(params.getViewid()));//获取视图信息,方便获取sheet名称,from,where,order by等信息
	if (view == null) {
		logger.error("获取视图实体失败!");
		return null;
	}
	getParams(params);//将fieldList和queryList赋值
	String dbId = params.getDatabindid();//获取需要导出的数据信息
	dbId = dbId.trim();
//		System.out.println(dbId);
	if(dbId!=null && dbId.length()>0){
		String tableid="",fieldStr="",fieldid="",tafd="";;
		String[] aliasStr=null;//声明数组用来储存Excel的标题信息(即第一行的标题信息)
		String PKMapkey = "",mapkey="";
		String runKey = params.getRelatedBIDS();//参数键集合
		String PKField="",MKey="";
		//1、处理select字段
		String hql="from com.tzj.tsp.entity.SDatabindView where SViewId="+ view.getSViewId() +" and SDatabindId in ("+ dbId +")";
		List<SDatabindView> databingviewlist =databindviewdao.get(hql);
		SDatabindView dbView=null;
		if(databingviewlist!=null && databingviewlist.size()>0){
			aliasStr = new String[databingviewlist.size()+1];//分配内存空间
			aliasStr[0]="序号";
			for(int i=0;i<databingviewlist.size();i++){
				dbView = databingviewlist.get(i);
				tableid= dbView.getEntityname();//获取表名
				fieldid = dbView.getAttributephysic();//获取字段名称
				String bieming=tableid;
				if(bieming.length()>7)bieming=bieming.substring(0, 6);
				tafd= tableid + "." + commonxml.tableAndField(fieldid);//拼接字段
				if(dbView.getOcxtype()!=null){
					tafd= commonxml.tableField(tafd, dbView.getOcxtype());
					if(dbView.getOcxtype()==28 || dbView.getOcxtype()==32){//单位件上传、单图片上传:多文件多图片上传类型的暂时不支持
						tafd="(select FILENAME from S_ACCESSORIES where ID="+tafd+")";//将文件序号替换成文件名称(表中只保存文件序号,其他的文件信息保存在S_ACCESSORIES表中)
					}
				}
				/*
				if(dbView.getStaticcontent()!=null && (!dbView.getStaticcontent().equals(""))){
					//统一转换成字符型数据 fieldid 表示别名
					tafd=commonxml.staticValue(tafd, dbView.getStaticcontent());
				}
				*/
				aliasStr[i+1]=dbView.getAlias();
				fieldStr += "," + tafd+" "+bieming+"_"+fieldid;
			}
		}
		//2、处理from
		String selectcondition = view.getSelectcondition();
		//3、处理where:原视图中有的条件
		String querySQL = view.getQuery();
		// 替换 selectcondition与query 中的标记
		if (fieldList != null && fieldList.size() > 0) {
			for (int j = 0; j < fieldList.size(); j++) {
				if (fieldList.get(j) != null) {
					Map<String, String> mapfield = fieldList.get(j);
					Set<String> con = mapfield.keySet();
					for (String c : con) {
						String key = "<" + c + ">";
						if(querySQL!=null && (!querySQL.equals(""))) {
							querySQL = querySQL.replaceAll(key, mapfield.get(c));
						}
						selectcondition = selectcondition.replaceAll(key,mapfield.get(c));
					}
				}
			}
		}
		//3、处理where:选定的数据
		String hql2="from com.tzj.tsp.entity.SDatabindView where SViewId="+ view.getSViewId() +" and (key>0 and key<>93) order by key asc";
		List<SDatabindView> sdbViewList = databindviewdao.get(hql2);
		SDatabindView sdbView = null;
		if(sdbViewList!=null && sdbViewList.size()>0 ){
			for(int i=0;i<sdbViewList.size();i++){
				sdbView = sdbViewList.get(i);
				tableid = sdbView.getEntityname();
				fieldid = sdbView.getAttributephysic();
				tafd= tableid + "." + commonxml.tableAndField(fieldid);
				if(sdbView.getOcxtype()!=null){
					tafd= commonxml.tableField(tafd, sdbView.getOcxtype());
				}
				if(sdbView.getStaticcontent()!=null && (!sdbView.getStaticcontent().equals(""))){
					//统一转换成字符型数据 fieldid 表示别名
					tafd=commonxml.staticValue(tafd, sdbView.getStaticcontent());
				}
				PKField=commonxml.getPrimaryKey(tableid); //获取主键所在列
				MKey=sdbView.getKey().toString();//获取参数键
				if(fieldid.equals(PKField) && runKey.indexOf(("M"+MKey))!=-1){//说明当前字段与主键所在列相同,且参数键在给定的参数键中
					if (fieldList != null && fieldList.size() > 0) {
						mapkey="";
						for (int j = 0; j < fieldList.size(); j++) {
							Map<String, String> mapfield = fieldList.get(j);
								String value = commonxml.getValueByTypeOn(0,sdbView.getAttributedetype(), mapfield.get("M"+ MKey));
								if (mapkey.equals(""))mapkey = tafd + "=" + value;
								else {
									if(flag==0) mapkey += " and " + tafd + "=" + value;
									else mapkey += " or " + tafd + "=" + value;
								}
						}
						break;//找到对应主键数据之后结束循环
					}
				}else{//说明当前字段与主键所在列不相同
					if (fieldList != null && fieldList.size() > 0) {
						for (int j = 0; j < fieldList.size(); j++) {
							Map<String, String> mapfield = fieldList.get(j);
								String value = commonxml.getValueByTypeOn(0,sdbView.getAttributedetype(), mapfield.get("M"+ MKey));
								if (mapkey.equals("")) mapkey = tafd + "=" + value;
								else {
									if(flag==0)	mapkey += " and " + tafd + "=" + value;
									else mapkey += " or " + tafd + "=" + value;
								}
						}
					}
				}
			}
			
		}
		
		//4、处理order by
		String orderSQL = view.getOrdersql();
		
		if(fieldStr.length()>1) fieldStr= fieldStr.substring(1);//除去第一个逗号
		//System.out.println(aliasStr+"\n"+fieldStr);
		
		String sql=" select "+fieldStr;
		if(querySQL!=null && (!querySQL.equals(""))) {//说明原来的where字段中就有条件
			//判断是否有<M,<E,<Q打头的数据,若有那么视图中的querySQL不拼接到SQL中,否则拼接
			if(querySQL.indexOf("<M")==-1 || querySQL.indexOf("<E")==-1 || querySQL.indexOf("<Q")==-1){
				querySQL="";//因为有不能替代的参数存在,SQL无法执行,所以去除当前查询条件
			}
		}
		if(querySQL!=null && (!querySQL.equals(""))){
			if (mapkey != null && mapkey.trim() != "") {querySQL = querySQL + " and (" + mapkey+")";}
		}else{
			if (mapkey != null && (!mapkey.trim().equals("")))querySQL = mapkey;
		}
		
		if(querySQL!=null && (!querySQL.equals("")))
			sql = sql + " from " + selectcondition + " where " + querySQL + " ";
		else
			sql = sql + " from " + selectcondition;
		if(orderSQL!=null && (!orderSQL.equals("")))sql = sql +" "+ orderSQL;
		if (userinfo != null) {sql=formatSQL(userinfo,sql);}
		//String sql2 = this.getTableSQL(view, fieldList, queryList, userinfo, params.getOrderList(), flag);
		list = execSQL.selectQuery2(sql);
		if(list!=null && list.size()>0){//说明查询之后有结果
			list.add(aliasStr);//保存别名用作Excel的标题
			list.add(new String[]{view.getViewname()});//保存视图名称作为工作簿名称
		}
	}
	return list;
}

 9、以下的方法用来查询SQL并将结果以数组的形式添加到List中,一条数据作为一个数组,一个字段作为一个数组中的一个值,最后返回包含多个Object数组的List集合。

/***
 * 执行sql语句获得结果集
 * 
 * @param sql
 * @return Object数组
 */
@SuppressWarnings("unchecked")
public List<Object[]> selectQuery2(final String sql) throws Exception {
	log.debug("执行sql语句: " + sql);
	List<Object[]> result=null;
	try {
		if(!this.checkSQL(sql)){
			throw new Exception("sql语句【"+ sql +"】不正确!");
		}
			result = (List<Object [] > ) getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session arg0) throws HibernateException,
					SQLException {
				return arg0.createSQLQuery(sql).list();
			}
		});
	} catch (Exception e) {
		System.out.println("ERROR:" + e.getMessage());
		log.info("执行sql:[" + sql + "]失败:" + e.getMessage());
		log.error("执行sql:[" + sql + "]失败:" + e.getMessage(), e);
		throw e;
	}
		if(result!=null && result.size()>0){
			return result;
		}else{
			return null;
		}
}

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics