JavaWEB之文件的下載

咱們要將Web應用系統中的文件資源提供給用戶進行下載,首先咱們要有一個頁面列出上傳文件目錄下的全部文件,當用戶點擊文件下載超連接時就進行下載操做,編寫一個ListFileServlet,用於列出Web應用系統中全部下載文件
獲取文件列表
package me.gacl.web.controller;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ListFileServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//獲取上傳文件的目錄
String uploadFilePath = this.getServletContext().getRealPath("/WEB-INF/upload");
//存儲要下載的文件名
Map<String,String> fileNameMap = new HashMap<String,String>();
//遞歸遍歷filepath目錄下的全部文件和目錄,將文件的文件名存儲到map集合中
listfile(new File(uploadFilePath),fileNameMap);//File既能夠表明一個文件也能夠表明一個目錄
//將Map集合發送到listfile.jsp頁面進行顯示
request.setAttribute("fileNameMap", fileNameMap);
request.getRequestDispatcher("/listfile.jsp").forward(request, response);
}
public void listfile(File file,Map<String,String> map){
//若是file表明的不是一個文件,而是一個目錄
if(!file.isFile()){
//列出該目錄下的全部文件和目錄
File files[] = file.listFiles();
//遍歷files[]數組
for(File f : files){
//遞歸
listfile(f,map);
}
}else{
/**html

  • 處理文件名,上傳後的文件是以uuid_文件名的形式去從新命名的,去除文件名的uuid部分
    file.getName().indexOf("
    ")檢索字符串中第一次出現"_"字符的位置,若是文件名相似於:9349249849-88343-8344_阿_凡達.avi
    那麼file.getName().substring(file.getName().indexOf("
    ")+1)處理以後就能夠獲得阿_凡達.avi部分
    */
    String realName = file.getName().substring(file.getName().indexOf("
    ")+1);
    //file.getName()獲得的是文件的原始名稱,這個名稱是惟一的,所以能夠做爲key,realName是處理事後的名稱,有可能會重複
    map.put(file.getName(), realName);
    }
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    doGet(request, response);
    }
    }
    ListFileServlet中listfile方法,listfile方法是用來列出目錄下的全部文件的,listfile方法內部用到了遞歸,在實際開發當中,咱們確定會在數據庫建立一張表,裏面會存儲上傳的文件名以及文件的具體存放目錄,咱們經過查詢表就能夠知道文件AxiTrader代理申請www.fx61.com/brokerlist/axitrader.html的具體存放目錄,是不須要用到遞歸操做的,這個例子是由於沒有使用數據庫存儲上傳的文件名和文件的具體存放位置,而上傳文件的存放位置又使用了散列算法打散存放,因此須要用到遞歸,在遞歸時,將獲取到的文件名存放到從外面傳遞到listfile方法裏面的Map集合當中,這樣就能夠保證全部的文件都存放在同一個Map集合當中。
    配置
    在Web.xml文件中配置ListFileServlet
    <servlet>
    <servlet-name>ListFileServlet</servlet-name>
    <servlet-class>me.gacl.web.controller.ListFileServlet</servlet-class>
    </servlet>
    <servlet-mapping>
    <servlet-name>ListFileServlet</servlet-name>
    <url-pattern>/servlet/ListFileServlet</url-pattern>
    </servlet-mapping>
    下載頁面
    展現下載文件的listfile.jsp頁面以下:
    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <!DOCTYPE HTML>
    <html>
    <head>
    <title>下載文件顯示頁面</title>
    </head>
    <body>
    <!-- 遍歷Map集合 -->
    <c:forEach var="me" items="${fileNameMap}">
    <c:url value="/servlet/DownLoadServlet" var="downurl">
    <c:param name="filename" value="${me.key}"></c:param>
    </c:url>
    ${me.value}<a href="${downurl}">下載</a>
    <br/>
    </c:forEach>
    </body>
    </html>
    實現文件下載
    編寫一個用於處理文件下載的Servlet,DownLoadServlet的代碼以下:
    public class DownLoadServlet extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    //獲得要下載的文件名
    String fileName = request.getParameter("filename"); //23239283-92489-阿凡達.avi
    //上傳的文件都是保存在/WEB-INF/upload目錄下的子目錄當中
    String fileSaveRootPath=this.getServletContext().getRealPath("/WEB-INF/upload");
    //經過文件名找出文件的所在目錄
    String path = findFileSavePathByFileName(fileName,fileSaveRootPath);
    //獲得要下載的文件
    File file = new File(path + "\" + fileName);
    //若是文件不存在
    if(!file.exists()){
    request.setAttribute("message", "您要下載的資源已被刪除!!");
    request.getRequestDispatcher("/message.jsp").forward(request, response);
    return;
    }
    //處理文件名
    String realname = fileName.substring(fileName.indexOf("_")+1);
    //設置響應頭,控制瀏覽器下載該文件
    response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(realname, "UTF-8"));
    //讀取要下載的文件,保存到文件輸入流
    FileInputStream in = new FileInputStream(path + "\" + fileName);
    //建立輸出流
    OutputStream out = response.getOutputStream();
    //建立緩衝區
    byte buffer[] = new byte[1024];
    int len = 0;
    //循環將輸入流中的內容讀取到緩衝區當中
    while((len=in.read(buffer))>0){
    //輸出緩衝區的內容到瀏覽器,實現文件下載
    out.write(buffer, 0, len);
    }
    //關閉文件輸入流
    in.close();
    //關閉輸出流
    out.close();
    }
    public String findFileSavePathByFileName(String filename,String saveRootPath){
    int hashcode = filename.hashCode();
    int dir1 = hashcode&0xf; //0--15
    int dir2 = (hashcode&0xf0)>>4; //0-15
    String dir = saveRootPath + "\" + dir1 + "\" + dir2; //upload\2\3 upload\3\5
    File file = new File(dir);
    if(!file.exists()){
    //建立目錄
    file.mkdirs();
    }
    return dir;
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    doGet(request, response);
    }
    }
    配置
    <servlet>
    <servlet-name>DownLoadServlet</servlet-name>
    <servlet-class>me.gacl.web.controller.DownLoadServlet</servlet-class>
    </servlet>
    <servlet-mapping>
    <servlet-name>DownLoadServlet</servlet-name>
    <url-pattern>/servlet/DownLoadServlet</url-pattern>
    </servlet-mapping>
    1.html5支持的文件下載
    很是簡單代碼以下:
    <a download="下載文件.txt">下載文件</a>
    這種方式不支持ie瀏覽器
    2.須要後臺支持的文件下載:
    前端代碼以下:
    function getRootPath() {
    //獲取當前網址,如: http://localhost:8083/uimcardprj/share/meun.jsp
    var curWwwPath = window.document.location.href;
    //獲取主機地址以後的目錄,如: uimcardprj/share/meun.jsp
    var pathName = window.document.location.pathname;
    var pos = curWwwPath.indexOf(pathName);
    //獲取主機地址,如: http://localhost:8083
    var localhostPaht = curWwwPath.substring(0, pos);
    //獲取帶"/"的項目名,如:/uimcardprj
    var projectName = pathName.substring(0, pathName.substr(1).indexOf('/') + 1);
    return (localhostPaht + projectName);
    }
    function downloadExcel(fileName) {
    fileName = encodeURI(fileName);
    var url = getRootPath() + "/static/excel/" + fileName;
    window.location.href = "data/downloadexcel?fileName=" + fileName + "&url=" + url;
    }
    此處須要傳遞下載文件的文件名稱與文件的地址(爲了不服務器路徑問題,此處直接使用前端傳遞的url路徑地址,這種方式也能夠用來下載第三方網站上的文件資源),注意對於文件名稱須要處理文件名稱中的中文字符與特殊字符須要使用js方法encodeURI對文件名稱編碼
    後臺代碼:
    /**前端

    • 下載文件
    • @param fileName
    • @param url
    • @return
      */
      @RequestMapping(value = "/index/download", method = RequestMethod.GET)br/>@ResponseBody
      public void download(String fileName, String url) {
      logger.info("下載文件:" + url);
      // 須要對url進行編碼,默認狀況下,只編碼最後一個 / 以後的內容
      int index = url.lastIndexOf("/") + 1;
      this.response.reset();
      this.response.setContentType("multipart/form-data");
      HttpURLConnection conn = null;
      InputStream inputStream = null;
      try {
      url = url.substring(0, index) + URLEncoder.encode(url.substring(index), "utf-8");
      //注意URLEncoder.encode會將空格轉換爲+,須要作特殊處理
      url = url.trim().replaceAll("\+", "%20");
      this.response.setHeader("Content-Disposition",
      "attachment;fileName=" + processFileName(this.request, fileName));
      URL url1 = new URL(url);
      conn = (HttpURLConnection) url1.openConnection();
      inputStream = conn.getInputStream();
      ServletOutputStream out = this.response.getOutputStream();
      IOUtils.copy(inputStream, out);
      out.flush();
      } catch (IOException e) {
      logger.error("下載模板文件出錯", e);
      } finally {
      if (null != inputStream) {
      try {
      inputStream.close();
      } catch (IOException e) {
      logger.error("下載模板文件出錯", e);
      }
      }
      if (null != conn) {
      try {
      conn.disconnect();
      } catch (Exception e) {
      logger.error("下載模板文件出錯", e);
      }
      }
      }
      }

    /**html5

    • @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 && agent.indexOf("MSIE") > -1 || null != agent
      && agent.indexOf("Trident") > -1) {// ie
      String name = java.net.URLEncoder.encode(fileNames, "UTF8").replaceAll("\+","%20");
      codedfilename = name;
      } else {// 火狐,chrome等java

      codedfilename = new String(fileNames.getBytes("UTF-8"),
                  "iso-8859-1");
      }

      } catch (Exception e) {
      logger.error("文件名稱編碼出錯", e);
      }
      return codedfilename;
      }
      下載文件代碼須要注意的地方就只有文件名稱的編碼問題,其餘代碼很簡單,須要特別注意URLEncoder.encode將空格轉換爲+,須要特殊處理轉換爲%20
      3.下載後臺實時生成的文件
      簡單的後臺實時生成文件基本代碼和步驟二一致,只是將從網絡獲取的文件改成從本機獲取就好了
      4.使用post方法下載文件
      post方法下載文件主要能夠經過兩種方式解決
      第一種將post提交到當前頁面的隱藏iframe便可,但這種方式在ie和chmore中會有兩種表現形式(一種直接在當前頁面下載,一種會打開一個空白頁下載)
      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) {
      var input = $("<input hidden>");
      input.attr("name", key);
      input.val(config.data[key]);
      $form.append(input);
      }
      $iframe.append($form);
      $(document.body).append($iframe);
      $form[0].submit();
      $iframe.remove();
      }
      //調用方法
      downLoadFile({
      url: '...', //請求的url
      data: {
      name:"",
      size:"",
      ......
      }//要發送的數據
      });
      使用以上方式便可使用post的方法下載文件
      第二種方法很簡單,能夠先用post方式上傳參數,將參數以緩存的形式存儲在服務端並返回key給前端,再在post的回調方法中使用get方式傳遞key給後臺下載文件
      樣例代碼很簡單,以下:
      $.post("download",params, function (data) {
      if (data.success) {
      window.location.href = "download?generatorId=" + data.data;
      } else {
      alert(data.msg);
      }
      })web

相關文章
相關標籤/搜索