• 12、JavaWeb启程——Servlet3.0文件上传与下载


    1、项目准备

    • 新建一个web项目,添加对应的jar包

    2、编写register.jsp

    • method:需要使用post请求,get请求限制了数据的大小
    • enctype使用multipart/form-data,不然直接报错(需要二进制数据)。
    • 提供文件上传的控件。
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
    	<title>注册</title>
    </head>
    <body>
    	<form action="/fileUpload"method="post"enctype="multipart/form-data">
    		<p>账号:<input type="text" name="username"/></p>
    		<p>头像:<input type="file" name="headImg"/></p>
    		<input type="submit" value="注册">
    	</form>
    </body>
    </html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    【结果预览】:
    在这里插入图片描述

    3、Servlet3.0文件上传

    1、API

    返回值方法作用
    PartgetPart(String name)用于获取请求中指定name文件
    CollectiongetParts()获取请求中的全部文件

    2、Part中的常用方法

    返回值方法作用
    voidwrite(String fileName)直接把接收到的文件保存到磁盘中
    voidgetContentType()获取文件的类型 MIME
    StringgetHeader(String name)获取请求头信息
    longgetSize()获取文件的大小

    3、基本使用代码示例

    package cn.simplelife.work._01fileupload;
    
    import javax.servlet.ServletException;
    import javax.servlet.ServletInputStream;
    import javax.servlet.annotation.MultipartConfig;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.*;
    import java.io.IOException;
    import java.util.Collection;
    import java.util.Scanner;
    import java.util.UUID;
    
    /**
     * @ClassName FileUploadServlet
     * @Description
     * @Author simplelife
     * @Date 2022/10/28 10:53
     * @Version 1.0
     */
    @MultipartConfig(maxFileSize = 1024 * 500, maxRequestSize = 1024 * 500)
    @WebServlet(value = "/register")
    public class FileUploadServlet extends HttpServlet {
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // 1、上传文件的基本使用
            req.setCharacterEncoding("utf-8");
            String username = req.getParameter("username");
            // 获取文件
            Part headImg = req.getPart("headImg");
            // 获取文件提交时的名称
            String submittedFileName = headImg.getSubmittedFileName();
            // 将文件写入到指定的目录下的文件中
            headImg.write("F:\\JavaWeb\\javaweb\\day18\\web\\upload\\" + submittedFileName);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    4、获取上传的文件名称

    返回值方法作用
    StringgetHeader(“contentdisposition”)Tocmat 8.0 之前使用通过请求头获取文件名,需截取字符串
    StringgetSubmittedFileName()Tomcat8.0 之后提供的直接获取文件名方式

    5、文件名相同覆盖现有文件名称解决

    【问题概述】: 若上传得文件名相同会导致覆盖服务器之前已上传的的文件。

    【解决方案】: 使用唯一的文件名称作为上传后的文件名称。我们使用UUID来做。

    【代码演示】:

    package cn.simplelife.work._01fileupload;
    
    import javax.servlet.ServletException;
    import javax.servlet.ServletInputStream;
    import javax.servlet.annotation.MultipartConfig;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.*;
    import java.io.IOException;
    import java.util.Collection;
    import java.util.Scanner;
    import java.util.UUID;
    
    /**
     * @ClassName FileUploadServlet
     * @Description
     * @Author simplelife
     * @Date 2022/10/28 10:53
     * @Version 1.0
     */
    @MultipartConfig(maxFileSize = 1024 * 500, maxRequestSize = 1024 * 500)
    @WebServlet(value = "/register")
    public class FileUploadServlet extends HttpServlet {
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // 2、生成唯一的文件名称----->防止用户上传相同的文件名称覆盖掉之前的文件信息
            req.setCharacterEncoding("utf-8");
            String username = req.getParameter("username");
            // 获取文件
            Part headImg = req.getPart("headImg");
            // 获取提交时的文件名称
            String submittedFileName = headImg.getSubmittedFileName();
            // 生成唯一的文件名称
            String filenamePre = UUID.randomUUID().toString();
            // 获取文件的拓展名称
            String substring = submittedFileName.substring(submittedFileName.lastIndexOf("."));
            // 保存文件名称
            String realName = filenamePre + substring;
            // 保存文件到磁盘
            headImg.write("F:\\JavaWeb\\javaweb\\day18\\web\\upload\\" + realName);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    6、文件保存位置问题解决

    【问题概述】: 文件在磁盘某个位置,不在项目下,无法使用 HTTP 协议访问,所以要把用户上传的文件存放到项目中才可通过 HTTP 协议来访问,且保存的位置路径不可以写绝对路径。

    【解决方法】: 可以通过ServletContext 对象的 getRealPath(“项目中保存上传文件的文件夹的相对路径”) 来获取其的绝对路径。

    【代码演示】:

    package cn.simplelife.work._01fileupload;
    
    import javax.servlet.ServletException;
    import javax.servlet.ServletInputStream;
    import javax.servlet.annotation.MultipartConfig;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.*;
    import java.io.IOException;
    import java.util.Collection;
    import java.util.Scanner;
    import java.util.UUID;
    
    /**
     * @ClassName FileUploadServlet
     * @Description
     * @Author simplelife
     * @Date 2022/10/28 10:53
     * @Version 1.0
     */
    @MultipartConfig(maxFileSize = 1024 * 500, maxRequestSize = 1024 * 500)
    @WebServlet(value = "/register")
    public class FileUploadServlet extends HttpServlet {
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    		 // 3、文件保存位置的问题
            req.setCharacterEncoding("utf-8");
            String username = req.getParameter("username");
            // 获取文件
            Part headImg = req.getPart("headImg");
            // 获取文件提交时的文件名称
            String submittedFileName = headImg.getSubmittedFileName();
            // 生成唯一的文件名称
            String realName = UUID.randomUUID().toString() + submittedFileName.substring(submittedFileName.lastIndexOf("."));
            // 自动获取项目路径的根路径,然后拼接上给的路径
            String baseDir = req.getServletContext().getRealPath("/upload/");
            // 将上传的文件写入文件
            headImg.write(baseDir + realName);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    7、文件上传类型的限制

    【问题概述】: 限制用户恶意上传文件,比如要让用户上传头像,而用户却上传一个非图片文件,比如 JSP 文件。

    【解决方案】: 判断用户上传的文件的类型是否符合需要的文件类型。

    【代码演示】:

    package cn.simplelife.work._01fileupload;
    
    import javax.servlet.ServletException;
    import javax.servlet.ServletInputStream;
    import javax.servlet.annotation.MultipartConfig;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.*;
    import java.io.IOException;
    import java.util.Collection;
    import java.util.Scanner;
    import java.util.UUID;
    
    /**
     * @ClassName FileUploadServlet
     * @Description
     * @Author simplelife
     * @Date 2022/10/28 10:53
     * @Version 1.0
     */
    @MultipartConfig(maxFileSize = 1024 * 500, maxRequestSize = 1024 * 500)
    @WebServlet(value = "/register")
    public class FileUploadServlet extends HttpServlet {
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // 4、文件上传类型约束
            req.setCharacterEncoding("utf-8");
            String username = req.getParameter("username");
            // 获取文件
            Part headImg = req.getPart("headImg");
            // 判断文件的类型是否为图片类型,不是图片类型不上传
            if (headImg.getContentType().startsWith("image/")) {
            // 获取文件上传时的名称
            String submittedFileName = headImg.getSubmittedFileName();
            // 生成唯一的文件名称
            String realName = UUID.randomUUID().toString() + submittedFileName.substring(submittedFileName.lastIndexOf("."));
            // 自动获取文件的根路径
            String baseDir = getServletContext().getRealPath("/upload/");
            // 将上传的文件写入文件
            headImg.write(baseDir + realName);
            }
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    8、文件大小的约束

    【问题说明】: 文件上传限制大小可提高服务器硬盘的使用率,防止用户恶意上传文件造成服务器磁盘资源紧张。

    **【解决方案】:**可以通过设置 @MutipartConfig 的属性做限制

    • maxFileSize:单个上传文件大小限制,单位:bytes
    • maxRequestSize:显示请求中数据的大小,单位:bytes

    【代码演示】:

    package cn.simplelife.work._01fileupload;
    
    import javax.servlet.ServletException;
    import javax.servlet.ServletInputStream;
    import javax.servlet.annotation.MultipartConfig;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.*;
    import java.io.IOException;
    import java.util.Collection;
    import java.util.Scanner;
    import java.util.UUID;
    
    /**
     * @ClassName FileUploadServlet
     * @Description
     * @Author simplelife
     * @Date 2022/10/28 10:53
     * @Version 1.0
     */
    @MultipartConfig(maxFileSize = 1024 * 500, maxRequestSize = 1024 * 500)
    @WebServlet(value = "/register")
    public class FileUploadServlet extends HttpServlet {
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // 5、文件上传大小的限制
            req.setCharacterEncoding("utf-8");
            String username = req.getParameter("username");
            try {
                // 获取上传的文件 ---多个文件
                Collection<Part> parts = req.getParts();
                // 遍历多个文件
                for (Part part : parts) {
                    // 获取每一个文件的文件名称
                    String contentType = part.getContentType();
                    if (contentType != null && contentType.startsWith("image/")) {
                        // 获取每一个文件上传的文件名称
                        String submittedFileName = part.getSubmittedFileName();
                        // 生成唯一的文件名称
                        String realName = UUID.randomUUID().toString() + submittedFileName.substring(submittedFileName.lastIndexOf("."));
                        // 获取保存的根路径
                        String baseDir = req.getServletContext().getRealPath("/upload/");
                        // 写入文件
                        part.write(baseDir + realName);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
                req.setAttribute("error", "亲,文件太大了!");
                req.getRequestDispatcher("/register.jsp").forward(req, resp);
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    4、Servlet3.0文件下载

    1、文件下载的简单实现

    • 在web目录下提供下载的资源
    • 编写下载页面
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    <a href="${pageContext.request.contextPath}/download/cat.png"></a>
    <a href="${pageContext.request.contextPath}/download/cat.rar"></a>
    </body>
    </html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2、文件下载的限制

    【问题概述】: 下载功能已经实现,但是文件放在 WEB-INF 外面不安全,用户只需要拿到下载的超链接都能够下载,实际开发中,我们的文件通常需要用户有一定的权限才能下载。

    【解决方法】:

    • 将需要下载的文件存放到WEB-INF目录下,通过Servlet进行下载操作。

    【代码演示】:

    • 移动下载目录文件到WEB-INF目录下
    • 修改下载页面
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    <a href="${pageContext.request.contextPath}/download?fileName=cat.png"></a>
    <a href="${pageContext.request.contextPath}/download?fileName=cat.rar"></a>
    </body>
    </html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 编写servlet
    package cn.simplelife.work._02filedownload;
    
    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.IOException;
    import java.net.URLEncoder;
    import java.nio.charset.StandardCharsets;
    import java.nio.file.Files;
    import java.nio.file.Paths;
    
    /**
     * @ClassName FileDownLoad
     * @Description
     * @Author simplelife
     * @Date 2022/10/28 16:09
     * @Version 1.0
     */
    @WebServlet(value = "/download")
    public class FileDownLoad extends HttpServlet {
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //接收用户要下载的文件名称
            req.setCharacterEncoding("utf-8");
            String fileName = req.getParameter("fileName");
            //在响应之前做其他操作
            System.out.println("扣钱");
            //在项目下找到文件并响应给用户
            String realPath = req.getServletContext().getRealPath("/WEB-INF/download/");
            // 使用工具类 Files 的 copy 方法获取文件输入流,响应回浏览器
    		Files.copy(Paths.get(realPath, fileName), resp.getOutputStream());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    3、下载文件名称问题

    【问题概述】: Tomcat 服务器未告知浏览器文件的名称,所以需要手动设置响应头来告知浏览器文件名称。

    【代码演示】:

    package cn.simplelife.work._02filedownload;
    
    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.IOException;
    import java.net.URLEncoder;
    import java.nio.charset.StandardCharsets;
    import java.nio.file.Files;
    import java.nio.file.Paths;
    
    /**
     * @ClassName FileDownLoad
     * @Description
     * @Author simplelife
     * @Date 2022/10/28 16:09
     * @Version 1.0
     */
    @WebServlet(value = "/download")
    public class FileDownLoad extends HttpServlet {
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //接收用户要下载的文件名称
            req.setCharacterEncoding("utf-8");
            String fileName = req.getParameter("fileName");
            //在响应之前做其他操作
            System.out.println("扣钱");
            //在项目下找到文件并响应给用户
            String realPath = req.getServletContext().getRealPath("/WEB-INF/download/");
            // 获取浏览器类型
            String header = req.getHeader("User-Agent");
            // 根据浏览器类型设置文件下载的名称
            String name = header.contains("MSIE") ? URLEncoder.encode(fileName, StandardCharsets.UTF_8) : new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
            resp.setHeader("Content-Disposition", "attachment;filename=" + name);
            //复制文件
            //Paths.get(realPath, fileName) 获取到文件的真实路径
            //Files.copy(Path,输出流)
            Files.copy(Paths.get(realPath, fileName), resp.getOutputStream());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
  • 相关阅读:
    【leetcode】【剑指offer Ⅱ】028. 展平多级双向链表
    python的time各种用法
    使用Xshell远程访问工具连接到Linux
    部门来了个拿25k出来的00后测试卷王,老油条表示真干不过,已被...
    【机器学习周志华】读书笔记 P1 机器学习基本概念知识
    RabbitMQ的基本使用
    中国人造金刚石行业投资战略规划及发展前景预测报告2022~2028年
    使用Feign远程调用快速入门
    计算机毕业设计(附源码)python银行招聘系统设计
    深入浅出线程池
  • 原文地址:https://blog.csdn.net/m0_37911124/article/details/127715971