在web項目中需要下載文件,由於傳遞的參數比較多(通過參數在服務器端動態下載指定文件),所以希望使用post方式傳遞參數。
通常,在web前端需要下載文件,都是通過指定<a>標簽的href屬性,訪問服務器端url即可下載並保存文件到本地。
但是這種方式使用的是HTTP GET方法,參數只能通過URL參數方式傳遞,無法使用POST方式傳遞參數。
於是,想到使用ajax方式下載文件。
實驗:ajax方式下載文件時無法觸發瀏覽器打開保存文件對話框,也就無法將下載的文件保存到硬盤上!
原因:ajax方式請求的數據只能存放在javascipt內存空間,可以通過javascript訪問,但是無法保存到硬盤,因為javascript不能直接和硬盤交互,否則將是一個安全問題。
那么,如果想實現post方式提交參數下載文件,應該怎么實現呢?
可以通過模擬表單提交的方式實現post傳遞數據。
<div> <a href="<%=request.getContextPath()%>/ajaxDownloadServlet.do?fileName=testAjaxDownload.txt">同步下載文件</a><br /> <a href="#" onclick="downloadFilebyAjax()">ajax下載文件</a> <br /> <a href="#" onclick="downloadFileByForm()">模擬表單提交下載文件</a> </div>
<script type="text/javascript">
// 直接通過ajax請求文件數據
// jquery下載文件時不能觸發瀏覽器彈出保存文件對話框!
// 可以在javascript中訪問下載的文件數據
function downloadFilebyAjax() {
console.log("ajaxDownloadDirectly");
var url = "http://localhost:8080/ajaxDownloadServlet.do";
$.ajax({
url: url,
type: 'post',
data: {'fileName': "testAjaxDownload.txt"},
success: function (data, status, xhr) {
console.log("Download file DONE!");
console.log(data); // ajax方式請求的數據只能存放在javascipt內存空間,可以通過javascript訪問,但是無法保存到硬盤
console.log(status);
console.log(xhr);
console.log("=====================");
}
});
}
// 模擬表單提交同步方式下載文件
// 能夠彈出保存文件對話框
function downloadFileByForm() {
console.log("ajaxDownloadSynchronized");
var url = "http://localhost:8080/ajaxDownloadServlet.do";
var fileName = "testAjaxDownload.txt";
var form = $("<form></form>").attr("action", url).attr("method", "post");
form.append($("<input></input>").attr("type", "hidden").attr("name", "fileName").attr("value", fileName));
form.appendTo('body').submit().remove();
}
</script>
servlet實現:
@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { logger.info("ajax download file"); String fileName = req.getParameter("fileName"); File file = new File(System.getProperty("user.home"), fileName); resp.setContentType("application/octet-stream"); resp.setHeader("Content-Disposition","attachment;filename=" + fileName); resp.setContentLength((int) file.length()); FileInputStream fis = null; try { fis = new FileInputStream(file); byte[] buffer = new byte[128]; int count = 0; while ((count = fis.read(buffer)) > 0) { resp.getOutputStream().write(buffer, 0, count); } } catch (Exception e) { e.printStackTrace(); } finally { resp.getOutputStream().flush(); resp.getOutputStream().close(); fis.close(); } }
【參考】
https://gist.github.com/DavidMah/3533415
http://marcanguera.net/blog/2013/07/01/download-file-via-ajax/
