JavaWeb 文件上传和下载

news2025/1/29 14:04:29

目录

一、文件上传

        1.文件上传和下载的使用说明 : 

        2.文件上传基本原理 : 

        3.文件上传经典案例 : 

            3.1 页面实现: 

            3.2 servlet实现 : 

            3.3 工具类实现 : 

            3.4 运行测试 : 

            3.5 注意事项 : 

二、文件下载

        1.文件下载基本原理 : 

        2.文件下载经典案例 : 

            2.1 准备工作

            2.2 页面实现 

            2.3 servlet实现

            2.4 运行测试 

            2.5 注意事项


一、文件上传

        1.文件上传和下载的使用说明 : 

        web文件上传和下载需要用到三个jar包(fileupload2版本, tomcat10),如下图所示 : 

        2.文件上传基本原理 : 

        客户端——

        (1) 使用表单提交数据

        (2) 表单属性action仍然指向目标web资源(数据提交给该web资源)

        (3) 表单属性method指定为post

        (4) 表单属性enctype,指encodetype,编码类型;默认为application/x-www-form-urlencoded,即url编码,这种编码不适合二进制文件数据的提交,一般是适用于文本数据。若想进行二进制文件的提交,需要指定enctype为multipart/form-data,表示表单提交的数据是由多个部分组成,也就是可以提交二进制数据和文本数据。

        服务端——

        (1) 判断是否为一个文件表单;

        (2) 判断文件表单所提交的各个表单项分别是什么类型;

        (3) 如果是一个普通文本表单项,就按照文本的方式来处理;如果是一个文件表单项(二进制数据) ,就使用IO技术进行处理

        (4) 把表单提交的文件数据,保存到指定的服务端的某个目录。

        3.文件上传经典案例 : 

            3.1 页面实现: 

                页面效果如下 : 

                upload.jsp代码如下 : 

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <base href="<%=request.getContextPath()+"/"%>>">
    <style type="text/css">
        table, td {
            border:2px pink dashed;
            border-collapse: collapse;
            padding: 5px
        }

        img {
            border-radius: 50%;
        }

        input[type="file"] {
            position: absolute;
            left: 0;
            top: 0;
            height: 200px;
            opacity: 0;
            cursor: pointer
        }
        input[type="submit"] {
            width: 150px
        }
        #td01 {
            width: 100px;
            text-align: center
        }
    </style>

    <script type="text/javascript">
        function prev(event) {
            //获取展示图片的区域
            var img = document.getElementById("prevView");
            //获取文件对象
            var file = event.files[0];
            //获取文件阅读器(JS的一个类FileReader)
            var reader = new FileReader();
            reader.readAsDataURL(file);
            reader.onload = function () {
                //给img的src设置图片url
                img.setAttribute("src", this.result);
            }
        }
    </script>

</head>
<body>
<!--
    form表单属性的注意事项 :
    (1) action : 注意此页面中base标签的指定
    (2) enctype="multipart/form-data", 表示提交的数据是多个部分构造,有文件和文本
 -->
<form action="fileUploadServlet" method="post" enctype="multipart/form-data">
    <table width="350px">
        <tr>
            <td>上传的图片:</td>
            <td><img src="2.jpg" alt="" width="200" height="200" id="prevView">
                <input type="file" name="pic" id="" value="" onchange="prev(this)"/>
            </td>
        </tr>
        <tr>
            <td>文件名(self-def):</td>
            <td><input type="text" name="name"><br/></td>
        </tr>
        <tr>
            <td colspan="2" id="td01"><input type="submit" value="Submit"/></td>
        </tr>
    </table>
</form>
</body>
</html>

            3.2 servlet实现 : 

                定义一个servlet来实现文件上传的功能,需要用到导入的jar包的工具类。FileUploadServlet类代码如下 : 

package servlet;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload2.core.DiskFileItem;
import org.apache.commons.fileupload2.core.DiskFileItemFactory;
import org.apache.commons.fileupload2.jakarta.JakartaServletFileUpload;
import utils.WebUtils;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.UUID;

/**
 * @author : Cyan_RA9
 * @version : 21.0
 */
@WebServlet(urlPatterns = {"/fileUploadServlet"})
public class FileUploadServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
        //1.判断是否为一个文件表单
        if (JakartaServletFileUpload.isMultipartContent(req)) {
            //2.创建一个DiskFileItemFactory对象(注意创建方式同低版本不同)
            DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory.Builder().get();

            //3.利用得到的diskFileItemFactory对象,创建一个解析上传数据的工具对象
            JakartaServletFileUpload<DiskFileItem, DiskFileItemFactory> jakartaServletFileUpload =
                    new JakartaServletFileUpload<>(diskFileItemFactory);
            jakartaServletFileUpload.setHeaderCharset(StandardCharsets.UTF_8);  //乱码问题

            //4.利用工具对象,将表单提交的数据(text or file) 封装到DiskFileItem中
            try {
                List<DiskFileItem> diskFileItems = jakartaServletFileUpload.parseRequest(req);

                //5.遍历获取到的集合
                for (DiskFileItem diskFileItem : diskFileItems) {
                    //6.判断是否为文件类型(true表示不是文件,是input type=text)
                    if (diskFileItem.isFormField()) {
                        String name = diskFileItem.getString(StandardCharsets.UTF_8);
                        System.out.println("文件名(self-def) = " + name);
                    } else {    //false表示是文件
                        //7.如果判断为是文件,就将上传的文件保存到本地。
                        String filePath = "/upload/";
                            //通过ServletContext对象,得到真实的工作路径
                        String realPath = req.getServletContext().getRealPath(filePath);
                        System.out.println("realPath = " + realPath);

                        String fileName = diskFileItem.getName();
                        System.out.println("fileName = " + fileName);

                        //8.由于实际工作的路径与web路径不同,所以需要创建目录
                            //利用定义的工具类,创建分级目录,提高程序执行的效率。
                        String finalPath = realPath + WebUtils.getLocalDate();
                        File file = new File(finalPath);
                        if (!file.exists()) {
                            file.mkdirs();
                        }

                        //9.将上传的文件拷贝到服务端的指定目录
                            /*
                                (1) 注意得到Path的两种方式
                                (2) 解决文件重名问题,给文件名加一个前缀,保证是唯一即可。
                             */
                        fileName = UUID.randomUUID().toString() + "_" + fileName;
                        diskFileItem.write(new File(finalPath + fileName).toPath());
                    }
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        } else {
            System.out.println("不是一个表单捏~");
        }
    }

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

            3.3 工具类实现 : 

                定义一个工具类,用来对文件名作标识,以解决文件重名导致的文件覆盖问题。
                WebUtils类代码如下 : 

package utils;

import java.time.LocalDateTime;

/**
    @function : 该方法返回一个日期形式的字符串路径
 */
public class WebUtils {
    public static String getLocalDate() {
        LocalDateTime ldt = LocalDateTime.now();
        int year = ldt.getYear();
        int month = ldt.getMonthValue();   //获取月份的值
        int dayOfMonth = ldt.getDayOfMonth();
        String localDate = year + "/" + month + "/" + dayOfMonth + "/";

        return localDate;
    }
}

            3.4 运行测试 : 

                测试结果如下GIF : 

            3.5 注意事项 : 

        (1) 同一个目录下上传了很多文件时,会造成访问文件速度变慢的问题,因此可以将文件上传到不同的目录,例如按照上传日期进行分类, eg : 2023/9/2/。

        (2) 一次完美的文件上传需要考虑很多因素,eg : 断点续传,对图片大小和尺寸的限制,分片上传,防止恶意上传等。PS : 在项目中,可以考虑百度开发的WebUploader组件。

        (3) 文件上传功能在项目中应该有限制的使用,一般用在头像、证明、合同、产品展示等;如果不加限制,会造成服务器空间被大量占用(eg : 微信朋友圈最多一次发9张)。

        (4) Tomcat在启动时,不会为web目录下的空文件夹在out目录下创建对应的文件夹,所以,需要在空文件夹中事先放入一个文件。


二、文件下载

        1.文件下载基本原理 : 

        服务器端要设置两个重要的HTTP响应头——

        (1) Content-Disposition : 表示下载数据的展示方式,比如是内联形式(即网页形式或者网页的一部分),或者是文件下载方式(attachment)。
        (2) Content-Type : 指定返回数据的MIME类型。        

        而响应体,在网络传输时是图片的原生数据(即按照浏览器下载的编码),而下载后查看到的是浏览器本身解析后的文件

        2.文件下载经典案例 : 

            2.1 准备工作

                将要下载的文件拷贝到web目录的sources目录下,如下图所示 : 

            2.2 页面实现 

                页面效果如下 : 

                download.jsp代码如下 : 

<%--
    User : Cyan_RA9
    Version : 21.0
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <meta charset="UTF-8"/>
    <title>Title</title>
    <base href="<%= request.getContextPath() + "/"%>"/>
</head>
<body>
<h1>文件下载</h1>
<a href="fileDownloadServlet?name=miku_flowers.jpg">点我下载初音未来</a> <br/><br/>
<a href="fileDownloadServlet?name=3.txt">点我下载王勃的滕王阁诗</a>
</body>
</html>

            2.3 servlet实现

                定义一个servlet,完成文件下载的功能。
                FileDownloadServlet代码如下 : 

package servlet;

import jakarta.servlet.ServletException;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;

import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;

/**
 * @author : Cyan_RA9
 * @version : 21.0
 */
@WebServlet(urlPatterns={"/fileDownloadServlet"})
public class FileDownloadServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.得到文件名和文件路径(文件资源的路径!)
        req.setCharacterEncoding("utf-8");
        String fileName = req.getParameter("name");
        String filePath = "/sources/" + fileName;

        //2.通过ServletContext对象得到文件的MIME类型
        String mimeType = req.getServletContext().getMimeType(filePath);
        System.out.println("mimeType = " + mimeType);

        //3.设置第一个响应头Content-Type
        resp.setContentType(mimeType);

        //4.设置第一个响应头Content-Disposition
            //Content-Disposition用于指定下载的数据的展示形式,其中attachment表示使用文件下载方式
            //不同浏览器需要的编码格式不同
        if (req.getHeader("User-Agent").contains("Chrome")) {
            resp.setHeader("Content-Disposition", "attachment; filename=" +
                    URLEncoder.encode(fileName, "UTF-8"));
        } else {
            //其他浏览器的编码操作
        }

        //5.读取文件,将读取到的文件返回给客户端(IO流拷贝的封装)
            //获取与数据源文件相关联的字节输入流
        InputStream resourceAsStream = req.getServletContext().getResourceAsStream(filePath);
            //获取与目的地文件相关联的字节输出流
        ServletOutputStream outputStream = resp.getOutputStream();
            //利用封装好的工具类,进行IO流拷贝
        IOUtils.copy(resourceAsStream, outputStream);
    }

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

            2.4 运行测试 

                运行效果如下图所示(GIF图)

            2.5 注意事项

        (1) 不同的浏览器,对于下载的文件的处理方式不同,有些是直接打开该文件,有些则是将文件下载到本地的指定下载目录。

        (2) 对于网站上的文件,很多文件可以使用“另存为”来下载;对于大文件(文档,视频等),往往使用专业的下载工具(eg : 迅雷,百度网盘等)。

        (3) 注意,不同的浏览器对文件解码格式的需求不同。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/965170.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2022年03月 C/C++(六级)真题解析#中国电子学会#全国青少年软件编程等级考试

C/C++编程(1~8级)全部真题・点这里 第1题:多项式相加 我们经常遇到两多项式相加的情况, 在这里, 我们就需要用程序来模拟实现把两个多项式相加到一起。 首先, 我们会有两个多项式,每个多项式是独立的一行, 每个多项式由系数、 幂数这样的多个整数对来表示。 如多项式 2…

专业的视觉特效处理包,FxFactory 8 Pro for Mac助您打造精彩视频

FxFactory 8 Pro for Mac是一款强大的视觉特效处理包&#xff0c;专门为Mac用户设计。它集成了超过200种高质量的视觉效果和过渡效果&#xff0c;可以轻松地应用于各种视频项目中。该软件提供了一个直观的界面&#xff0c;用户可以通过简单拖放操作将特效应用到视频片段上。它支…

【golang】调度系列之goroutine

前面的两篇&#xff0c;从相对比较简单的锁的内容入手(也是干货满满)&#xff0c;开始了go的系列。这篇开始&#xff0c;进入更核心的内容。我们知道&#xff0c;go应该是第一门在语言层面支持协程的编程语言(可能是我孤陋寡闻)&#xff0c;goroutine也完全算的上是go的门面。g…

[SpringBoot3]博客管理系统(源码放评论区了)

八、博客管理系统 创建新的SpringBoot项目&#xff0c;综合运用以上知识点&#xff0c;做一个文章管理的后台应用。依赖&#xff1a; Spring WebLombokThymeleafMyBatis FrameworkMySQL DriverBean Validationhutool 需求&#xff1a;文章管理工作&#xff0c;发布新文章&…

Web安全——穷举爆破上篇(仅供学习)

Web安全 一、概述二、常见的服务1、burpsuite 穷举后台密码2、burpsuite 对 webshell 穷举破解密码3、有 token 防御的网站后台穷举破解密码3.1 burpsuite 设置宏获取 token 对网站后台密码破解3.2 编写脚本获取token 对网站后台密码破解 4、针对有验证码后台的穷举方法4.1 coo…

华为云云服务器评测 [Vue3 博物馆管理系统] 使用Vue3、Element-plus菜单组件构建轮播图

系列文章目录 第一章 定制上中下&#xff08;顶部菜单、底部区域、中间主区域显示&#xff09;三层结构首页 第二章 使用Vue3、Element-plus菜单组件构建菜单 第三章 使用Vue3、Element-plus菜单组件构建轮播图 [第四章 使用Vue3、Element-plus菜单组件构建组图文章] 华为云云…

WebSocket(一)

一.什么是WebSocket 【1】WebSocket是一种协议&#xff0c;设计用于提供低延迟&#xff0c;全双工和长期运行的连接。 全双工&#xff1a;通信的两个参与方可以同时发送和接收数据&#xff0c;不需要等待对方的响应或传输完成。 【2】比较 传统通信&#xff08;http协议&am…

QML与C++的交互操作

QML旨在通过C 代码轻松扩展。Qt QML模块中的类使QML对象能够从C 加载和操作&#xff0c;QML引擎与Qt元对象系统集成的本质使得C 功能可以直接从QML调用。这允许开发混合应用程序&#xff0c;这些应用程序是通过混合使用QML&#xff0c;JavaScript和C 代码实现的。除了从QML访问…

15年检测生涯转瞬即逝,复旦MBA助力邢国芒实现质量强国梦

日月光华&#xff0c;旦复旦兮&#xff01;复旦MBA如同一个巨大的磁场&#xff0c;吸引了诸多来自五湖四海、各行各业的职场精英。从初入职场的青涩懵懂到如今的独当一面专业干练&#xff0c;他们逐渐成长为职场的中坚力量&#xff0c;在各自领域内发光发热。作为新时代的青年&…

多线程应用——阻塞队列

阻塞队列 文章目录 阻塞队列1.队列的概念2.阻塞队列3.现实中的例子4.消息队列5.使用队列的优势1.解耦2.削峰填谷3.异步操作 6.实现 1.队列的概念 一种先进先出的数据结构 2.阻塞队列 队列写元素是从队尾插入&#xff0c;从对头取出 当插入元素时&#xff0c;先判断一下队列…

数据治理-数据管理框架

DMBOK2提出的想法和概念在不同的组织中都可以应用&#xff0c;组织所采用的数据管理方法取决于某些关键要素&#xff0c;如其所处行业、所应用的数据范围、企业文化、成熟度、战略、愿景以及待解决的问题和挑战。 战略一致性模型和阿姆斯特丹模型&#xff0c;展示了组织管理数…

算法通关村第十二关——字符串反转问题解析

前言 字符串反转是关于字符串算法里的重要问题&#xff0c;虽然不是太难&#xff0c;但需要考虑到一些边界问题。本篇文章就对几道字符串反转题目进行分析。 1.反转字符串 力扣344题&#xff0c;编写一个函数&#xff0c;其作用是将输入的字符串反转过来。输入字符串以字符数…

opencv 提取选中区域内指定hsv颜色的水印

基于《QT 插件化图像算法研究平台》做的功能插件。提取选中区域内指定hsv颜色的水印。 《QT 插件化图像算法研究平台》有个HSV COLOR PICK功能&#xff0c;可以很直观、方便地分析出水印 的hsv颜色&#xff0c;比如, 蓝色&#xff1a;100,180,0,255,100,255。 然后利用 opencv …

JavaScript中关于数组的小挑战

史蒂芬仍在建立他的小费计算器&#xff0c;使用的规则与以前一样&#xff1a; 如果账单价值在50到300之间&#xff0c;小费为账单的15%&#xff0c;如果价值不同&#xff0c;小费为20%。 编写一个函数’calcTip’&#xff0c;将任何账单值作为输入&#xff0c;并返回相应的小费…

【业务功能篇94】微服务-springcloud-springboot-认证服务-注册功能-第三方短信验证API

商城认证服务 一、搭建认证服务环境 结合我们前面介绍的商城的架构我们需要单独的搭建一个认证服务。 1.创建项目 首先创建一个SpringBoot项目&#xff0c;然后添加对应的依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"htt…

MySQL主从复制与读写分离 及其实例

目录 主从复制与读写分离 1、MySQL主从复制原理 1.1、MySQL的复制类型 1.2、MySQL主从复制的工作过程 1.3、mysq支持的复制类型 1.4、 数据流向 1.5、主从复制的工作过程 2、读写分离 2.1、什么是读写分离&#xff1f; 2.2、为什么要读写分离呢&#xff1f; 2.3、什么…

HFSS 3维曲线导入

HFSS 3维曲线导入 简介环境参考代码使用结果 简介 如图一所示&#xff0c;CST中可以通过导入和到出由任意点组成的曲线&#xff0c;但是HFSS中貌似不能导入&#xff08;如图二所示&#xff09;&#xff0c;如果我们要将matlab的产生的曲线的点的数据导入特变麻烦&#xff0c;特…

21.4 CSS 盒子模型

1. 边框样式 border-style属性: 指定元素的边框样式.常用属性值: - none: 无边框(默认值). - solid: 实线边框. - dotted: 点状边框. - dashed: 虚线边框. - double: 双线边框. - groove: 凹槽状边框. - ridge: 脊状边框. - inset: 内阴影边框. - outset: 外阴影边框.这些值可…

Loki日志系统

1、Loki是什么&#xff1f; Loki是一个开源的日志聚合系统&#xff0c;由Grafana Labs开发和维护。它旨在帮助用户收集、存储和查询大规模的日志数据&#xff0c;帮助用户更好地理解和监控他们的应用程序和系统。 Loki的设计灵感来自于Prometheus&#xff0c;它采用了类似的标…

【ROS 03】ROS通信机制进阶

上一章内容&#xff0c;主要介绍了ROS通信的实现&#xff0c;内容偏向于粗粒度的通信框架的讲解&#xff0c;没有详细介绍涉及的API&#xff0c;也没有封装代码&#xff0c;鉴于此&#xff0c;本章主要内容如下: ROS常用API介绍&#xff1b;ROS中自定义头文件与源文件的使用。…