Java Web - File Upload and Download

Keywords: Java Apache JSP xml

In the development of Web application system, file upload and download functions are very common functions. Today, let's talk about the implementation of file upload and download functions in Java Web.

For file upload, browsers submit files as streams to the server in the process of uploading. If it is more troublesome to get the input stream of uploaded files directly by using Servlet and then parse the request parameters, it is generally preferred to use apache's open source tool common-fileupload as the file upload component. The jar package of the common-fileupload upload component can be downloaded on apache's official website or found under the lib folder of struts. The function of struts upload is based on this. Comm-fileupload relies on the common-io package, so it needs to be downloaded.


1. Construction of Development Environment

Create a FileUpload AndDownLoad project and join Apache's commons-fileupload file upload component's Jar package (note to put it under WebRoot-WEB-INF-lib, not build path), as shown below:

2. Implementing file upload

2.1. File upload page and message prompt page

The code for upload.jsp page is as follows:

<%@ page language="java" pageEncoding="UTF-8"%>
<!DOCTYPE HTML>
<html>
  <head>
    <title>File upload</title>
  </head>
  
  <body>
    <form action="${pageContext.request.contextPath}/servlet/UploadHandleServlet" enctype="multipart/form-data" method="post">
        //Upload user: <input type="text" name="username"><br/>
        //Upload file 1: <input type="file" name="file1"><br/>
        //Upload file 2: <input type="file" name="file2"><br/>
        <input type="submit" value="Submission">
    </form>
  </body>
</html>

The code for message.jsp is as follows:

<%@ page language="java" pageEncoding="UTF-8"%>
<!DOCTYPE HTML>
<html>
  <head>
    <title>Message hint</title>
  </head>
  
  <body>
        ${message}
  </body>
</html>

2.2. Servlet Processing File Upload

The code for the Upload Handle Servlet is as follows:

package me.gacl.web.controller;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

public class UploadHandleServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
                //Get the saved directory of uploaded files, store the uploaded files in WEB-INF directory, do not allow outside direct access, ensure the security of uploaded files.
                String savePath = this.getServletContext().getRealPath("/WEB-INF/upload");
                File file = new File(savePath);
                //Determine whether the saved directory of the uploaded file exists
                if (!file.exists() && !file.isDirectory()) {
                    System.out.println(savePath+"The directory does not exist and needs to be created");
                    //Create directory
                    file.mkdir();
                }
                //Message hint
                String message = "";
                try{
                    //Processing file upload steps using Apache file upload component:
                    //1. Create a DiskFile ItemFactory
                    DiskFileItemFactory factory = new DiskFileItemFactory();
                    //2. Create a file upload parser
                    ServletFileUpload upload = new ServletFileUpload(factory);
                     //Resolve Chinese Scrambling of Uploaded File Names
                    upload.setHeaderEncoding("UTF-8"); 
                    //3. Determine whether the submitted data is uploaded form data?
                    if(!ServletFileUpload.isMultipartContent(request)){
                        //Obtaining data in a traditional way
                        return;
                    }
                    //4. Using the ServletFileUpload parser to parse the uploaded data, the parsing result returns a List < FileItem > collection, each FileItem corresponds to an input item of a Form form.
                    List<FileItem> list = upload.parseRequest(request);
                    for(FileItem item : list){
                        //If the data encapsulated in fileitem is normal input item
                        if(item.isFormField()){
                            String name = item.getFieldName();
                            //Solving the Chinese scrambling problem of the data of common input items
                            String value = item.getString("UTF-8");
                            //value = new String(value.getBytes("iso8859-1"),"UTF-8");
                            System.out.println(name + "=" + value);
                        }else{//If the uploaded file is encapsulated in fileitem
                            //Get the name of the uploaded file.
                            String filename = item.getName();
                            System.out.println(filename);
                            if(filename==null || filename.trim().equals("")){
                                continue;
                            }
                            //Note: File names submitted by different browsers are different. Some browsers submit file names with paths, such as: c: a b 1.txt, while others are simply file names, such as: 1.txt.
                            //Processing the path part of the file name of the acquired uploaded file, leaving only the file name part
                            filename = filename.substring(filename.lastIndexOf("\\")+1);
                            //Get the input stream of the uploaded file in item
                            InputStream in = item.getInputStream();
                            //Create a file output stream
                            FileOutputStream out = new FileOutputStream(savePath + "\\" + filename);
                            //Create a buffer
                            byte buffer[] = new byte[1024];
                            //Identification to determine whether the data in the input stream has been read out
                            int len = 0;
                            //The loop reads the input stream into the buffer, (len = in. read (buffer) > 0 means that there is data in the buffer.
                            while((len=in.read(buffer))>0){
                                //Use the FileOutputStream output stream to write buffer data to the specified directory (savePath + "\" + filename)
                                out.write(buffer, 0, len);
                            }
                            //Close the input stream
                            in.close();
                            //Close the output stream
                            out.close();
                            //Delete temporary files generated when processing file uploads
                            item.delete();
                            message = "Document upload success!";
                        }
                    }
                }catch (Exception e) {
                    message= "File upload failed!";
                    e.printStackTrace();
                    
                }
                request.setAttribute("message",message);
                request.getRequestDispatcher("/message.jsp").forward(request, response);
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        doGet(request, response);
    }
}

Register Upload Handle Servlet in Web.xml file
<servlet>
    <servlet-name>UploadHandleServlet</servlet-name>
    <servlet-class>me.gacl.web.controller.UploadHandleServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>UploadHandleServlet</servlet-name>
    <url-pattern>/servlet/UploadHandleServlet</url-pattern>
</servlet-mapping>

The operation results are as follows:


After successful file upload, the upload file is saved in the upload directory of WEB-INF directory, as shown in the following figure:

2.3. Details of file upload

Although the above code can successfully upload files to the specified directory on the server, the file upload function has many small details to pay attention to. The following points need special attention

1. In order to ensure the security of the server, uploaded files should be placed in directories that can not be accessed directly by the outside world, such as WEB-INF directory.

2. To prevent file overwriting, a unique file name should be created for uploading files.

3. In order to prevent too many files from appearing under a directory, hash algorithm should be used to scatter the storage.

4. Limit the maximum value of uploaded files.

5. To limit the type of uploaded file, judge whether the suffix name is legal when the uploaded file name is received.


To address the five details mentioned above, let's improve the Upload Handle Servlet. The improved code is as follows:

package me.gacl.web.controller;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadBase;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

/**
* @ClassName: UploadHandleServlet
* @Description: TODO(Here is a sentence describing the function of this class.
* @author: Aloof and proud wolf
* @date: 2015-1-3 11:35:50 p.m.
*
*/ 
public class UploadHandleServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
                //Get the saved directory of uploaded files, store the uploaded files in WEB-INF directory, do not allow outside direct access, ensure the security of uploaded files.
                String savePath = this.getServletContext().getRealPath("/WEB-INF/upload");
                //Temporary file saved directory generated when uploading
                String tempPath = this.getServletContext().getRealPath("/WEB-INF/temp");
                File tmpFile = new File(tempPath);
                if (!tmpFile.exists()) {
                    //Create temporary directories
                    tmpFile.mkdir();
                }
                
                //Message hint
                String message = "";
                try{
                    //Processing file upload steps using Apache file upload component:
                    //1. Create a DiskFile ItemFactory
                    DiskFileItemFactory factory = new DiskFileItemFactory();
                    //Set the size of the factory buffer. When the uploaded file size exceeds the size of the buffer, a temporary file will be generated and stored in the specified temporary directory.
                    factory.setSizeThreshold(1024*100);//Set the size of the buffer to 100KB. If not specified, the default size of the buffer is 10KB.
                    //Set the save directory of temporary files generated when uploading
                    factory.setRepository(tmpFile);
                    //2. Create a file upload parser
                    ServletFileUpload upload = new ServletFileUpload(factory);
                    //Monitor file upload progress
                    upload.setProgressListener(new ProgressListener(){
                        public void update(long pBytesRead, long pContentLength, int arg2) {
                            System.out.println("The file size is:" + pContentLength + ",Currently processed:" + pBytesRead);
                            /**
                             * File size: 14608, currently processed: 4096
                                File size: 14608, currently processed: 7367
                                File size: 14608, currently processed: 11419
                                File size: 14608, currently processed: 14608
                             */
                        }
                    });
                     //Resolve Chinese Scrambling of Uploaded File Names
                    upload.setHeaderEncoding("UTF-8"); 
                    //3. Determine whether the submitted data is uploaded form data?
                    if(!ServletFileUpload.isMultipartContent(request)){
                        //Obtaining data in a traditional way
                        return;
                    }
                    
                    //Set the maximum size for uploading a single file, currently set to 1024 * 1024 bytes, or 1MB
                    upload.setFileSizeMax(1024*1024);
                    //Set the maximum value of the total number of uploaded files, the maximum value = the sum of the maximum sizes of multiple files uploaded at the same time, currently set to 10MB
                    upload.setSizeMax(1024*1024*10);
                    //4. Using the ServletFileUpload parser to parse the uploaded data, the parsing result returns a List < FileItem > collection, each FileItem corresponds to an input item of a Form form.
                    List<FileItem> list = upload.parseRequest(request);
                    for(FileItem item : list){
                        //If the data encapsulated in fileitem is normal input item
                        if(item.isFormField()){
                            String name = item.getFieldName();
                            //Solving the Chinese scrambling problem of the data of common input items
                            String value = item.getString("UTF-8");
                            //value = new String(value.getBytes("iso8859-1"),"UTF-8");
                            System.out.println(name + "=" + value);
                        }else{//If the uploaded file is encapsulated in fileitem
                            //Get the name of the uploaded file.
                            String filename = item.getName();
                            System.out.println(filename);
                            if(filename==null || filename.trim().equals("")){
                                continue;
                            }
                            //Note: File names submitted by different browsers are different. Some browsers submit file names with paths, such as: c: a b 1.txt, while others are simply file names, such as: 1.txt.
                            //Processing the path part of the file name of the acquired uploaded file, leaving only the file name part
                            filename = filename.substring(filename.lastIndexOf("\\")+1);
                            //Get the extension of the uploaded file
                            String fileExtName = filename.substring(filename.lastIndexOf(".")+1);
                            //If you need to limit the type of file you upload, you can use the extension of the file to determine whether the uploaded file type is legitimate.
                            System.out.println("The extension of the uploaded file is:"+fileExtName);
                            //Get the input stream of the uploaded file in item
                            InputStream in = item.getInputStream();
                            //Get the name of the file saved
                            String saveFilename = makeFileName(filename);
                            //Get the saved directory of the file
                            String realSavePath = makePath(saveFilename, savePath);
                            //Create a file output stream
                            FileOutputStream out = new FileOutputStream(realSavePath + "\\" + saveFilename);
                            //Create a buffer
                            byte buffer[] = new byte[1024];
                            //Identification to determine whether the data in the input stream has been read out
                            int len = 0;
                            //The loop reads the input stream into the buffer, (len = in. read (buffer) > 0 means that there is data in the buffer.
                            while((len=in.read(buffer))>0){
                                //Use the FileOutputStream output stream to write buffer data to the specified directory (savePath + "\" + filename)
                                out.write(buffer, 0, len);
                            }
                            //Close the input stream
                            in.close();
                            //Close the output stream
                            out.close();
                            //Delete temporary files generated when processing file uploads
                            //item.delete();
                            message = "Document upload success!";
                        }
                    }
                }catch (FileUploadBase.FileSizeLimitExceededException e) {
                    e.printStackTrace();
                    request.setAttribute("message", "Single file exceeds maximum!!!");
                    request.getRequestDispatcher("/message.jsp").forward(request, response);
                    return;
                }catch (FileUploadBase.SizeLimitExceededException e) {
                    e.printStackTrace();
                    request.setAttribute("message", "The total size of uploaded files exceeds the maximum limit!!!");
                    request.getRequestDispatcher("/message.jsp").forward(request, response);
                    return;
                }catch (Exception e) {
                    message= "File upload failed!";
                    e.printStackTrace();
                }
                request.setAttribute("message",message);
                request.getRequestDispatcher("/message.jsp").forward(request, response);
    }
    
    /**
    * @Method: makeFileName
    * @Description: Generate the file name of the uploaded file with the original name of uuid+""+file
    * @Anthor:Aloof and proud wolf
    * @param filename The original name of the file
    * @return uuid+"_"+The original name of the file
    */ 
    private String makeFileName(String filename){  //2.jpg
        //To prevent file overwriting, a unique file name is generated for uploading files.
        return UUID.randomUUID().toString() + "_" + filename;
    }
    
    /**
     * To prevent too many files from appearing under a directory, hash algorithm is used to scatter storage.
    * @Method: makePath
    * @Description: 
    * @Anthor:Aloof and proud wolf
    *
    * @param filename File name, to generate storage directory based on file name
    * @param savePath File Storage Path
    * @return New storage directory
    */ 
    private String makePath(String filename,String savePath){
        //Get the hashCode value of the file name, and get the address of the string object filename in memory.
        int hashcode = filename.hashCode();
        int dir1 = hashcode&0xf;  //0--15
        int dir2 = (hashcode&0xf0)>>4;  //0-15
        //Construct a new saved directory
        String dir = savePath + "\\" + dir1 + "\\" + dir2;  //upload\2\3  upload\3\5
        //File can represent both files and directories
        File file = new File(dir);
        //If the directory does not exist
        if(!file.exists()){
            //Create directory
            file.mkdirs();
        }
        return dir;
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        doGet(request, response);
    }
}

III. File Download

3.1. List file resources for download

We want to provide file resources in Web application system for users to download. First of all, we need a page to list all files in the uploaded file directory. When users click on the file download hyperlink, we download the files and write a ListFile Servlet to list all downloaded files in Web application system.

The code for ListFileServlet is as follows:

package me.gacl.web.controller;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* @ClassName: ListFileServlet
* @Description: List all downloaded files in the Web system
* @author: Aloof and proud wolf
* @date: 2015-1-4 9:54:40 p.m.
*
*/ 
public class ListFileServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //Get the directory of the uploaded file
        String uploadFilePath = this.getServletContext().getRealPath("/WEB-INF/upload");
        //Store the file name to download
        Map<String,String> fileNameMap = new HashMap<String,String>();
        //Recursively traverse all files and directories in the filepath directory, and store the file name of the file in the map collection
        listfile(new File(uploadFilePath),fileNameMap);//File can represent either a file or a directory
        //Send the Map collection to the listfile.jsp page for display
        request.setAttribute("fileNameMap", fileNameMap);
        request.getRequestDispatcher("/listfile.jsp").forward(request, response);
    }
    
    /**
    * @Method: listfile
    * @Description: Recursively traverses all files in a specified directory
    * @Anthor:Aloof and proud wolf
    * @param file Represents both a file and a file directory.
    * @param map Map Collection for Storing File Names
    */ 
    public void listfile(File file,Map<String,String> map){
        //If the file represents not a file, but a directory
        if(!file.isFile()){
            //List all files and directories in this directory
            File files[] = file.listFiles();
            //Traverse files [] arrays
            for(File f : files){
                //recursion
                listfile(f,map);
            }
        }else{
            /**
             * Processing file names. Uploaded files are renamed in the form of uuid_file names, and the uuid_part of file names is removed.
                file.getName().indexOf("_")Retrieve the location of the first occurrence of the "" character in the string if the filename is similar to: 9349249849-88343-8344_A_Vanda.avi
                Then after file. getName (). substring (file. getName (). indexOf ("")+1) processing, you can get the Avanda. avi part.
             */
            String realName = file.getName().substring(file.getName().indexOf("_")+1);
            //file.getName() gets the original name of the file, which is unique, so it can be used as a key. realName is the name after processing and may be repeated.
            map.put(file.getName(), realName);
        }
    }
    
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}

listfile method in ListFileServlet is used to list all files in the directory. Recursion is used in listfile method. In practice, we will create a table in the database, which will store the uploaded file name and the specific storage directory of the file. We can know the details of the file by querying the table. There is no need to use recursive operation to store directories. This example is because the database is not used to store the uploaded file names and the specific storage location of files, and the storage location of uploaded files is scattered by hashing algorithm. Therefore, recursion is needed. When recursion occurs, the obtained file names are stored in the Map set passed from outside to the file method. In this way, you can ensure that all files are stored in the same Map collection.

Configure ListFileServlet in Web.xml file

<servlet>
     <servlet-name>ListFileServlet</servlet-name>
     <servlet-class>me.gacl.web.controller.ListFileServlet</servlet-class>
</servlet>
 
<servlet-mapping>
     <servlet-name>ListFileServlet</servlet-name>
    <url-pattern>/servlet/ListFileServlet</url-pattern>
</servlet-mapping>

The listfile.jsp page showing the download file is as follows:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML>
<html>
  <head>
    <title>Download File Display Page</title>
  </head>
  
  <body>
      <!-- ergodic Map aggregate -->
    <c:forEach var="me" items="${fileNameMap}">
        <c:url value="/servlet/DownLoadServlet" var="downurl">
            <c:param name="filename" value="${me.key}"></c:param>
        </c:url>
        ${me.value}<a href="${downurl}">download</a>
        <br/>
    </c:forEach>
  </body>
</html>

Accessing the ListFileServlet, you can display the file resources provided for users to download in the listfile.jsp page, as shown in the following figure:


3.2. Realizing File Download

Write a Servlet for processing file downloads. The code for DownLoad Servlet is as follows:

package me.gacl.web.controller;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class DownLoadServlet extends HttpServlet {

    
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //Get the file name to download
        String fileName = request.getParameter("filename");  //23239283-92489-Avatar.avi
        fileName = new String(fileName.getBytes("iso8859-1"),"UTF-8");
        //Uploaded files are stored in subdirectories in the / WEB-INF/upload directory
        String fileSaveRootPath=this.getServletContext().getRealPath("/WEB-INF/upload");
        //Find the directory of the file by its name
        String path = findFileSavePathByFileName(fileName,fileSaveRootPath);
        //Get the file to download
        File file = new File(path + "\\" + fileName);
        //If the file does not exist
        if(!file.exists()){
            request.setAttribute("message", "The resources you want to download have been deleted!!");
            request.getRequestDispatcher("/message.jsp").forward(request, response);
            return;
        }
        //Processing File Names
        String realname = fileName.substring(fileName.indexOf("_")+1);
        //Set the response header to control the browser to download the file
        response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(realname, "UTF-8"));
        //Read the file to download and save it to the file input stream
        FileInputStream in = new FileInputStream(path + "\\" + fileName);
        //Create an output stream
        OutputStream out = response.getOutputStream();
        //Creating Buffers
        byte buffer[] = new byte[1024];
        int len = 0;
        //The loop reads the contents of the input stream into the buffer
        while((len=in.read(buffer))>0){
            //Output Buffer Content to Browser to Realize File Download
            out.write(buffer, 0, len);
        }
        //Close File Input Stream
        in.close();
        //Close the output stream
        out.close();
    }
    
    /**
    * @Method: findFileSavePathByFileName
    * @Description: Find the path of the file to download through the file name and the root directory of the uploaded file
    * @Anthor:Aloof and proud wolf
    * @param filename File name to download
    * @param saveRootPath The root directory where the upload file is saved, that is, / WEB-INF/upload directory
    * @return Storage directory of files to download
    */ 
    public String findFileSavePathByFileName(String filename,String saveRootPath){
        int hashcode = filename.hashCode();
        int dir1 = hashcode&0xf;  //0--15
        int dir2 = (hashcode&0xf0)>>4;  //0-15
        String dir = saveRootPath + "\\" + dir1 + "\\" + dir2;  //upload\2\3  upload\3\5
        File file = new File(dir);
        if(!file.exists()){
            //Create directory
            file.mkdirs();
        }
        return dir;
    }
    
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}

Configure DownLoadServlet in Web.xml file

<servlet>
      <servlet-name>DownLoadServlet</servlet-name>
      <servlet-class>me.gacl.web.controller.DownLoadServlet</servlet-class>
</servlet>
 
<servlet-mapping>
      <servlet-name>DownLoadServlet</servlet-name>
      <url-pattern>/servlet/DownLoadServlet</url-pattern>
</servlet-mapping>

Click on the hyperlink and submit the request to DownLoad Servlet for processing. The file can be downloaded. The effect is as follows:


From the running results, we can see that our file download function can download files normally.

There's so much about file upload and download in Java Web.

(This article is from: http://www.cnblogs.com/xdp-gacl/p/4200090.html)

Posted by eziitiss on Thu, 18 Apr 2019 18:12:33 -0700