使用commons-fileUpload組件上傳文件


  在近期的一個項目中有用到commons-fileUpload組件進行實現文件上傳的功能(由於沒用到框架),在使用的過程中有遇到一些問題,經過自己的琢磨也算順利地將其解決了,在這里做個記錄。

  一、commons-fileUpload文件上傳組件簡介

    commons-fileUpload上傳組件是Apache的一個開源項目,可以到http://commons.apache.org/proper/commons-fileupload/下載最新版本(該組件需要commons-io包的支持)。該組件使用方便,同樣可以實現一個或多個文件的上傳,也可實現限制上傳文件大小等功能。

    在文件上傳中,文件上傳請求由有序的表單項列表組成,fileUpload能夠解析上傳請求,然后向應用提供一個單獨的文件表單項的列表。每個這樣的表單項都實現了FileItem接口,並包含例如文件名等屬性。

  二、使用要求

    1、使用commons-fileUpload組件上傳文件時,需要將form表單的enctype屬性設置為multipart/form-data;同時還需要設置上傳文件在內存中的大小,多余的部分存儲在磁盤中。

    2、將相應的commons-fileUpload包和commons-io包拷貝放入到你的web工程WEN-INF/lib目錄下並Add to Build Path。

  三、使用步驟

    1、首先,創建磁盤工廠DiskFileItemFactory對象,用來配置上傳組件ServletFileUpload;

        DiskFileItemFactory factory = new DiskFileItemFactory();

DiskFileItemFactory類的常用方法

方法 返回值 描述
setSizeThrehold() void 該方法需要傳入一個int型參數,用來設置最大內存大小(byte為單位)
setRepositoryPath()

void

該方法需要傳入一個String型參數,用來設置臨時文件目錄
getRepository() File 獲取保存臨時文件地址

    2、其次,創建ServletFileUpload實例,即創建上傳文件的句柄。

      可通過DiskFileItemFactory實例構造ServletFileUpload對象,代碼如下:

       ServletFileUpload upload = newServletFileUpload(factory); 

ServletFileUpload類的常用方法
方法 返回值 描述
isMultipartContent() boolean 檢查是否是一個文件上傳請求
parseRequest() List 從request對象中得到所有上傳域表單

  四、使用例子(servlet部分代碼)

    下面就給出一個簡單的文件上傳的例子。

     1、jsp部分的代碼:

 1 <%@ page language="java" contentType="text/html; charset=utf-8"
 2     pageEncoding="UTF-8"%>
 3 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 4 <html>
 5 <head>
 6 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 7 <title>file upload demo</title>
 8 </head>
 9 <body>
10     <form action="/servletPro/FileUpload" method="post" enctype="multipart/form-data">
11         <table width="31%" border="0" align="center">
12             <tr bgcolor="#CCCCCC">
13                 <th height="26">請選擇要上傳的附件:</th>
14             </tr>
15             <tr>
16                 <td><label>上傳文件</label><input type="file" name="file" /></td>
17             </tr>
18             <tr bgcolor="#CCCCCC">
19                 <td height="23"><input type="submit" name="submit" value="上傳"></td>
20             </tr>
21         </table>
22     </form>
23     <%
24         if (request.getAttribute("result") != null) {
25             out.println("<script>alert('" + request.getAttribute("result") + "');</script>");
26         }
27     %>
28 </body>
29 </html>

    2、在項目WebContent/目錄下創建一個uploadfiles文件夾用來存放上傳的文件。

    3、創建一個名為FileUpload的servlet,代碼如下:
    

package com.hyman.servlet;

public class FileUpload extends HttpServlet {
    private static final long serialVersionUID = 1L;
    
    private String uploadFileDir;
    
    private ServletContext sc;
    
    
    public FileUpload() {
        super();
    }
    
    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        uploadFileDir = config.getInitParameter("uploadDir");
        sc = config.getServletContext();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        this.doPost(request, response);
    }


    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String simpleFileName = "";
        String fileDir = sc.getRealPath("/") + uploadFileDir;
        String message = "文件上傳成功!";
        if (ServletFileUpload.isMultipartContent(request)) {
            DiskFileItemFactory factory = new DiskFileItemFactory();
            factory.setSizeThreshold(20 * 1024); //20KB
            factory.setRepository(factory.getRepository());
            ServletFileUpload upload = new ServletFileUpload(factory);
            int maxSize = 2 * 1024 * 1024; //2MB
            List formlists = null;
            try {
                formlists = upload.parseRequest(request);
            } catch (FileUploadException e) {
                e.printStackTrace();
            }
            Iterator iterator = formlists.iterator();
            while (iterator.hasNext()) {
                FileItem formitem = (FileItem) iterator.next(); 
                if (formitem.isFormField()) {
                    String fieldname = formitem.getFieldName(); 
                    //這里是非上傳文件的表單域,可以通過formitem.getString(fieldname)來獲取相應表單字段的值
                } else {
                    //這里是上傳文件的表單域
                    String name = formitem.getName();
                    if (formitem.getSize() > maxSize) {
                        message = "您上傳的文件太大,請重新選擇不超過2M的文件";
                        break;
                    }
                    String fileSize = new Long(formitem.getSize()).toString();
                    if (name == null || "".equals(name) && "0".equals(fileSize)) 
                        continue;
                    int delimiter = name.lastIndexOf("\\");
                    simpleFileName = delimiter == -1 ? name : name.substring(delimiter + 1);
                    File saveFile = new File(fileDir, simpleFileName);
                    try {
                        formitem.write(saveFile);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        request.setAttribute("result", message);
        request.getRequestDispatcher("FileUpload.jsp").forward(request, response);
    }


}

    4、在web.xml中進行初始化參數配置:

 1  <servlet>
 2     <description></description>
 3     <display-name>FileUpload</display-name>
 4     <servlet-name>FileUpload</servlet-name>
 5     <servlet-class>com.hyman.servlet.FileUpload</servlet-class>
 6     <init-param>
 7         <param-name>uploadDir</param-name>
 8         <param-value>uploadfiles\</param-value>
 9     </init-param>
10   </servlet>
11   <servlet-mapping>
12     <servlet-name>FileUpload</servlet-name>
13     <url-pattern>/FileUpload</url-pattern>
14   </servlet-mapping>

  五、使用過程中遇到的一些問題及解決辦法

    1、每個用戶上傳的文件需要存放在以用戶uid通過MD5加密命名的文件夾中,即需先在uploadfiles目錄下創建一個對應的文件夾再將文件存該文件夾中。

      可以如下實現:

1 String fileDir = sc.getRealPath("/") + uploadFileDir;
2 //創建文件夾的路徑
3 String folderName = fileDir + "328ae78f9298e9a00c9dfa673280c17d";
4 File folder = new File(folderName);
5 if (!folder.exists()) {
6     folder.mkdir();
7 }

     2、路徑中的"/"改為"\"

        可以使用:folderName = folderName.replaceAll("/", "\\\\");

        路徑中的"\"改為"/"

        可以使用:folderName = folderName.replaceAll("\\\\", "/");

     3、在上傳文件的時候還提交了非上傳文件的表單,則讀取文件和其他表單數據的先后順序跟jsp文件中表單的前后順序有關。

     4、在項目中,可能同時上傳多份文件,而這些文件的全路徑需以一個特定的連接符連接起來存到數據庫中。我在項目中碰到這么一個問題,只要服務器重新啟動,第一次上傳文件保存的路徑集沒錯,但是之后的上傳都會出現路徑集中附帶之前上傳的文件路徑...而重啟服務器之后的第一次上傳又不會出現這種情況。這個問題着實糾結了很久,后來看到網上有介紹說可能是緩存的問題formitem用完要調用delete()方法清空緩存,這樣處理之后還是沒能解決這個問題。后來突然發現自己將保存每次上傳路徑集的String對象定義成了當前servlet的一個成員變量!!!servlet是單例的,該servlet只要被服務器創建了就會一直保存在服務器中,所以保存每次上傳路徑集的String對象會將每次上傳的文件全都疊加起來。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM