JavaWeb文件上传的实现及FileUpload

一、概述

  1. 实现功能的类

    • ServletFileUpload
      • 负责处理上传的文件数据,并将表单中每个输入项封装成一个FileItem对象, 在使用ServletFileUpload对象解析请求时需要DiskFileItemFactory对象。所以,我们需要在进行解析工作前构造好DiskFileItemFactory对象,通过ServletFileUpload对象的构造方法或setFileItemFactory()方法设置ServletFileUpload对象的fileItemFactory属性。
    • DiskFileItemFactory
      • 将请求消息实体中的每一个项目封装成单独的DiskFileItem (FileItem接口的实现) 对象的任务由 FileItemFactory 接口的默认实现DiskFileItemFactory 来完成。当上传的文件项目比较小时,直接保存在内存中(速度比较快),比较大时,以临时文件的形式,保存在磁盘临时文件夹(虽然速度慢些,但是内存资源是有限的)。
  2. 项目所需依赖

    <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
    <dependency>
        <groupId>commons-fileupload</groupId>
        <artifactId>commons-fileupload</artifactId>
        <version>1.4</version>
    </dependency>
    

二、实现功能的注意事项

  • 为保证服务器安全,上传文件应放在外界无法直接访问的目录下,就比如放于WEB-INF目录下
  • 为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名
  • 要限制上传文件的最大值,避免用户恶意占用磁盘资源
  • 要限制上传文件的类型,在收到上传文件时,判断后缀名是否合法
  • 表单 method 属性应该设置为POST 方法,不能使用 GET 方法

三、代码实现

  • index.jsp
    • ${pageContext.request.contextPath} 是JSP取得绝对路径的方法,等价于<%=request.getContextPath()%> ,也就是取出部署的应用程序名或者是当前的项目名称。
    • enctype="multipart/form-data"是将文件以二进制的形式上传,这样可以实现多种类型的文件上传。
    • 表单必须是POST请求。
<%-- 这里主要讲解后端实现,前端就不过多展示 --%>
<form action="${pageContext.request.contextPath}/upload" enctype="multipart/form-data" method="post">
    <input type="text" name="content">
    <input type="file" name="file01">
    <input type="file" name="file02">
    <input type="submit" value="提交" />
</form>
<!--文件上传-->
<servlet>
    <servlet-name>UploadServlet</servlet-name>
    <servlet-class>com.hello.UploadServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>UploadServlet</servlet-name>
    <url-pattern>/upload</url-pattern>
</servlet-mapping>
  • Servlet
package com.hello;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.ProgressListener;
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;
import java.util.UUID;

/**
 * 文件上传功能
 */
@SuppressWarnings({"all"})
public class UploadServlet extends HttpServlet {
    @Override
    public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    	// ================ 初始化 ===================
        // 接收和响应的编码处理
        req.setCharacterEncoding("utf-8");
        resp.setCharacterEncoding("utf-8");

        // 创建文件的上传路径
        String uploadPath = req.getServletContext().getRealPath("/WEB-INF/upload");
        System.out.println("realPath:" + uploadPath);
        File uploadFile = new File(uploadPath);
        // 文件夹不存在,需要创建文件夹
        if (!uploadFile.exists())
            uploadFile.mkdir();

        // 创建大文件临时保存路径,重复上述步骤
        String tempPath = req.getServletContext().getRealPath("/WEB-INF/temp");
        System.out.println("realPath:" + tempPath);
        File tempFile = new File(tempPath);
        if (!tempFile.exists())
            tempFile.mkdir();

        // 创建 DiskFileItemFactory 对象
        DiskFileItemFactory factory = new DiskFileItemFactory();
        // 设置一个缓冲区,当上传的文件大于这个缓冲区的时候,将他放到临时文件中
        factory.setSizeThreshold(1024 * 1024 * 10); // 缓冲区大小设为 10M
        factory.setRepository(tempFile);  // 临时文件保存的目录,需要一个FiLe

        // 创建 ServletFileUpload对象
        ServletFileUpload upload = new ServletFileUpload(factory);
        // 设置文件编码
        upload.setHeaderEncoding("utf-8");
        // 设置单文件接收的最大值 10M
        upload.setFileSizeMax(1024 * 1024 * 10);
        // 设置总共能够上传的文件大小 10M
        upload.setSizeMax(1024 * 1024 * 10);
        // 监听文件的上传进度
        upload.setProgressListener(new ProgressListener() {
            public void update(long pBytesRead, long pContentLength, int pItems) {
                // pBytesRead:已经读取到的文件大小
                // pContentLength:文件大小
                System.out.println("文件总大小:" + pContentLength + "已上传" + pBytesRead);
            }
        });

        /*============== 处理请求 ==============*/
        try {
            // 将前端的请求解析成 fileItem对象
            List<FileItem> fileItems = upload.parseRequest(req);
            // 遍历List集合,判断是否为文件
            for (FileItem fileItem : fileItems) {
                if (fileItem.isFormField()) {
                    // 普通表单控件
                    String name = fileItem.getFieldName();
                    String value = fileItem.getString("utf-8");
                    System.out.println(name + ":" + value);
                } else {
                    // ================ 文件处理开始 ===================
                    // 获取文件名字,判断文件名字是否合法
                    String fileName = fileItem.getName();
                    if (fileName.trim().equals("") && fileName == null)
                        continue;

                    // 获取上传的文件名和文件后缀名
                    String uploadFileName = fileName.substring(fileName.lastIndexOf("/") + 1);
                    String uploadFileEndName = fileName.substring(fileName.lastIndexOf(".") + 1);
                    // 这里可以验证文件的后缀名是否为所需...
                    System.out.println("文件:" + uploadFileName + "正在上传,文件类型为" + uploadFileEndName);
                    // 这里为了文件名的唯一性,可以使用UUID(唯一识别通用码)来保证唯一性,关于UUID的用法,这里不再赘述,有兴趣的小伙伴可以去了解一下
                    String uuidPath = UUID.randomUUID().toString();
                    // ================ 文件处理结束 ===================

                    // ================ 文件传输开始 ===================
                    // 获取输入流
                    InputStream in = fileItem.getInputStream();
                    // 获取文件输出流,路径为存放文件的真实路径 /WEB-INF/xxx
                    FileOutputStream out = new FileOutputStream(uploadPath + "/" + uuidPath + "." + uploadFileEndName);
                    // 创建缓冲区
                    byte[] buffer = new byte[1024];
                    int len = 0;
                    // 将流写入文件
                    while ((len = in.read(buffer)) > 0) {
                        out.write(buffer, 0, len);
                    }
                    System.out.println("文件上传成功,路径为:" + uploadPath + "\\" + uploadFileName);
                    // 最后关闭流,释放资源
                    out.close();
                    in.close();
                    // 响应给前端文件上传成功的信息
                    req.setAttribute("msg", "文件上传成功");
                    // ================ 文件传输结束 ===================
                }
            }
        } catch (Exception e) {
            // 响应给前端文件上传失败的信息
            req.setAttribute("msg", "文件上传失败");
            throw new RuntimeException(e);
        }
    }
}

四、最终效果图

在这里插入图片描述

  • 到这里功能就基本实现了,如果有报错的话,就需要去检查一下代码是否打错或者看一下配置是否正确了
结语:感谢您的阅读,欢迎指正博客中存在的问题,也可以跟我联系,一起进步,一起交流!
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值