前台 VUE 界面:
<el-table-column prop="attachment" align="center" label="附件詳情"> <template slot-scope="scope"> <!--<el-button @click="downloadFile(scope.row.fileName,scope.row.fileUrl)">{{scope.row.fileName}}</el-button>--> <a @click="downloadFile(scope.row.fileName,scope.row.fileUrl)">{{scope.row.fileName}}</a> </template> </el-table-column>
//window.open打開一個新的瀏覽器窗口,通過 url 對后台的 rest 接口進行調用
downloadFile(fileName,fileUrl){ let param = {"fileUrl": fileUrl, "fileName": fileName}; window.open( downloadManage.downloadFile(param), this.openType ); },
/* 下載文件,對參數 url 和 fileName 進行拼接處理,然后通過 window.open 對后台的 rest 接口進行調用 */ export const downloadManage = { downloadFile: (query) => requestGetUrl('/process/downloadFile.do_', query, 'post'), };
后台java代碼:(rest接口,供前台進行調用)
/** * 下載文件 * * @return */ @RequestMapping("/downloadFile.do_") @ResponseBody public void downloadFile( HttpServletResponse response, @RequestParam String fileUrl, @RequestParam String fileName ) { downLoadFromUrl(fileUrl,fileName,response); } /** * 從網絡Url中下載文件 * @param urlStr 指定的url * @param fileName 下載文件完成要叫的名字 * @param response */ public static void downLoadFromUrl(String urlStr,String fileName,HttpServletResponse response){ try { URL url = new URL(urlStr); HttpURLConnection conn = (HttpURLConnection)url.openConnection(); //增加頭部,說明該文件為附件,只能進行下載,不直接讀 response.setContentType("application/x-msdownload; charset=UTF-8"); response.setHeader("Content-Disposition", "attachment; filename=" + fileName); //得到輸入流 InputStream inputStream = conn.getInputStream(); BufferedInputStream bis = new BufferedInputStream(inputStream); OutputStream os = response.getOutputStream(); BufferedOutputStream bos = new BufferedOutputStream(os); /* ContentLength必須設置,否則文件下載不全 * 或者調用 BufferedOutputStream#write(byte[] b, int off, int len) 方法輸出 */ response.setContentLength(bis.available()); byte[] b = new byte[1024]; while(bis.read(b) != -1) { bos.write(b); } bos.flush(); LOGGER.info("info:"+fileName+" download success"); } catch (IOException e) { LOGGER.error("uploadFile failed", e); } }
注意:上面的方法有一個小問題:用過url去網絡獲取 inputStream 是一點一點不斷獲取,獲取的過程中就去寫這個 inputStream ,則 inputStream 還沒有獲取完就寫了,導致文件最后有缺失,所以可以給 inputStream 加一個同步鎖synchronized,就能使 inputStream 全部獲取完並寫,這樣就能獲取完整的 inputStream 並寫下來,就能下載一個完整的文件
public static void downLoadFromUrl(String urlStr,String fileName,HttpServletResponse response){ URL url = null; HttpURLConnection conn = null; try { url = new URL(urlStr); conn = (HttpURLConnection)url.openConnection(); }catch (Exception e) { LOGGER.error("HttpURLConnection failed", e); } try ( InputStream inputStream = conn.getInputStream(); BufferedInputStream bis = new BufferedInputStream(inputStream); OutputStream os = response.getOutputStream(); BufferedOutputStream bos = new BufferedOutputStream(os); ) { //未知上傳的文件類型設置ContentType 和 Header response.setContentType("application/octet-stream; charset=UTF-8"); response.setHeader("Content-Disposition", "attachment; filename=" + new String(fileName.getBytes(),"ISO8859-1")); //同步塊,同步 inputStream ,邊獲取 inputStream 邊寫,一直到全部獲取完 inputStream synchronized (inputStream) { byte[] b = new byte[1024]; int count = 0; int len; while((len = bis.read(b)) != -1) { bos.write(b, 0, len); count++; } bos.flush(); //多少 Kb 大小的文件,則循環多少次,為count值 LOGGER.info("write BufferedOutputStream:" + count); LOGGER.info("info:" + fileName + " download success"); } } catch (Exception e) { LOGGER.error("uploadFile failed", e); } }
會出現如下通常我們網上點擊某超鏈接下載文件的效果:(下載完成出現在瀏覽器頁面左下角)