在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(); } }