使用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对象会将每次上传的文件全都叠加起来。

 

原文地址:https://www.cnblogs.com/page-of-Hyman/p/4449881.html