文件上传下载

文章目录

文件上传下载

HTTP请求会包含一个请求头,其中"Content-Type"字段告诉服务器正在发送什么类型的数据。根据发送的数据类型,浏览器和服务器会采取适应的处理方式。

"multipart/form-data"是一种常见的POST数据提交的方式。当表单中使用文件上传字段时,经常需要使用这个值。表单以multipart/form-data方式发送的数据必须以一种特殊编码方式进行编码,使得多个部分可以作为一个整体发送。这种情况常出现在同时发送文件和其他表单数据时。

表单类型有三种常见的MIME类型:

  • "application/x-www-form-urlencoded",这是默认类型,适合发送简单的文本数据。
  • "multipart/form-data",适合发送包含所有类型的数据,包括文件数据。
  • "text/plain",虽不常用,但有其特殊用途,用于发送未经编码的文本数据。

文件上传

在HTML表单中,如果要提交的数据包含文件类型(如:图片,文档等),"enctype"属性需要被设置为"multipart/form-data"。

1)导入依赖:

xml 复制代码
<dependency>
    <groupId>com.liferay</groupId>
    <artifactId>org.apache.commons.fileupload</artifactId>
    <version>1.2.2.LIFERAY-PATCHED-1</version>
</dependency>

2)前端界面:

html 复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>demo</title>
        <style type="text/css">
            input[type="submit"] {
                outline: none;
                border-radius: 5px;
                cursor: pointer;
                background-color: #31B0D5;
                border: none;
                width: 70px;
                height: 35px;
                font-size: 20px;
            }

            img {
                border-radius: 50%;
            }

            form {
                position: relative;
                width: 200px;
                height: 200px;
            }

            input[type="file"] {
                position: absolute;
                left: 0;
                top: 0;
                height: 200px;
                opacity: 0;
                cursor: pointer;
            }
        </style>
        <script type="text/javascript">
            function prev(event) {
                //获取展示图片的区域
                var img = document.getElementById("prevView");

                //获取文件对象
                let file = event.files[0];

                //获取文件阅读器
                let reader = new FileReader();
                reader.readAsDataURL(file);

                reader.onload = function () {
                    //给 img 的 src 设置图片 url
                    img.setAttribute("src", this.result);
                }
            }
        </script>
    </head>
    <body>
        <!-- 表单的 enctype 属性要设置为 multipart/form-data -->
        <form action="/zzz" enctype="multipart/form-data" method="post">
            家居图: <img alt="" height="200" id="prevView" width="200">
            <input id="" name="pic" onchange="prev(this)" type="file"/>
            家居名: <input name="name" type="text"><br/>
            <input type="submit" value="上传"/>
        </form>
    </body>
</html>

3)后端接收并保存:

java 复制代码
package com.lhs;

import org.apache.commons.fileupload.FileItem;
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.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.UUID;

public class myServlet02 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws Exception {
        // 检查请求的enctype标头是否为multipart/form-data,这意味着请求包含上载的文件
        if (ServletFileUpload.isMultipartContent(req)) {

            // 创建一个新的文件项工厂和文件上传对象
            DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
            ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory);

            // 设置请求头的字符编码为UTF-8,解决中文乱码问题
            servletFileUpload.setHeaderEncoding("utf-8");

            try {
                // 解析请求,将每个表单字段和文件作为单独的项目
                List<FileItem> list = servletFileUpload.parseRequest(req);
                System.out.println(list);

                // 迭代这些项目
                for (FileItem fileItem : list) {

                    // 查看项目是否是一个表单字段还是一个文件 
                    if (!fileItem.isFormField()) {

                        // 定义要上传文件的路径
                        String filePath = "/upload/";
                        // 计算出文件应该被保存的绝对路径
                        String realPath = req.getServletContext().getRealPath(filePath);
                        System.out.println(realPath);

                        // 如果文件路径不存在,那么就创建文件路径
                        if (!Files.isDirectory(Path.of(realPath))) {
                            Files.createDirectory(Path.of(realPath));
                        }

                        // 获取文件的原名
                        String name = fileItem.getName();
                        // 指定文件的新名字,然后写入磁盘
                        fileItem.write(new File(realPath + "/" + UUID.randomUUID() + "_" + name));

                        // 设置响应类型和编码,然后将成功消息写入响应
                        resp.setContentType("text/html;charset=utf-8");
                        resp.getWriter().write("上传成功");
                    }
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        } else {
            System.out.println("不是表单");
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

4)文件按日期分组存储:

java 复制代码
//获取当前本地日期
LocalDate localDate = LocalDate.now();

//从日期中获取年份
int year = localDate.getYear();

//从日期中获取月份
int month = localDate.getMonth().getValue();

//从日期中获得日期
int day = localDate.getDayOfMonth();

//通过年、月、日构造文件路径字符串
String filePath = "/upload/" + year + "/" + month + "/" + day + "/";

//获取此文件路径的真实路径
String realPath = req.getServletContext().getRealPath(filePath);


if (!Files.isDirectory(Path.of(realPath))) {
    //创建该路径下的所有目录
    Files.createDirectories(Path.of(realPath));
}

文件下载

在Http响应中,当Content-Disposition的值设置为"attachment",那么浏览器通常会尝试下载并保存的响应数据,而不是直接在浏览器中显示它。

1)前端界面:

html 复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>demo</title>
    </head>
    <body>
        <h1>文件下载</h1>
        <a href="/zzz?name=1.png">点击下载图片1</a><br/><br>
        <a href="/zzz?name=2.png">点击下载图片2</a><br/><br>
    </body>
</html>

2)将资源存放在web/download目录下

3)后端返回资源:

java 复制代码
package com.lhs;

import org.apache.commons.io.IOUtils;


import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;


public class myServlet02 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws Exception {
        // 设置请求编码格式为utf-8
        req.setCharacterEncoding("utf-8");

        // 获取下载资源名
        String name = req.getParameter("name");
        
        // 构建文件的完整路径
        String fullPath = "/download/" + name;

        ServletContext servletContext = req.getServletContext();

        // 获取文件的MIME类型
        String mimeType = servletContext.getMimeType(fullPath);

        // 设置响应的内容类型
        resp.setContentType(mimeType);

        // 设置响应头,使得浏览器接收到这个响应后,会下载文件,而不是直接打开
        // filename参数指定下载后的文件名,这里需要进行URL编码,以防文件名有特殊字符
        resp.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(name));

        // 获取要下载的文件的输入流
        InputStream resourceAsStream = servletContext.getResourceAsStream(fullPath);

        // 获取响应的输出流
        ServletOutputStream outputStream = resp.getOutputStream();

        // 使用Apache的IOUtils工具类,把文件的输入流复制到响应输出流,实现文件下载
        IOUtils.copy(resourceAsStream, outputStream);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
相关推荐
ajsbxi4 分钟前
苍穹外卖学习记录
java·笔记·后端·学习·nginx·spring·servlet
&岁月不待人&19 分钟前
Kotlin by lazy和lateinit的使用及区别
android·开发语言·kotlin
StayInLove23 分钟前
G1垃圾回收器日志详解
java·开发语言
对许27 分钟前
SLF4J: Failed to load class “org.slf4j.impl.StaticLoggerBinder“
java·log4j
无尽的大道31 分钟前
Java字符串深度解析:String的实现、常量池与性能优化
java·开发语言·性能优化
爱吃生蚝的于勒34 分钟前
深入学习指针(5)!!!!!!!!!!!!!!!
c语言·开发语言·数据结构·学习·计算机网络·算法
小鑫记得努力40 分钟前
Java类和对象(下篇)
java
binishuaio44 分钟前
Java 第11天 (git版本控制器基础用法)
java·开发语言·git
zz.YE1 小时前
【Java SE】StringBuffer
java·开发语言
老友@1 小时前
aspose如何获取PPT放映页“切换”的“持续时间”值
java·powerpoint·aspose