day20JavaWeb(檔案上傳)
阿新 • • 發佈:2018-11-19
上傳不能使用BaseServlet 因為無法獲取引數了getParameter 方法不能用 檔案上傳概述 1、檔案上傳的作用 例如網路硬碟,就是用來上傳下載檔案的 2、檔案上傳也對面的要求 1、必須使用表單,而不能是超連結 2、表單的method必須是POST,而不能是GET 3、表單的enctype必須是multipart/form-data; 處理編碼 4、在表單中新增file表單欄位,即<input type="file"name="xxx"/> <form action="xxx" method ="post" enctype="multipart/form-data"> <input type="text" name="username"/> <input type="text" name="username"/> 3、上次對Servlet限制 request.getParameter("xxx");這個方法在表單為enctype="multipart/form-data"時,作廢了,永遠返回null ServletInputStream request.getInputStream ();包含整個請求的體 多部件表單的體 1、每隔出多個部件,即一個表單項一個部件 2、一個部件中自己包含請求頭和空行,以及請求體 3、普通表單項 1個頭:Content-Disposition 包含name="xx",即表單項名稱 體就是表單項的值 4、檔案表單項 2個頭 Content-Disposition:包含name="xxx"即表單項名稱:還有一個filename="xxx",表示上次檔案的名稱 Content-Type:是上傳檔案的MIME型別 例如:image/pjpeg,表示上傳的是圖片,圖上中jpg副檔名的圖片 體就是上傳檔案的內容 commons-fileupload commons-fileupload.jar 上傳依賴io commons-io.jar 可以獨立存 可以幫我們解析request中的上傳資料,解析後的結果是一個表單項封裝到一個FileItem物件中,只需要呼叫FileItem的方法即可 1、上傳3步 相關類: 工廠:DiskFileItemFactory 解析器:ServletFileUpload 表單項:FileItem 1、建立工廠:DiskFileItemFactory factory = new 工廠:DiskFileItemFactory(); 2、建立解析器:ServletFileUpload sfu = new 解析器:ServletFileUpload(factory); 3、使用解析器來解析request:得到FileItem集合:List<FileItem> fileItemList = sfu.paraseRequest(request); 2、FileItem boolean isFormField():是否為普通表單項。返回true為普通表單項,如果為false即檔案表單項 String getFieldName():返回當前表單項的名稱 String getString(String charset):返回表單項的值 String getName():返回上傳的檔名稱 Long getSize():返回上傳檔案的位元組數 InputStream getInputStream():返回上傳檔案對應的輸入流 void write(File destFile):把上傳的檔案內容儲存到指定的檔案中 String getContentType():獲取檔案型別 上傳的細節 1、檔案必須儲存到WEB-INF下 不讓瀏覽器直接訪問到 假如說使用者上傳了一個a.jsp檔案,然後使用者在通過瀏覽器去房屋呢這個a.jsp檔案,那麼就會執行a.jsp中的內容。 如果在a.jsp中有Runtime.getRuntime().exec("shutdown -s -t 1"); shutdown -a 取消 通常會在WEB-INF目錄下建立一個uploads目錄來存放上傳的檔案,而在servlet中找到這個目錄需要使用ServletContext的getRealPath(Sting)方法, ServletContext servletContext = this.getServletContext(); String savapath = servletContext.getRealPath("WEB-INF/uploads"); 其中savapath為:F:\tomcat8_5\webapps\uploads\WEB-INF\uploads 2、檔名稱相關問題 有的瀏覽器(IE6)上傳的檔名是絕對路徑,需要切割 c:\files\aa.jpg 無論是否為完整路徑,都去擷取最後一個"\\"後面的內容即可 String filename = fi2.getName(); int index = filename.lastIndexOf("\\"); if(index!=-1){ filename = filename.subString(index+1); } 檔名亂碼或者普通表單項亂碼。request.setCharacterEncoding("utf-8");因為fileUpload內部會呼叫request.getCharacterEncoding("utf-8") ServletFileUpload.setHeaderEncoding("utf-8");//優先順序高 檔案同名問題:需要為每個檔案新增名稱字首:這個字首要保證不能重複。uuid filename = CommonUtils.uuid() + "_" + filename; 3、目錄打散 不能在一個目錄下存放過多檔案 過萬檔案在一個資料夾會很卡 首字元打散:使用檔案的首字母作為目錄名稱,例如abc.txt.那麼我們把檔案儲存到a目錄下,如果a目錄此時不存在,那麼建立 時間打散:使用當前日期作為目錄 雜湊打散: 通過檔名稱得到int值,即呼叫hashCode() 它int值轉換成16進位制0~9,A~F 獲取16進位制的前兩位來生成目錄,目錄為二層。例如1B2C3D4E5F /1/B儲存檔案 4、上傳檔案的大小限制 單個檔案大小限制 ServletFileUpload類的setFileSizeMax(long)即可,引數就是上傳檔案的上限位元組數, 例如servletFileUpload.setFileSizeMax(1024*10)表示上限為10kb 一旦超出會丟擲FileUploadBase.FileSizeLimitExceededException 可以在sevlet獲取這個異常然後向頁面輸出 必須在解析開始之前 parseRequest之前 如果上傳的檔案超出限制,在parseRequest()方法執行時,會丟擲異常FileUploadBase.FileSizeLimitExceededException 整個請求所有資料大小限制 sfu.setSizeMax(1024*1024);//限制整個表單大小為1M 這個方法也是必須在parseRequest()之前呼叫 如果上傳的檔案超出限制,在parseRequest()方法執行時,會丟擲異常FileUploadBase.SizeLimitExceededException 5、快取大小與臨時目錄 快取大小:超出多大,才向硬碟儲存。預設10KB 臨時目錄:向硬碟的什麼位置儲存 設定快取大小與臨時目錄:new DiskFileItemFactory(20*1024,new Fil("F:/temp")) 用到的jar包: commons-io-2.6.jar commons-fileupload-1.2.1.jar itcast-tools-1.4.jar commons-beanutils-1.8.3.jar commons-logging-1.1.1.jar
public class UploadServlet extends HttpServlet { public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); /* * 上傳 1.得到工廠 2.通過工廠得到解析器 3.解析request得到fileTtem集合 * 4.遍歷fileItem集合,呼叫其API儲存檔案 * * // 建立工廠 DiskFileItemFactory factory = new DiskFileItemFactory(); // * 建立解析器 ServletFileUpload fileUpload = new ServletFileUpload(factory); * // 使用解析器解析request try { List<FileItem> fileItems = * fileUpload.parseRequest(request); FileItem f1 = fileItems.get(0); * FileItem f2 = fileItems.get(1); System.out.println("普通表單項:" + * f1.getFieldName() + f1.getString("UTF-8")); * System.out.println("檔案表單項:"); System.out.println("FileNAme:" + * f2.getName()); System.out.println("ContetType:" + * f2.getContentType()); System.out.println("FileSize:" + f2.getSize()); * // 儲存檔案 File destFile = new File("D:/圖片.jsp"); f2.write(destFile); * * } catch (FileUploadException e) { throw new RuntimeException(e); } * catch (Exception e) { throw new RuntimeException(e); } */ // 建立工廠 DiskFileItemFactory factory = new DiskFileItemFactory(1 * 1024, new File("D:/資料")); // 建立解析器 ServletFileUpload fileUpload = new ServletFileUpload(factory); /* * fileUpload.setFileSizeMax(5*1024); fileUpload.setSizeMax(1024*1024); */ // 使用解析器解析request try { List<FileItem> fileItems = fileUpload.parseRequest(request); FileItem fi = fileItems.get(1); // /////////////////////////////////////////////// /* * 1.得到檔案儲存路徑 */ String root = this.getServletContext() .getRealPath("/WEB-INF/files"); /* * 2.生成二層目錄 1).得到檔名稱 2).得到hashcode 3).轉發成十六進位制 4).得到前兩個字元用來生成目錄 */ String fileName = fi.getName(); // 處理檔名絕對路徑的問題 int index = fileName.lastIndexOf("\\"); if (index != -1) { // 擷取//後的檔名 fileName = fileName.substring(index + 1); } /* * 給檔名稱新增UUID,解決檔案同名問題 */ String savename = CommonUtils.uuid() + "_" + fileName; /* * 1.得到hashcode */ int hashcode = fileName.hashCode(); // 轉換成十六進位制 String hex = Integer.toHexString(hashcode); /* * 2.得到前兩位字母,與root一起連線成完整的路徑 */ File dirFile = new File(root, hex.charAt(0) + "/" + hex.charAt(1)); /* * 3.建立目錄鏈 */ dirFile.mkdirs(); /* * 4.建立目錄檔案 */ File destFile = new File(dirFile, savename); /* * 5.儲存 */ fi.write(destFile); // /////////////////////////////////////////////// } catch (FileUploadException e) { if (e instanceof FileSizeLimitExceededException) { request.setAttribute("msg", "上傳圖片過大,不能超過5kb"); request.getRequestDispatcher("/index.jsp").forward(request, response); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
<h3>${msg }</h3> <body> <form action="<c:url value='/UploadServlet'/>" method="post" enctype="multipart/form-data"> 使用者名稱<input type="text" name="username"><br> 照 片<input type="file" name="zhaopian"><br> <input type="submit" value="提交"> </form> </body>