<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    聶永的博客

    記錄工作/學習的點點滴滴。

    Servlet 3.0筆記之超方便的文件上傳支持

    在以前,處理文件上傳是一個很痛苦的事情,大都借助于開源的上傳組件,諸如commons fileupload等。現在好了,很方便,便捷到比那些組件都方便至極。以前的HTML端上傳表單不用改變什么,還是一樣的multipart/form-data MIME類型。
    讓Servlet支持上傳,需要做兩件事情
    1. 需要添加MultipartConfig注解
    2. 從request對象中獲取Part文件對象
    但在具體實踐中,還是有一些細節處理,諸如設置上傳文件的最大值,上傳文件的保存路徑。
    需要熟悉MultipartConfig注解,標注在@WebServlet之上,具有以下屬性:
    屬性名類型是否可選描述
    fileSizeThresholdint當數據量大于該值時,內容將被寫入文件。
    locationString存放生成的文件地址。
    maxFileSizelong允許上傳的文件最大值。默認值為 -1,表示沒有限制。
    maxRequestSizelong針對該 multipart/form-data 請求的最大數量,默認值為 -1,表示沒有限制。

    一些實踐建議:
    1. 若是上傳一個文件,僅僅需要設置maxFileSize熟悉即可。
    2. 上傳多個文件,可能需要設置maxRequestSize屬性,設定一次上傳數據的最大量。
    3. 上傳過程中無論是單個文件超過maxFileSize值,或者上傳總的數據量大于maxRequestSize值都會拋出IllegalStateException異常;
    4. location屬性,既是保存路徑(在寫入的時候,可以忽略路徑設定),又是上傳過程中臨時文件的保存路徑,一旦執行Part.write方法之后,臨時文件將被自動清除。
    5. 但Servlet 3.0規范同時也說明,不提供獲取上傳文件名的方法,盡管我們可以通過part.getHeader("content-disposition")方法間接獲取得到。
    6. 如何讀取MultipartConfig注解屬性值,API沒有提供直接讀取的方法,只能手動獲取。
      來一個示例吧,上傳前臺頁面:
      后臺處理Servlet:
      /**
      * 上傳文件測試 location為臨時文件保存路徑
      *
      * @author yongboy
      * @date 2011-1-13
      * @version 1.0
      */
      @MultipartConfig(location = "/home/yongboy/tmp/", maxFileSize = 1024 * 1024 * 10)
      @WebServlet("/upload")
      public class UploadFileAction extends HttpServlet {
      private static final long serialVersionUID = 92166165626L;
      private static final Log log = LogFactory.getLog(UploadFileAction.class);
      // 得到注解信息
      private static final MultipartConfig config;

      static {
      config = UploadFileAction.class.getAnnotation(MultipartConfig.class);
      }

      protected void doGet(HttpServletRequest request,
      HttpServletResponse response) throws ServletException, IOException {
      request.getRequestDispatcher("/upload.jsp").forward(request, response);
      }

      protected void doPost(HttpServletRequest request,
      HttpServletResponse response) throws ServletException, IOException {
      // 為避免獲取文件名稱時出現亂碼
      request.setCharacterEncoding("UTF-8");

      Part part = null;
      try {
      // <input name="file" size="50" type="file" />
      part = request.getPart("file");
      } catch (IllegalStateException ise) {
      // 上傳文件超過注解所標注的maxRequestSize或maxFileSize值
      if (config.maxRequestSize() == -1L) {
      log.info("the Part in the request is larger than maxFileSize");
      } else if (config.maxFileSize() == -1L) {
      log.info("the request body is larger than maxRequestSize");
      } else {
      log.info("the request body is larger than maxRequestSize, or any Part in the request is larger than maxFileSize");
      }

      forwardErrorPage(request, response, "上傳文件過大,請檢查輸入是否有誤!");
      return;
      } catch (IOException ieo) {
      // 在接收數據時出現問題
      log.error("I/O error occurred during the retrieval of the requested Part");
      } catch (Exception e) {
      log.error(e.toString());
      e.printStackTrace();
      }

      if (part == null) {
      forwardErrorPage(request, response, "上傳文件出現異常,請檢查輸入是否有誤!");
      return;
      }

      // 得到文件的原始名稱,eg :測試文檔.pdf
      String fileName = UploadUtils.getFileName(part);

      log.info("contentType : " + part.getContentType());
      log.info("fileName : " + fileName);
      log.info("fileSize : " + part.getSize());
      log.info("header names : ");
      for (String headerName : part.getHeaderNames()) {
      log.info(headerName + " : " + part.getHeader(headerName));
      }

      String saveName = System.currentTimeMillis() + "."
      + FilenameUtils.getExtension(fileName);

      log.info("save the file with new name : " + saveName);

      // 因在注解中指定了路徑,這里可以指定要寫入的文件名
      // 在未執行write方法之前,將會在注解指定location路徑下生成一臨時文件
      part.write(saveName);

      request.setAttribute("fileName", fileName);
      request.getRequestDispatcher("/uploadResult.jsp").forward(request,
      response);
      }

      private void forwardErrorPage(HttpServletRequest request,
      HttpServletResponse response, String errMsg)
      throws ServletException, IOException {
      request.setAttribute("errMsg", errMsg);

      request.getRequestDispatcher("/upload.jsp").forward(request, response);
      }
      }
      獲取文件名的函數,很簡單:
       /**
      * 如何得到上傳的文件名, API沒有提供直接的方法,只能從content-disposition屬性中獲取
      *
      * @param part
      * @return
      */
      protected static String getFileName(Part part) {
      if (part == null)
      return null;

      String fileName = part.getHeader("content-disposition");
      if (StringUtils.isBlank(fileName)) {
      return null;
      }

      return StringUtils.substringBetween(fileName, "filename=\"", "\"");
      }
      文件上傳成功之后,以及日志輸出的截圖如下:
      截圖中可以看到Part包含content-disposition屬性,可以很容易從值中抽取出文件名。臨時生成的上傳文件大都以 .tmp為后綴,大致如下:
      讓上傳出現錯誤,就可以在保存路徑下看到大致如上的臨時文件。
      一次上傳多個文件的后臺servlet示范:
      /**
      * 多文件上傳支持
      * @author yongboy
      * @date 2011-1-14
      * @version 1.0
      */
      @MultipartConfig(
      location = "/home/yongboy/tmp/",
      maxFileSize = 1024L * 1024L, // 每一個文件的最大值
      maxRequestSize = 1024L * 1024L * 10L // 一次上傳最大值,若每次只能上傳一個文件,則設置maxRequestSize意義不大
      )
      @WebServlet("/uploadFiles")
      public class UploadFilesAction extends HttpServlet {
      private static final long serialVersionUID = 2304820820384L;
      private static final Log log = LogFactory.getLog(UploadFilesAction.class);

      protected void doGet(HttpServletRequest request,
      HttpServletResponse response) throws ServletException, IOException {
      request.getRequestDispatcher("/uploads.jsp").forward(request, response);
      }

      protected void doPost(HttpServletRequest request,
      HttpServletResponse response) throws ServletException, IOException {
      request.setCharacterEncoding("UTF-8");

      Collection parts = null;
      try {
      parts = request.getParts();
      } catch (IllegalStateException ise) {
      // 可能某個文件大于指定文件容量maxFileSize,或者提交數據大于maxRequestSize
      log.info("maybe the request body is larger than maxRequestSize, or any Part in the request is larger than maxFileSize");
      } catch (IOException ioe) {
      // 在獲取某個文件時遇到拉IO異常錯誤
      log.error("an I/O error occurred during the retrieval of the Part components of this request");
      } catch (Exception e) {
      log.error("the request body is larger than maxRequestSize, or any Part in the request is larger than maxFileSize");
      e.printStackTrace();
      }

      if (parts == null || parts.isEmpty()) {
      doError(request, response, "上傳文件為空!");
      return;
      }

      // 前端具有幾個file組件,這里會對應幾個Part對象
      List fileNames = new ArrayList();
      for (Part part : parts) {
      if (part == null) {
      continue;
      }
      // 這里直接以源文件名保存
      String fileName = UploadUtils.getFileName(part);

      if (StringUtils.isBlank(fileName)) {
      continue;
      }

      part.write(fileName);
      fileNames.add(fileName);
      }

      request.setAttribute("fileNames", fileNames);
      request.getRequestDispatcher("/uploadsResult.jsp").forward(request,
      response);
      }

      private void doError(HttpServletRequest request,
      HttpServletResponse response, String errMsg)
      throws ServletException, IOException {
      request.setAttribute("errMsg", errMsg);

      this.doGet(request, response);
      }
      }
      批量上傳很簡單,但也有風險,任一個文件若超過maxFileSize值,意味著整個上傳都會失敗。若不限大小,那就不存在以上憂慮了。
      總之,在Servlet 3.0 中,無論是上傳一個文件,或者多個批量上傳都是非常簡單,但要處理好異常,避免出錯。

      posted on 2011-01-15 20:43 nieyong 閱讀(14722) 評論(2)  編輯  收藏 所屬分類: Servlet3

      評論

      # re: Servlet 3.0筆記之超方便的文件上傳支持 2011-03-18 14:22 - -

      謝謝  回復  更多評論   

      # re: Servlet 3.0筆記之超方便的文件上傳支持 2016-08-16 10:22 yxscomeon

      @- -
      謝謝,解決了我的一個問題!特意注冊過來謝謝的!  回復  更多評論   

      公告

      所有文章皆為原創,若轉載請標明出處,謝謝~

      新浪微博,歡迎關注:

      導航

      <2011年1月>
      2627282930311
      2345678
      9101112131415
      16171819202122
      23242526272829
      303112345

      統計

      常用鏈接

      留言簿(58)

      隨筆分類(130)

      隨筆檔案(151)

      個人收藏

      最新隨筆

      搜索

      最新評論

      閱讀排行榜

      評論排行榜

      主站蜘蛛池模板: 亚洲乱亚洲乱妇无码| 国产免费一区二区三区在线观看| 亚洲精品国产自在久久| a级毛片在线免费观看| 亚洲av无码一区二区三区天堂古代 | 亚欧乱色国产精品免费视频| 亚洲国产天堂久久综合网站| 女人被弄到高潮的免费视频| 国产特黄一级一片免费 | 在线亚洲午夜理论AV大片| 亚洲最大免费视频网| 午夜成人无码福利免费视频| 亚洲综合久久1区2区3区| 国产极品美女高潮抽搐免费网站| 永久免费av无码入口国语片| 亚洲丁香婷婷综合久久| 亚洲高清在线视频| 免费国产一级特黄久久| 亚洲一级免费毛片| 国产成人高清精品免费观看| 亚洲国产成人精品激情| 国产AV无码专区亚洲精品| 国产高清在线免费| 四虎精品视频在线永久免费观看| 国产久爱免费精品视频| 亚洲日韩一区二区一无码| 日韩亚洲Av人人夜夜澡人人爽| 免费a级黄色毛片| 拍拍拍又黄又爽无挡视频免费| 精品成人免费自拍视频| 一级毛片一级毛片免费毛片| 亚洲AV成人影视在线观看| 337p日本欧洲亚洲大胆色噜噜| 亚洲人成人网站色www| 亚洲不卡AV影片在线播放| 99久久免费精品国产72精品九九| 57pao一国产成永久免费 | 免费va在线观看| 四虎成人免费观看在线网址| 亚洲高清视频免费| 精品一区二区三区无码免费视频|