文件上传

一、通过FileUpload工具实现文件上传

要使用FileUpload工具,就得先导入Commons-fileuoload.jar和commons-io.jar

在Servlet3.0之前仅仅通过Java原生的api很难实现文件的上传,而通过引用外部jar包所提供的工具类可以解决这一问题

下面代码是利用FileUpload工具及时清除文件上传时产生的临时文件

package com.zyr1106.file;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * 使用 commons fileupload 实现文件上传,并设置临时目录
 */
public class fileServlet02 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //判断当前表单是否满足文件上传
        request.setCharacterEncoding("utf-8");
        boolean multipartContent = ServletFileUpload.isMultipartContent(request);
        if (!multipartContent) {
         //不满足文件上传条件时,抛出一个异常
            throw new RuntimeException("该请求无法支持文件上传!");
        }
        //创建DiskFileItemFactory对象
        DiskFileItemFactory factory = new DiskFileItemFactory();
        //获取临时文件存放路径
        String path1 = this.getServletContext().getRealPath("/temp");
        factory.setRepository(new File(path1));


        //创建ServletFileUpload对象,该对象是文件上传的核心
        ServletFileUpload upload = new ServletFileUpload(factory);
        try {
            List<FileItem> items = upload.parseRequest(request);
            for (FileItem f : items) {
                //FormField:表单域
                if (f.isFormField()) {
                    //如果是单纯的表单,将他们获取并打印
                    String fieldName = f.getFieldName();
                    //getString可以获取表单中的值并设置编码为utf-8
                    String fieldValue = f.getString("UTF-8");
                    System.out.println(fieldName + ":" + fieldValue);
                } else {
                    InputStream inputStream = null;
                    FileOutputStream fos = null;
                    try {
                        //fieldName1获取的是上传文件名称
                        String fieldName1 = f.getName();
                        //fieldName2获取的是jsp中<<input type="file" name="photo"> 的name
                        String fieldName2 = f.getFieldName();
                        System.out.println(fieldName1);
                        System.out.println(fieldName2);

                        //获取输入流对象
                        inputStream = f.getInputStream();

                        //获取输出路径
                        String path = this.getServletContext().getRealPath("/upload");
                        //  System.out.println(path);
                        //创建File对象,并赋予路径path+fieldName1
                        File file = new File(path, fieldName1);
                        System.out.println(file);
                        //创建输出流
                        fos = new FileOutputStream(file);

                        //创建用于存放数据的byte数组
                        byte[] bytes = new byte[1024];
                        int len = -1;
                        while ((len = inputStream.read(bytes)) != -1) {
                            fos.write(bytes, 0, len);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    } finally {
                        if (inputStream != null) {
                            inputStream.close();
                        }
                        if (fos!=null){
                            fos.close();
                        }
                        //调用FileItem中的delete方法删除临时文件
                        f.delete();
                    }

                }
            }
        } catch (FileUploadException e) {
            e.printStackTrace();
        }
    }

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

为什么会产生临时文件?

文件经由浏览器上传到服务器,并不是把一整个完整的文件传输过去,而是将文件分解为若干个数据包通过网络传输给服务器,因此服务器会在临时目录下创建一个临时文件存放发过来的数据包,当一个文件的所有数据包都传输到服务器后,再将这些数据包拼接,最后服务器获得经由浏览器上传的文件。简单来说是因为传输过程需要将文件分成若干数据包进行传输,因此会借助临时文件存放这些数据包,最后再拼接成文件

DiskFileItemFactory对象可以设置生成临时文件所需的大小

factory.setSizeThreshold(1024 * 1024 *3);   //表示文件大于3MB之后再创建临时文件

二、使用UUID解决文件上传时文件名重名问题

当上传文件与服务器存在的文件名称重名时,上传的文件会覆盖服务器端的文件,解决这个问题可以使用java.util.UUID,UUID可以随机生成一串32位的随机数

UUID是Universally Unique Identifier的缩写,中文是通用统一识别码,uuid具有唯一性,uuid的生成跟系统的时间、mac地址、时间序列、随机数有关,所以通常所生成的uuid是不会重复的

所以文件的名称可以通过拼接UUID的方式存放

String fieldName1 = f.getName();//fieldName1获取的是上传文件名称

//为了获取文件名,有些IE浏览器会上传图片的本地路径
 fieldName1 = fieldName1.substring(fieldName1.lastIndexOf("\\") + 1);

//在文件名前面添加当前时间
fieldName1 = System.currentTimeMillis() + "_" +fieldName1;

//使用UUID添加文件名的前缀
fieldName1 = UUID.randomUUID()+"_"+fieldName1;

//fieldName2获取的是jsp中<<input type="file" name="photo"> 的name
 String fieldName2 = f.getFieldName();

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GH8hWt2p-1595233372522)(C:\Users\Administrator\Desktop\搜狗截图20200720151645.png)]

这样,文件就会以图上名称的形式保存在服务器上了

三、设置文件上传的大小

通过ServletFileUpload 中的setFileSizeMax()和setSizeMax()两个方法可以设置文件上传的大小

DiskFileItemFactory factory = new DiskFileItemFactory();

ServletFileUpload upload = new ServletFileUpload(factory);
//setFileSizeMax设置单个文件上传的大小,这里限制为2MB
upload.setFileSizeMax(1024*1024*2);
//setSizeMax设置单次上传的的大小,这里限制为5MB
upload.setSizeMax(1024*1024*5);

四、创建保存文件目录

上传的文件,应该分目录进行管理,下面是按年、月、日的层级目录来保存用户上传的文件

//获取输出路径
 String path = this.getServletContext().getRealPath("/upload");

		LocalDate now = LocalDate.now();
   		int year = now.getYear();
 		int month = now.getMonthValue();
		int day = now.getDayOfMonth();

	path = path + "/" + year + "/" + month + "/" + day;

	File parentDir = new File(path);
 		if (!parentDir.exists()) {
   //mkdirs方法创建此抽象路径名(path)指定的目录,包括创建必需但不存在的父目录。
		parentDir.mkdirs();
                        }
//创建File对象,并赋予路径path+fieldName1
	File file = new File(path, fieldName1);


);
 if (!parentDir.exists()) {
 //mkdirs方法创建此抽象路径名(path)指定的目录,包括创建必需但不存在的父目录。
 parentDir.mkdirs();
 }
 //创建File对象,并赋予路径path+fieldName1
 File file = new File(path, fieldName1);