飞道的博客

用 commons-fileupload 实现文件上传

527人阅读  评论(0)


文件上传系统

1. 主要需求

  • 在用户注册页面,输入用户名,可以选择要上传的文件;
  • 点击提交按钮,可以将用户输入的内容和选择的文件保存到服务器上。

2. 技术分析

a. 客户端将文件转为文本

i. 要求

  • 表单提交方式必须为 post,即 action="post"。因为 get 方式的地址栏会有大小的限制。
  • 表单的 enctype 属性值必须为 multipart/form-data 多组件表单数据,即 enctype="multipart/form-data"
  • 必须在表单中提供文件上传项,即 <input type="file" name="pic">

ii. 多组件表单数据

  • Chrome 无法查看多组件文件上传信息:
  • 推荐使用 FireFox 查看:
  • 在消息头(请求头)中获得黄金分割线:
  • enctype="multipart/form-data" 的作用:将请求体通过黄金分割线分割为单项内容:
  • 文件上传项中会将上传内容转为文本输出。

b. 服务器将文本转为字节流

i. 获取浏览器上传的数据

  • 如果直接通过 Request 对象,效率就会变得非常低,所以可以借用第三方技术来实现:

ii. 处理 IO 流的 3 种方式

  1. 使用 Apache 提供工具类 commons-fileupload。(这里用到的方式)
  2. 使用 Servlet3.0 版本。(通过注解实现)
  3. 使用 SpringMVC 框架。(底层使用了 commons-fileupload)

3. 代码实现

a. 导入文件上传相关 Jar 包

相关 Jar 包已上传至 CSDN:文件上传相关 Jar 包

b. index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
  <title>${NAME}</title>
  <script src="${pageContext.request.contextPath}/js/jquery-3.2.1.js"></script>
</head>
<body>
<h3>文件上传</h3>
<form action="${pageContext.request.contextPath}/UploadServlet" method="post" enctype="multipart/form-data">
    用户名:<input type="text" name="username" id="username"><br>
    上传图片:<input type="file" name="pic"><br>
    <input type = "submit" value="提交表单">
</form>
</body>
</html>

c. 指定服务器保存文件路径

d. UploadServlet 接收文件并保存

i. 步骤分析

  1. 创建磁盘文件项工厂;
  2. 创建核心解析对象(依赖工厂对象);
  3. 解析 Request 对象,返回上传项 List 集合;
  4. 遍历 List,获取每一个上传项;
  5. 判断:
    • 普通上传项:保存 name 和 value;
    • 文件上传项:保存文件名和文本字节输入流到服务器端。

ii. UploadServlet

package com.company;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.IdUtil;
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.annotation.WebServlet;
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;

@WebServlet("/UploadServlet")
public class UploadServlet extends HttpServlet {

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

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            // 1.创建磁盘文件项工厂
            DiskFileItemFactory factory = new DiskFileItemFactory();
            // 2.创建上传解析器对象(依赖工厂对象)
            ServletFileUpload fileUpload = new ServletFileUpload(factory);
            // 3.解析Request请求,返回上传项List集合
            List<FileItem> fileItems = fileUpload.parseRequest(request);
            // 4.遍历List
            for (FileItem fileItem : fileItems) {
                // 5.判断是文件项还是普通项
                if (fileItem.isFormField()) {// 普通上传项
                    // 获取name属性名
                    String name = fileItem.getFieldName();
                    // 获取value属性值
                    String value = fileItem.getString();
                    System.out.println("普通上传项:" + name + "=" + value);
                } else {// 文件上传项
                    // a.获取文件名 Regino.txt
                    String fileName = fileItem.getName();
                    // b.获取文件字节输入流
                    InputStream in = fileItem.getInputStream();
                    // c.获取文件扩展名
                    String extName = FileUtil.extName(fileName);
                    // d.生成随机文件名,解决服务器端保存的文件出现文件名重复问题
                    fileName = IdUtil.simpleUUID() + "." + extName; // UUID 全球唯一

                    // 此文件名会保存数据库一份,给用户查询使用...

                    // 获取upload目录在服务器真实路径
                    String realPath = request.getServletContext().getRealPath("/upload/");

                    // 判断此目录是否存在,解决IDEA没有上传空的upload文件夹导致找不到输出目录的问题
                    File dirFile = new File(realPath);
                    if (!dirFile.exists()) {
                        dirFile.mkdirs(); // 如果不存在自己创建
                    }

                    // 设置文件字节输出流
                    FileOutputStream out = new FileOutputStream(realPath + fileName);

                    // 流的拷贝
                    IoUtil.copy(in, out);

                    // 关流
                    out.close();
                    in.close();

                    response.getWriter().write("success");
                }
            }
        } catch (FileUploadException e) {
            e.printStackTrace();
        }
    }
}

e. 测试

  • 上传文件,提交表单:

  • 页面显示:

  • 控制台显示:

  • 上传文件已保存:

原文链接:https://qwert.blog.csdn.net/article/details/105781749


转载:https://blog.csdn.net/Regino/article/details/105781749
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场