1. 程式人生 > >js下載檔案以及下載檔名亂碼問題的解決

js下載檔案以及下載檔名亂碼問題的解決

原文連結    js傳送post請求下載檔案

關鍵點:

1.封裝form表單提交,做成類似post請求傳遞多引數下載檔案的效果。

2.請求引數亂碼的簡單紀要

3.下載功能,中文檔名的亂碼解決

4.下載CSV格式的檔案的亂碼問題分析


大家都知道ajax是不能直接下載檔案的,所以一般都是通過一個超連結的形式去下載一個檔案

但是當牽扯到需要傳送很多資料到伺服器上再下載的時候超連結的形式就有些太過勉強了

如下是一個工具方法(依賴jquery) 可以通過傳送多資料的情況下下載檔案,程式碼如下:

/*===================下載檔案
 * options:{
 * url:'',  //下載地址
 * data:{name:value}, //要傳送的資料
 * method:'post'
 * }
 */
var DownLoadFile = function (options) {
    var config = $.extend(true, { method: 'post' }, options);
    var $iframe = $('<iframe id="down-file-iframe" />');
    var $form = $('<form target="down-file-iframe" method="' + config.method + '" />');
    $form.attr('action', config.url);
    for (var key in config.data) {
        $form.append('<input type="hidden" name="' + key + '" value="' + config.data[key] + '" />');
    }
    $iframe.append($form);
    $(document.body).append($iframe);
    $form[0].submit();
    $iframe.remove();
}

很簡單的,傳如url和資料就可以啦

demo: DownLoad({

url:'http://www.baidu.com.....', //請求的url

data:{sc:'xxx'}//要傳送的資料

});

根據博主的文章,我自己測試了下,確實可行。

本質上這個已經不是$Ajax的post請求了。而是form表單的post請求,請求同步的,而不是非同步的。

針對ie8下不相容的問題。解決方案:

最後的解決方案是直接用一個form,沒有巢狀iframe。(時間問題,沒有親試,但是這種form表單的post請求方案,理論上是絕對可行的。

下面是我自己做js匯出CVS文件的例子:

jsp頁面,就一個按鈕

<body>
 <button id="getcsv">匯出CVS</button> 
</body>


js:

<script type="text/javascript" src="http://cdn.hcharts.cn/jquery/jquery-1.8.3.min.js"></script>
<script type="text/javascript">
/*===================下載檔案
 * options:{
 * url:'',  //下載地址
 * data:{name:value}, //要傳送的資料
 * method:'post'
 * }
 * 過了有一段時間了,忘記當時IE8具體是哪裡的問題。
 最後的解決方案是直接用一個form,沒有巢狀iframe。
 */
var DownLoadFile = function (options) {
    var config = $.extend(true, { method: 'post' }, options);
    var $iframe = $('<iframe id="down-file-iframe" />');
    var $form = $('<form target="down-file-iframe" method="' + config.method + '" />');
    $form.attr('action', config.url);
    for (var key in config.data) {
        $form.append('<input type="hidden" name="' + key + '" value="' + config.data[key] + '" />');
    }
    $iframe.append($form);
    $(document.body).append($iframe);
    $form[0].submit();
    $iframe.remove();
}
 
 
 
  $('#getcsv').click(function () {
		var  csv_data ="姓名,年齡";
		for (var i = 0; i < 100; i++) {
			csv_data+="\n長征,123";
		}
		DownLoadFile({ 
			url:'export.do', //請求的url
			data:{csv:csv_data,flag:'exportExcel'}//要傳送的資料
			});
  });
</script>

servlet程式碼:
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
	      /**
	       * 注意,Request格式的設定只有在doPost方法中才會有效,如果是在doPost的方法內部的方法中呼叫,
	       * 如exportExcel(req,resp)方法內部呼叫req.setCharacterEncoding("UTF-8"),引數仍然是亂碼。
	       * 
	       * get請求的引數,是web伺服器決定編碼,預設是URIEncoding=iso8859-1。所以可以在servlet中使用
	       * String param = new String(param.getBytes("iso8859-1"),"UTF-8");
	       * 當然,更直接的方法是修改tomcat中的URIEncoding,如下
	       * 修改tomcat的配置檔案server.xml:
             <Connector URIEncoding="UTF-8" 
                 port="8080"   maxHttpHeaderSize="8192"
               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
               connectionTimeout="20000" disableUploadTimeout="true" />
                                             只需增加 URIEncoding="UTF-8"  這一句,然後重啟tomcat即可。
	       * 
	       */
		   req.setCharacterEncoding("UTF-8");//只對post請求的引數有效
		  String flag=req.getParameter("flag");
		  //根據flag分發請求
	     if(flag.equals("login")){
		  doLogin(req,resp);
           }else if(flag.equals("out")){
           	doOut(req,resp);
         }else if(flag.equals("exportExcel")){
        	 exportExcel(req,resp);
         }   
	}

具體匯出CSV的方法:
/**
	 * js匯出Excel
	 * @param req
	 * @param resp
	 */
	private void exportExcel(HttpServletRequest req, HttpServletResponse resp){
	/**
	 * response.setContentType("application/csv;charset=gbk"); 
	 * response.setHeader("Content-Disposition","attachment; filename=x.csv"); 
	 * PrintWriter out = response.getWriter(); 
	 * 因為excel是用ansi編碼開啟,不是你匯出檔案亂碼,而是它渲染亂碼了. 所以如果你的使用者是win,應該設定為gbk編碼.
	 * 當然這樣在linux下應該就是亂碼了.. 另外匯出excel可以參考我寫的 jfinal-ext中 excelRender
	 * 
	 * 如果您的CSV是由Windows Live Mail匯出,那麼,這是由於您所用的CSV檔案編碼不同有關的。
	 * 在Windows Live Mail中所到處的CSV檔案編碼為“UTF-8”,而Outlook 2007所支援的格式為“ANSI”。
	 * 您需要將匯出的CSV檔案另存一份,儲存時在“編碼”下選擇“ANSI”,然後再嘗試在Outlook 2007下匯入另存後的CSV檔案。
	 */
			try {
				String 	csv = req.getParameter("csv");
				String filename  = "中國你好.csv";
				//方式一:ie,迅雷下亂碼,谷歌,火狐下正常,360急速模式正常,相容模式亂碼
				//filename = new String(filename.getBytes(), "ISO8859_1"); 
				//方式二:360下2種模式都正常,ie,谷歌和迅雷下檔案都沒有亂碼,但是火狐下出現亂碼
				//filename = URLEncoder.encode(filename, "UTF-8");
				//方式三:全部正常
				filename = processFileName(req,filename);
						
				resp.setContentType("application/csv;charset=GBK");// resp.setCharacterEncoding("GBK");這裡注意,csv預設使用的是GBK的編碼格式
				resp.setHeader("Content-Disposition","attachment; filename=" + filename);
				// 
				
				if(csv!=null && !"".equals(csv)) {
				    	resp.getWriter().print(csv);
				    }
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	}

處理匯出檔名亂碼的方法:
/** 
     *  處理匯出生成的Excel檔名在火狐或ie下出現亂碼的問題
     * @Title: processFileName 
     *  
     * @Description: ie,chrom,firfox下處理檔名顯示亂碼 
     */  
    public static String processFileName(HttpServletRequest request, String fileNames) {  
        String codedfilename = null;  
        try {  
            String agent = request.getHeader("USER-AGENT");  
            if (null != agent && -1 != agent.indexOf("MSIE") || null != agent  
                    && -1 != agent.indexOf("Trident")) {// ie  
  
                String name = java.net.URLEncoder.encode(fileNames, "UTF8");  
  
                codedfilename = name;  
            } else if (null != agent && -1 != agent.indexOf("Mozilla")) {// 火狐,chrome等  
  
  
                codedfilename = new String(fileNames.getBytes("UTF-8"), "iso-8859-1");  
            }  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return codedfilename;  
    }