美文网首页
92、【JavaEE】【Servlet 与 JSP】文件上传

92、【JavaEE】【Servlet 与 JSP】文件上传

作者: yscyber | 来源:发表于2021-10-11 05:02 被阅读0次

1、概述

  • 均是简易案例。

  • 后端使用的第三方库是:Apache Commons FileUpload、Apache Commons IO

2、HTML 原生提交

2.1、单个文件

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>File Upload</title>
</head>
<body>
<form method="post" enctype="multipart/form-data" action="http://localhost:8080/receive-data/receive/file-upload/1">
    <input type="text" name="my_text" autocomplete="false" />
    <input type="file" name="my_file" />
    <input type="submit" value="提交" />
</form>
</body>
</html>
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 org.apache.commons.io.IOUtils;

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.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;

@WebServlet(name = "FileUploadServlet1", urlPatterns = "/receive/file-upload/1")
public class FileUploadServlet1 extends HttpServlet {

    private static final String CHARSET_ENCODING = "UTF-8";

    private static final long UPLOAD_FILE_MAX_BYTES = 5 * 1024 * 1024;

    private static final String UPLOAD_FILE_TARGET_PATH = "E:\\";

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding(CHARSET_ENCODING);
        response.setCharacterEncoding(CHARSET_ENCODING);

        try {
            // 1. Create a factory for disk-based file items
            DiskFileItemFactory factory = new DiskFileItemFactory();

            // 2. Create a new file upload handler
            ServletFileUpload uploadHandler = new ServletFileUpload(factory);

            // 3. Set constraints (约束)

            // 文件名编码
            uploadHandler.setHeaderEncoding(CHARSET_ENCODING);
            // 文件最大不超过 5MB
            // 单位是字节
            uploadHandler.setFileSizeMax(UPLOAD_FILE_MAX_BYTES);

            // 4. Parse the request, get a item list parsed from the form
            List<FileItem> formItemList = uploadHandler.parseRequest(request);

            // 5. Process
            for (FileItem item : formItemList) {
                if (item.isFormField()) {
                    // item.isFormField() == false
                    // item is not a file
                    String fieldName = item.getFieldName();
                    String value = item.getString(CHARSET_ENCODING);
                    System.out.println(fieldName + "=" + value);
                } else {
                    // item.isFormField() == true
                    // item is a file
                    String fieldName = item.getFieldName();
                    String fileName = item.getName();
                    System.out.println(fieldName + "=" + fileName);

                    String newFileName = UUID.randomUUID().toString().replaceAll("-", "") + fileName.substring(fileName.lastIndexOf("."));
                    InputStream in = item.getInputStream();
                    FileOutputStream fos = new FileOutputStream(UPLOAD_FILE_TARGET_PATH + newFileName);
                    IOUtils.copy(in, fos);
                    if (fos != null) {
                        fos.close();
                    }
                    if (in != null) {
                        in.close();
                    }
                }
            }
        } catch (FileUploadException e) {
            e.printStackTrace();
        }
    }

}

2.2、多个文件 — 使用一个<input type="file" multiple />实现

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>File Upload</title>
</head>
<body>
<form method="post" enctype="multipart/form-data" action="http://localhost:8080/receive-data/receive/file-upload/2">
    <input type="text" name="my_text" autocomplete="false" />
    <input type="file" name="my_file" multiple />
    <input type="submit" value="提交" />
</form>
</body>
</html>
// 后端代码没有变化
  • “后端代码没有变化”的原因是:按照常规理解,每一个<input />中的内容最终在 HTTP 请求报文的报文主体中被boundary分隔,第三方库会根据boundary切分字节流。尽管多个文件因为multiple属性被写在了一个<input type="file"/>中,但是最终形成的 HTTP 请求报文中,一个<input />中的多个文件是照常被boundary分隔开的(只不过name相同罢了)。HTTP 请求报文:

Content-Type: multipart/form-data; boundary=----WebKitFormBoundarywQ0kklBQk2mrySAH


------WebKitFormBoundarywQ0kklBQk2mrySAH
Content-Disposition: form-data; name="my_text"

₩ネム¥メフ¦ᄑᅠ
------WebKitFormBoundarywQ0kklBQk2mrySAH
Content-Disposition: form-data; name="my_file"; filename="1.pdf"
Content-Type: application/pdf


------WebKitFormBoundarywQ0kklBQk2mrySAH
Content-Disposition: form-data; name="my_file"; filename="2.pdf"
Content-Type: application/pdf


------WebKitFormBoundarywQ0kklBQk2mrySAH--

2.3、多个文件 — 使用多个<input type="file" />实现

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>File Upload</title>
</head>
<body>
<form method="post" enctype="multipart/form-data" action="http://localhost:8080/receive-data/receive/file-upload/2">
    <input type="text" name="my_text" autocomplete="false" />
    <input type="file" name="my_file1" />
    <input type="file" name="my_file2" />
    <input type="submit" value="提交" />
</form>
</body>
</html>
// 后端代码没有变化

3、jQuery Ajax 提交

3.1、<input type="file" />

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>File Upload</title>
</head>
<body>
<form enctype="multipart/form-data">
    <input type="text" name="my_text" id="my_text" autocomplete="false" />
    <br />
    <br />
    <input type="file" name="my_file1" id="my_file1" />
    <br />
    <br />
    <input type="file" name="my_file2" id="my_file2" />
    <br />
    <br />
    <input type="button" id="my_btn" value="提交" />
</form>

<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
<script>
    $("#my_btn").on('click', function() {

        let formData = new FormData();

        formData.append("myText", $("#my_text").val());
        formData.append("myFile1", $("#my_file1")[0].files[0]);
        formData.append("myFile2", $("#my_file2")[0].files[0]);

        $.ajax({
            url: 'http://localhost:8080/receive-data/receive/file-upload/3',
            type: 'POST',
            contentType: false,
            processData: false,
            data: formData,

            success: function(data, status, xhr) {
                console.log(status);
            },

            error: function(xhr, status, error) {}
        });
    });
</script>
</body>
</html>
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 org.apache.commons.io.IOUtils;

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.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;

@WebServlet(name = "FileUploadServlet3", urlPatterns = "/receive/file-upload/3")
public class FileUploadServlet3 extends HttpServlet {

    private static final String CHARSET_ENCODING = "UTF-8";

    private static final long UPLOAD_FILE_MAX_BYTES = 5 * 1024 * 1024;

    private static final String UPLOAD_FILE_TARGET_PATH = "E:\\";

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding(CHARSET_ENCODING);
        response.setCharacterEncoding(CHARSET_ENCODING);

        try {
            // 1. Create a factory for disk-based file items
            DiskFileItemFactory factory = new DiskFileItemFactory();

            // 2. Create a new file upload handler
            ServletFileUpload uploadHandler = new ServletFileUpload(factory);

            // 3. Set constraints (约束)

            // 文件名编码
            uploadHandler.setHeaderEncoding(CHARSET_ENCODING);
            // 文件最大不超过 5MB
            // 单位是字节
            uploadHandler.setFileSizeMax(UPLOAD_FILE_MAX_BYTES);

            // 4. Parse the request, get a item list parsed from the form
            List<FileItem> formItemList = uploadHandler.parseRequest(request);

            // 5. Process
            for (FileItem item : formItemList) {
                if (item.isFormField()) {
                    // item.isFormField() == false
                    // item is not a file
                    String fieldName = item.getFieldName();
                    String value = item.getString(CHARSET_ENCODING);
                    System.out.println(fieldName + "=" + value);
                } else {

                    // item.isFormField() == true
                    // item is a file
                    String fieldName = item.getFieldName();
                    String fileName = item.getName();
                    System.out.println(fieldName + "=" + fileName);

                    String newFileName = UUID.randomUUID().toString().replaceAll("-", "") + fileName.substring(fileName.lastIndexOf("."));
                    InputStream in = item.getInputStream();
                    FileOutputStream fos = new FileOutputStream(UPLOAD_FILE_TARGET_PATH + newFileName);
                    IOUtils.copy(in, fos);
                    if (fos != null) {
                        fos.close();
                    }
                    if (in != null) {
                        in.close();
                    }
                }
            }
        } catch (FileUploadException e) {
            e.printStackTrace();
        }
    }

}

3.1、<input type="file" multiple />

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>File Upload</title>
</head>
<body>
<form enctype="multipart/form-data">
    <input type="text" name="my_text" id="my_text" autocomplete="false" />
    <br />
    <br />
    <input type="file" name="my_file" id="my_file" multiple />
    <br />
    <br />
    <input type="button" id="my_btn" value="提交" />
</form>

<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
<script>
    $("#my_btn").on('click', function() {

        let formData = new FormData();

        formData.append("myText", $("#my_text").val());

        let fileArr = $("#my_file")[0].files;
        for (let i = 0; i < fileArr.length; i++) {
            formData.append("myFile", fileArr[i]);
        }

        $.ajax({
            url: 'http://localhost:8080/receive-data/receive/file-upload/3',
            type: 'POST',
            contentType: false,
            processData: false,
            data: formData,

            success: function(data, status, xhr) {
                console.log(status);
            },

            error: function(xhr, status, error) {}
        });
    });
</script>
</body>
</html>
// 后端代码不用变
  • 需要注意的是,FormDataappend方法,FormData虽然像 Java 中的 Map,但是FormData中允许存在重复的“键”,所以当使用append方法时,“键”相同也不存在被覆盖的问题。
    当然,具体使用上是否允许“重复”存在,取决于开发约定。

相关文章

网友评论

      本文标题:92、【JavaEE】【Servlet 与 JSP】文件上传

      本文链接:https://www.haomeiwen.com/subject/byqtoltx.html