File upload using fileupload component

Keywords: Java encoding Apache

Reasons for using fileupload components:
The Request object provides a getInputStream() method through which the data submitted by the client can be read, but since users may upload multiple files at the same time, it is a very troublesome task to program and parse these uploaded data in the servlet. To facilitate developers to process file upload data, Apache Open Source Organization provides an open source component (Commons-fileupload) for processing form file upload. This component has excellent performance and is easy to use, which can make developers easily realize web file upload function.

To upload files using the Commons-fileupload component, it is necessary to import the corresponding supporting jar package of the component:
commons-fileupload and connons-io (the commons-upload component starts with version 1.1, and its work requires support from the commons-io package)

FileUpload component workflow:

The corresponding code framework is:

package pers.msidolphin.uploadservlet.web;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
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.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

/**
 * Servlet implementation class UploadServlet
 */
public class UploadServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public UploadServlet() {
        super();
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //Get the parsing factory
        DiskFileItemFactory factory = new DiskFileItemFactory();
        //Get the parser
        ServletFileUpload parser = new ServletFileUpload(factory);
        //Solving the problem of file name scrambling
        parser.setHeaderEncoding("UTF-8");
        //Determine the type of uploaded form
        if(!ServletFileUpload.isMultipartContent(request)) {
            return;
        }
        try {
            //Call parser to parse uploaded data
            List<FileItem> fileItems = parser.parseRequest(request);
            //Get the path to save the uploaded file directory
            String uploadPath = request.getServletContext().getRealPath("/WEB-INF/upload");
            //Traversing List Sets
            for (FileItem fileItem : fileItems) {
                //Determine whether it is a normal form field
                if(fileItem.isFormField()) {
                    //If it's a normal form field, print to the console
                    if(fileItem.getString() == null || "".equals(fileItem.getString().trim())) {
                        continue;
                    }
                    System.out.println(fileItem.getFieldName() + " = " + new String(fileItem.getString().getBytes("ISO-8859-1"), "UTF-8"));
                }else {
                    //Get the file path
                    String filePath = fileItem.getName();
                    //If the file is not uploaded, proceed with the next field
                    if(filePath == null || "".equals(filePath.trim())) {
                        continue;
                    }
                    System.out.println("process the file:" + filePath);
                    //Intercept file name
                    String fileName = filePath.substring(filePath.lastIndexOf("\\") + 1);
                    String reallyName = this.createFileName(fileName);
                    String reallyPath = this.mkDir(reallyName, uploadPath);
                    //Here are the usual IO operations
                    InputStream in = fileItem.getInputStream();
                    FileOutputStream out = new FileOutputStream(reallyPath + "\\" + reallyName);
                    byte[] buffer = new byte[1024];
                    int len = 0;
                    while((len = in.read(buffer)) > 0) {
                        out.write(buffer, 0, len);
                    }
                    out.close();
                    in.close();
                }
            }
            System.out.println("Finished processing...");
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    //Random Generation of Unique File Names
    private String createFileName(String fileName) throws NoSuchAlgorithmException, UnsupportedEncodingException {
        String extension = fileName.substring(fileName.lastIndexOf("."));
        MessageDigest md = MessageDigest.getInstance("md5");
        String currentTime = System.currentTimeMillis() + "";
        return UUID.randomUUID() + currentTime + extension;
    }

    //Generate directories based on hash values
    private String mkDir(String fileName, String uploadPath) {
        int hasCode = fileName.hashCode();
        //Low four bits as a first-level directory
        int parentDir = hasCode & 0xf;
        //Secondary catalogue
        int childDir = hasCode & 0xff >> 2;
        File file = new File(uploadPath + "\\" + parentDir + "\\" + childDir);
        if(!file.exists()) {
            file.mkdirs();
        }
        uploadPath = uploadPath + "\\" + parentDir + "\\" + childDir;
        return uploadPath;
    }

}

Core API: DiskFileItemFactory class

//Set the size of the memory buffer by default of 10K. When the upload file size is larger than the buffer size, the fileupload component will use temporary file cache to upload files.
public void setSizeThreshold(int sizeThreshold);
//Specifies that the default value of the temporary file directory is System.getProperty("java.io.tmpdir")
public void setRepository(java.io.file respository); 
//Construction method
public DiskFileItemFactory(int sizeThreshold, java.io.file respository);

Core API: ServletFileUpload class

//Determine whether the uploaded form is multipart/form-data type
boolean isMultipartContent(HttpServletRequest request);
//Parse the request object and wrap each input item in the form as a fileitem object, returning a list collection of these objects
List<FileItem> parseRequest(HttpServletRequest request);
//Set the maximum number of uploaded files in bytes
void setSizeMax(long sizeMax);
//Set the maximum unit of a single uploaded file: bytes
void setFileSizeMax(long fileSizeMax);
//Setting the encoding format to solve the problem of scrambling uploaded file names
void setHeaderEncoding(String encoding);
//Set up the file upload listener to get the size of uploaded files in real time
void setProgressListener(ProgressListener pListener);

Core API: FileItem class

//Determine whether the form input item is a normal input item (non-file input item, return true if it is a normal input item)
boolean isFormField();
//Get the name of the entry
String getFieldName();
//Get the value of the input item
String getString();
String getString(String encoding);  //Encoding can be set to solve the problem of data scrambling

The following are for non-ordinary fields:

//Get the full file name (different browsers may vary, some may contain paths, some may only have file names)
String getName();
//Get the file input stream
InputStream getInputStream();

Several points for attention in file upload:
1. File name scrambling problem of uploaded files: ServletFileUpload object provides setHeaderEncoding(String encoding) method to solve Chinese scrambling problem.

2. Chinese scrambling of uploaded data:
Solution 1: new String(fileItem.getString().getBytes("ISO-8859-1"), "UTF-8")
Solution 2: fileItem.getString("UTF-8")
Solution 3: fileItem.getString(request.getCharacterEncoding())

3. Uniqueness of upload file name: UUID, MD5 solutions are many.

4. It's better not to make the directory of uploaded files public.

5. Limit the size of uploaded files: The ServletFileUpload object provides setFileSizeMax(long fileSizeMax) and setSizeMax(long sizeMax) methods to solve this problem.

6. Restrict file upload types: intercept suffix names to make judgments (it seems not too strict, but also need to study...)

Posted by vig0 on Sat, 29 Jun 2019 10:50:05 -0700