Spring MVC中实现一个文件上传和下载功能
说到文件上传和下载,相信每个开发者都有或多或少的接触过文件上传的功能吧,文件上传和下载是我们在学习计算机网络应用常见的一个功能,主要涉及到用户和服务器之间的数据传输。
我们来对文件上传和下载功能的进行相关概述吧!
文件上传
定义:文件上传是指用户将本地计算机上的文件通过网络传输到服务器的过程。用户通常通过网页表单选择文件并提交,服务器接收并存储该文件。
过程:
- 用户选择文件:用户在网页上选择要上传的文件,通常通过一个文件输入框(
<input type="file">)。 - 表单提交:用户点击提交按钮,浏览器将文件和其他表单数据一起发送到服务器。
- HTTP请求:浏览器发起一个HTTP POST请求,包含文件数据和其他表单字段。
- 服务器接收文件:
- 服务器接收到请求后,解析请求体中的文件数据。
- 服务器将文件存储在指定的目录中。
- 反馈结果:服务器处理完上传后,通常会返回一个响应,告知用户上传是否成功。
文件下载
定义:文件下载是指用户从服务器获取文件并保存到本地计算机的过程。用户通常通过点击链接或按钮来触发下载。
过程:
- 用户请求下载:用户在网页上点击下载链接或按钮,触发下载请求。
- HTTP请求:浏览器发起一个HTTP GET请求,请求特定的文件。
- 服务器处理请求:
- 服务器接收到请求后,查找请求的文件。
- 服务器将文件内容写入HTTP响应体,并设置适当的响应头(如Content-Disposition)以指示浏览器下载文件而不是直接显示。
- 浏览器接收文件:浏览器接收到响应后,开始下载文件并提示用户选择保存位置。
- 文件保存:用户选择保存位置后,文件被下载到本地计算机。
文件上传和下载的关键步骤
在文件上传和下载的过程中,涉及以下关键步骤:
- 用户界面:提供文件选择和下载的用户界面(HTML表单)。
- HTTP请求:使用适当的HTTP方法(POST用于上传,GET用于下载)发送请求。
- 请求处理:服务器端代码处理请求,解析文件数据(上传)或查找文件(下载)。
- 文件存储:在上传过程中,将文件存储在服务器的指定位置。
- 响应返回:服务器返回处理结果(上传成功/失败)或文件内容(下载)。
- 错误处理:处理可能出现的错误,如文件大小限制、文件类型验证、文件不存在等。
在SpringMVC中实现一个文件上传和下载的功能
第一步创建我们的文件项目目录结构:
src└── main├── java│ └── com│ └── example│ └── fileupload│ ├── FileUploadController.java│ └── WebConfig.java├── resources│ └── templates│ └── upload.html└── web.xml
第二步:添加相关依赖
<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.10</version></dependency><dependency><groupId>org.thymeleaf</groupId><artifactId>thymeleaf-spring5</artifactId><version>3.0.12.RELEASE</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version><scope>provided</scope></dependency>
</dependencies>
第三步,创建我们的Web配置类,用来监听相关信息
在WebConfig.java中配置Spring MVC:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {@Beanpublic ViewResolver viewResolver(SpringTemplateEngine templateEngine) {ThymeleafViewResolver resolver = new ThymeleafViewResolver();resolver.setTemplateEngine(templateEngine);resolver.setCharacterEncoding("UTF-8");resolver.setOrder(1);return resolver;}@Beanpublic CommonsMultipartResolver multipartResolver() {CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();multipartResolver.setMaxUploadSize(10485760); // 10MBreturn multipartResolver;}@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/uploads/**").addResourceLocations("file:uploads/");}
}
创建控制器
在FileUploadController.java中实现文件上传和下载的逻辑:
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;@Controller
public class FileUploadController {private final String uploadDir = "uploads/";@GetMapping("/")public String index() {return "upload";}@PostMapping("/upload")public String uploadFile(@RequestParam("file") MultipartFile file, RedirectAttributes redirectAttributes) {if (file.isEmpty()) {redirectAttributes.addFlashAttribute("message", "请选择一个文件上传!");return "redirect:/";}try {// 保存文件File dir = new File(uploadDir);if (!dir.exists()) {dir.mkdirs();}File uploadedFile = new File(uploadDir + file.getOriginalFilename());file.transferTo(uploadedFile);redirectAttributes.addFlashAttribute("message", "文件上传成功:" + file.getOriginalFilename());} catch (IOException e) {redirectAttributes.addFlashAttribute("message", "文件上传失败:" + e.getMessage());}return "redirect:/";}@GetMapping("/download")public void downloadFile(@RequestParam("filename") String filename, HttpServletResponse response) {File file = new File(uploadDir + filename);if (file.exists()) {response.setContentType("application/octet-stream");response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");try (FileInputStream in = new FileInputStream(file);OutputStream out = response.getOutputStream()) {byte[] buffer = new byte[1024];int bytesRead;while ((bytesRead = in.read(buffer)) != -1) {out.write(buffer, 0, bytesRead);}} catch (IOException e) {e.printStackTrace();}} else {response.setStatus(HttpServletResponse.SC_NOT_FOUND);}}
}
第五步,创建HTML模板
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head><title>文件上传</title>
</head>
<body>
<h1>文件上传</h1><form method="post" enctype="multipart/form-data" th:action="@{/upload}"><input type="file" name="file" required/><button type="submit">上传</button>
</form><div th:if="${message}" th:text="${message}"></div><h2>下载文件</h2>
<form method="get" th:action="@{/download}"><input type="text" name="filename" placeholder="输入文件名" required/><button type="submit">下载</button>
</form>
</body>
</html>
最后一步,配置web.xml文件
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"version="3.1"><servlet><servlet-name>dispatcher</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>dispatcher</servlet-name><url-pattern>/</url-pattern></servlet-mapping><context-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/applicationContext.xml</param-value></context-param><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener></web-app>

14:18:08.583 [http-nio-8008-exec-6] DEBUG org.springframework.web.servlet.DispatcherServlet - POST "/SpringMVC/upload", parameters={}
14:18:08.595 [http-nio-8008-exec-6] DEBUG org.springframework.web.multipart.commons.CommonsMultipartResolver - Part 'file', size 719635 bytes, filename='白底logo.png'
14:18:08.596 [http-nio-8008-exec-6] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped to com.miaow.controller.FileUploadController#uploadFile(MultipartFile, RedirectAttributes)
14:18:08.600 [http-nio-8008-exec-6] DEBUG org.springframework.web.multipart.commons.CommonsMultipartFile - Part 'file', filename '白底logo.png': moved to [D:\IDEATomcat\apache-tomcat-9.0.89-windows-x64\apache-tomcat-9.0.89\bin\uploads\白底logo.png]
14:18:08.600 [http-nio-8008-exec-6] DEBUG org.springframework.web.servlet.view.RedirectView - View name 'redirect:', model {}
14:18:08.601 [http-nio-8008-exec-6] DEBUG org.springframework.web.multipart.commons.CommonsMultipartResolver - Cleaning up part 'file', filename '白底logo.png'
14:18:08.601 [http-nio-8008-exec-6] DEBUG org.springframework.web.servlet.DispatcherServlet - Completed 302 FOUND
14:18:08.608 [http-nio-8008-exec-5] DEBUG org.springframework.web.servlet.DispatcherServlet - GET "/SpringMVC/", parameters={}
14:18:08.608 [http-nio-8008-exec-5] DEBUG org.springframework.web.servlet.handler.SimpleUrlHandlerMapping - Mapped to ParameterizableViewController [view="index"]
14:18:08.610 [http-nio-8008-exec-5] DEBUG org.springframework.web.servlet.DispatcherServlet - Completed 200 OK
14:18:12.924 [http-nio-8008-exec-10] DEBUG org.springframework.web.servlet.DispatcherServlet - GET "/SpringMVC/upload", parameters={}
14:18:12.924 [http-nio-8008-exec-10] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped to com.miaow.controller.FileUploadController#index()
14:18:12.925 [http-nio-8008-exec-10] DEBUG org.springframework.web.servlet.DispatcherServlet - Completed 200 OK
上传成功日志。
下载成功日志:
14:19:16.956 [http-nio-8008-exec-9] DEBUG org.springframework.web.servlet.DispatcherServlet - GET "/SpringMVC/download?filename=violet.webp", parameters={masked}
14:19:16.956 [http-nio-8008-exec-9] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped to com.miaow.controller.FileUploadController#downloadFile(String, HttpServletResponse)
14:19:16.958 [http-nio-8008-exec-9] DEBUG org.springframework.web.servlet.DispatcherServlet - Completed 200 OK
相关文章:
Spring MVC中实现一个文件上传和下载功能
说到文件上传和下载,相信每个开发者都有或多或少的接触过文件上传的功能吧,文件上传和下载是我们在学习计算机网络应用常见的一个功能,主要涉及到用户和服务器之间的数据传输。 我们来对文件上传和下载功能的进行相关概述吧! 文…...
Webpack 介绍
Webpack 介绍 Date: August 29, 2024 全文概要 Webpack概念: Webpack是一个静态的模块化的打包工具,可以为现代的 JavaSript 应用程序进行打包。 1-静态:Webpack可以将代码打包成最终的静态资源 2-模块化:webpack支持各种模块…...
在Linux实时监控某个应用是否运行,未运行,执行运行命令
1、shell脚本(每隔30秒检测一次) 脚本要注意的地方是:在Nodepad编辑的时候要使用Unix(LF)格式,避免在Linux无法执行命令 #!/bin/bash# RabbitMQ进程名称(可能需要根据你的安装进行调整) RABBITMQ_PROCE…...
Serilog文档翻译系列(六) - 可用的接收器、增强器、格式化输出
01、提供的接收器 Serilog 使用接收器将日志事件以各种格式写入存储。许多接收器由更广泛的 Serilog 社区开发和支持;可以通过在 NuGet 上搜索 serilog 标签找到。 02、增强器 日志事件可以通过多种方式增强属性。通过 NuGet 提供了一些预构建的增强器ÿ…...
傅里叶级数在机器人中的应用(动力学参数辨识)
B站首发!草履虫都能看懂的【傅里叶变换】讲解,清华大学李永乐老师教你如何理解傅里叶变换,辨清美颜和变声原理,!!_哔哩哔哩_bilibiliB站首发!草履虫都能看懂的【傅里叶变换】讲解,清…...
前端框架Vue、React、Angular、Svelte对比
在对比 React、Vue.js、Angular 和 Svelte 时,除了在高层次的特性上有显著差异,它们在核心设计理念和底层实现机制上也有明显的不同。为了清晰地理解这些框架,我们可以从以下几个方面来分析它们的核心不同点和底层不同点。 1. 框架类型和设计…...
深度学习后门攻击分析与实现(二)
前言 在本系列的第一部分中,我们已经掌握了深度学习中的后门攻击的特点以及基础的攻击方式,现在我们在第二部分中首先来学习深度学习后门攻击在传统网络空间安全中的应用。然后再来分析与实现一些颇具特点的深度学习后门攻击方式。 深度学习与网络空间…...
boost 的lockfree 使用
boost 的lockfree 使用 // test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <mutex> #include <memory> #include <condition_variable> #include <…...
基于Hexo个人博客界面优化
基于Hexo个人博客界面优化 怎么搭建个人博客 选择主题 经过多个对比,选择简单一点的的yilia 1.将主题文件下载解压到 你的博客目录的 themes下 下载yilia主题文件 2.改写配置 打开你的_config.yml #theme: landscape 这是原来的,改成下面这个 theme: yil…...
vue3+ts不能将类型“Timeout”分配给类型“null”不能将类型“Timeout”分配给类型number
在设置有setTimeout() 函数时,一般是需要进行清除计时器操作的; 常用的做法是定义一个全局变量timer,在onMounted或者有需要的地方进行赋值,在onBeforeUnmount进行clear,一般在定义timer变量时,使用 numbe…...
如何给多台Linux机器设置时间同步
文章目录 1,使用chrony时间同步服务1.1 修改chrony配置文件 2,使用ntpdate服务 1,使用chrony时间同步服务 Centos7默认已安装,另外基于centos7的统信OS,中科OS也会默认安装这个。如果你机器上没有这个服务,…...
忘写return有什么现象?
使用C语言,一直觉得没有return无所谓,直到被制裁。。 参考: 非void函数缺失返回值导致crash或结果异常的分析 - 知乎 (zhihu.com) 可以分析出: 没有写return 的话,eax的内容是在预期之外的。 例如更新参考内容的解…...
大数据新视界 --大数据大厂之 Druid 实时数据分析平台在大数据中的应用
💖💖💖亲爱的朋友们,热烈欢迎你们来到 青云交的博客!能与你们在此邂逅,我满心欢喜,深感无比荣幸。在这个瞬息万变的时代,我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…...
MySQL --基本查询(下)
文章目录 3.Update3.1将孙悟空同学的数学成绩变更为 80 分3.2将曹孟德同学的数学成绩变更为 60 分,语文成绩变更为 70 分3.3将总成绩倒数前三的 3 位同学的数学成绩加上 30 分3.4将所有同学的语文成绩更新为原来的 2 倍 4.Delete4.1删除数据4.1.1删除孙悟空同学的考…...
vue3实现自定义主题色切换功能
目录 1.添加theme样式文件2.引入样式文件3.使用变量设置css样式4.设置主题样式5.切换方法 1.添加theme样式文件 文件内容如下: html[data-theme"light"]{--text-color: #000000;/* 写需要切换的样式 */ } html[data-theme"dark"]{--text-color…...
不懂性能测试,被面试官挂了...
性能测试旨在检查应用程序或软件在特定负载下工作时的响应性和稳定性,从而检测应用程序/软件在响应速度、可扩展性和稳定性方面是否达到预期的要求。 简而言之,性能测试目标就是为了识别并消除应用程序中的性能瓶颈。 本文将为大家详细介绍性能测试主要…...
JS逆向基础-谷歌浏览器调试技巧(详细)
概述 浏览器的调试工具在 JavaScript 逆向工程中,帮助开发者分析和理解代码执行流程、变量值及其变化,从而揭示隐藏逻辑和加密机制,为破解、修改或复现代码提供重要支持。 调试面板详解 谷歌浏览器的调试面板概览: 顶部操作栏 …...
那年我双手插兜,使用IPv6+DDNS动态域名解析访问NAS
估计有很多科技宅和我一样,会买一个NAS存储或者自己折腾刷一下黑群晖玩玩,由于运营商不给分配固定的公网IP,就导致我在外出的时候无法访问家里的NAS,于是远程访问常常受到IP地址频繁变动的困扰。为了解决这一问题,结合…...
CSS的弹性盒子模型(Flex box)
弹性盒子模型是CSS3的一种新的布局模式,弹性盒是一种当页面需要适应不同的屏幕大小以及设备类型时确保拥有合适的布局方式,引入弹性盒子模型的目的时提供更加有效的方式来对一个容器中的子元素进行排列,对齐和分配空白空间。 弹性盒子由弹性容…...
django drf 分页器
自定义分页器代码: from django.core.paginator import InvalidPage from django.core.paginator import Paginator as DjangoPaginator from django.utils.functional import cached_property from rest_framework.exceptions import NotFound from rest_framewor…...
ArcSWAT建模踩坑记:你的土壤数据库参数算对了吗?聊聊SPAW的那些默认值和单位陷阱
ArcSWAT土壤参数校准实战:避开SPAW计算中的5个致命误区 当水文模拟结果与实测数据出现系统性偏差时,经验丰富的建模者会首先检查土壤参数——这个隐藏在界面背后的"沉默变量"往往是误差的最大来源。SPAW作为ArcSWAT推荐的土壤参数计算工具&…...
JVM调优实战:让你的服务性能提升50%
一、背景 线上一个核心订单服务,QPS 3000左右,经常出现接口超时告警。监控显示: 平均RT: 180ms(要求<100ms)Full GC频率: 每天20次,每次STW 1.5sCPU使用率: 峰值85%服务规格: 8C16G,堆内存…...
Windows Cleaner终极指南:3分钟彻底解决C盘爆红问题!
Windows Cleaner终极指南:3分钟彻底解决C盘爆红问题! 【免费下载链接】WindowsCleaner Windows Cleaner——专治C盘爆红及各种不服! 项目地址: https://gitcode.com/gh_mirrors/wi/WindowsCleaner 还在为Windows系统越用越慢而烦恼吗&…...
【稀缺首发】Midjourney达达主义风格提示工程白皮书:含89组对比实验数据+12个独家种子编号(限前500名下载)
更多请点击: https://intelliparadigm.com 第一章:达达主义在AI图像生成中的哲学解构 达达主义并非技术流派,而是一场对逻辑、秩序与意义权威的激进质疑——这一精神正悄然渗透至当代AI图像生成的核心机制中。当Stable Diffusion接收“一只会…...
DeepSeek LeetCode 2421. 好路径的数目 Python3实现
给你 Python3 版本的代码,思路和之前的 Java 实现一致: 完整代码 python class Solution: def numberOfGoodPaths(self, vals: List[int], edges: List[List[int]]) -> int: n len(vals) # 1. 构建邻接表 gr…...
AI模型部署实战:基于FastAPI与Tauri构建OpenClaw模型GUI应用
1. 项目概述与核心价值最近在AI应用开发圈里,一个名为“GrahamMiranda-AI/openclaw-model-gui”的项目引起了我的注意。乍一看这个标题,它融合了“openclaw-model”和“gui”两个关键部分,这让我立刻联想到一个典型的场景:一个已经…...
AI原生产品管理:多智能体协作如何重塑产品开发工作流
1. 项目概述:当AI成为你的产品经理最近在GitHub上看到一个挺有意思的项目,叫NathanJCW/ai-native-pm-cortex。光看名字,你大概能猜到它想做什么——“AI原生的产品经理大脑”。这可不是一个简单的聊天机器人插件,它试图构建一个完…...
BiscuitLang:专为Web业务逻辑设计的轻量级脚本语言
1. 项目概述:一个为现代Web开发而生的轻量级语言如果你和我一样,长期在Web前端和全栈开发的泥潭里摸爬滚打,那你一定对JavaScript生态的“臃肿”与“复杂”深有体会。一个简单的项目动辄node_modules文件夹体积惊人,工具链配置繁琐…...
如何用Wedecode实现微信小程序源代码的完美还原:从加密包到可读代码的完整指南
如何用Wedecode实现微信小程序源代码的完美还原:从加密包到可读代码的完整指南 【免费下载链接】wedecode 全自动化,微信小程序 wxapkg 包 源代码还原工具, 线上代码安全审计,支持 Windows, Macos, Linux 项目地址: https://gitcode.com/gh…...
大语言模型分步推理与自我验证框架:提升AI生成准确性的工程实践
1. 项目概述:当AI学会“自我验证”最近在开源社区里,一个名为“Lets-Verify-Step-by-Step”的项目引起了我的注意。这个项目直指当前大语言模型(LLM)应用中的一个核心痛点:如何让模型在生成复杂答案时,能像…...
