1. 程式人生 > >使用fileupload實現文件上傳(1)

使用fileupload實現文件上傳(1)

所有 class oca col dea nds post 個數 幫助

一. fileupload組件工作原理

先來張圖片, 幫助大家理解

技術分享圖片

fileupload核心API

1. DiskFileItemFactory
構造器
1) DiskFileItemFactory() // 使用默認配置
2) DiskFileItemFactory(int sizeThreshold, File repository)
  sizeThreshold 內存緩沖區, 不能設置太大, 否則會導致JVM崩潰
  repository 臨時文件目錄

2. ServletFileUpload
1) isMutipartContent(request) // 判斷上傳表單是否為multipart/form-data類型 true/false
2) parseRequest(request) // 解析request, 返回值為List<FileItem>類型
3) setFileSizeMax(long) // 上傳文件單個最大值
4) setSizeMax(long) // 上傳文件總量最大值
5) setHeaderEncoding(String) // 設置編碼格式
6) setProgressListener(ProgressListener) // 設置監聽器, 可以用於制作進度條

二. 使用fileupload實現文件上傳

1. 編寫JSP

 1 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
 2 <html>
 3 <head>
 4     <title>演示文件上傳</title>
 5 </head>
 6 <body>
 7     <form action="${pageContext.request.contextPath}/servlet/FileUpload1" method="post"
enctype="multipart/form-data"> 8 用戶名: <input type="text" name="username"/><br/> 9 文件1: <input type="file" name="file1"/><br/> 10 文件2: <input type="file" name="file2"/><br/> 11 <input type="submit"/> 12 </form> 13 </body
> 14 </html>

要點:

1) 表單包含file類型輸入項時, enctype屬性必須設置為multipart/form-data

2) input:file必須指定name屬性

3) 表單提交方式為post, 因為get請求無法攜帶大量數據

4) 若表單的提交方式為multipart/form-data, 那麽在Servlet就無法使用getParameter方法獲取表單數據, 可以通過獲取客戶機提交數據的輸入流來獲取所有上傳數據, 然後進行解析.

1 // 獲取客戶機提交數據的輸入流
2 request.getInputStream();

5) 解析數據難度較大, 一般不自己編寫程序, 可以使用開源項目解析數據

2. 編寫Servlet

 1 public class FileUpload1 extends HttpServlet {
 2     @Override
 3     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 4 
 5         InputStream in = null;
 6         OutputStream out = null;
 7 
 8         try {
 9             // 使用默認配置創建解析器工廠
10             DiskFileItemFactory factory = new DiskFileItemFactory();
11             // 獲取解析器
12             ServletFileUpload upload = new ServletFileUpload(factory);
13             // 上傳表單是否為multipart/form-data類型
14             if (!upload.isMultipartContent(request)) {
15                 return;
16             }
17             // 解析request的輸入流
18             List<FileItem> fileItemList = upload.parseRequest(request);
19             // 叠代list集合
20             for (FileItem fileItem : fileItemList) {
21                 if (fileItem.isFormField()) {
22                     // 普通字段
23                     String name = fileItem.getFieldName();
24                     String value = fileItem.getString();
25                     System.out.println(name + "=" + value);
26                 } else {
27                     // 上傳文件
28                     // 獲取上傳文件名
29                     String fileName = fileItem.getName();
30                     fileName = fileName.substring(fileName.lastIndexOf("\\")+1);
31                     // 獲取輸入流
32                     in = fileItem.getInputStream();
33 
34                     // 獲取上傳文件目錄
35                     String savePath = this.getServletContext().getRealPath("/WEB-INF/upload");
36                     // 上傳文件名若不存在, 則先創建
37                     File savePathDir = new File(savePath);
38                     if (!savePathDir.exists()) {
39                         savePathDir.mkdir();
40                     }
41 
42                     // 獲取輸出流
43                     out = new FileOutputStream(savePath + "\\" + fileName);
44                     int len = 0;
45                     byte[] buffer = new byte[1024];
46                     while((len=in.read(buffer)) > 0) {
47                         out.write(buffer, 0, len);
48                     }
49                 }
50             }
51         } catch (Exception e) {
52             e.printStackTrace();
53         } finally {
54             if (in != null) {
55                 in.close();
56             }
57             if (out != null) {
58                 out.close();
59             }
60         }
61 
62     }
63 
64     @Override
65     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
66         doGet(req, resp);
67     }
68 }

1) 在WEB-INF中創建upload文件夾時. IDEA不會在out目錄的WEB-INF中創建upload文件夾, 需要手動創建, 所以上面先檢查upload文件夾是否存在

2) 在finally中關閉流時, 應該先檢查流是否為null, 否則當上傳表單不為multipart/form-data類型時, 執行return後再執行finally, 程序就會出現NPE

3) 記得在web.xml中配置servlet的映射路徑

3. 測試

技術分享圖片

4. 使用瀏覽器抓包

技術分享圖片

三. 禁止別人訪問上傳文件目錄

上傳文件目錄應該放在WEB-INF目錄下, 禁止別人訪問上傳文件目錄, 否則黑客可能通過上傳腳本, 然後訪問該腳本, 對網站發起攻擊

舉例:

1. 黑客上傳一個JSP文件

test.jsp
1 <%
2     Runtime.getRuntime().exec("shutdown -s -t 200")  // 執行Windows命令
3 %>

2. 通過訪問該文件, 關閉服務器

http://localhost:8080/upload/test.jsp

備註:

1) Runtime類 // 調用Windows程序

2) Window命令:

  shutdown -a
  format c:\

四. 待解決的問題

1. 中文文件名亂碼問題
2. 上傳文件目錄, 文件存儲個數 -> 使用Hash算法打散
3. 文件覆蓋問題 -> 使用UUID作為文件名稱

使用fileupload實現文件上傳(1)