Spring MVC中实现一个文件上传和下载功能

说到文件上传和下载,相信每个开发者都有或多或少的接触过文件上传的功能吧,文件上传和下载是我们在学习计算机网络应用常见的一个功能,主要涉及到用户和服务器之间的数据传输。

我们来对文件上传和下载功能的进行相关概述吧!

文件上传

定义:文件上传是指用户将本地计算机上的文件通过网络传输到服务器的过程。用户通常通过网页表单选择文件并提交,服务器接收并存储该文件。

过程:

  1. 用户选择文件 :用户在网页上选择要上传的文件,通常通过一个文件输入框(<input type="file">)。
  2. 表单提交:用户点击提交按钮,浏览器将文件和其他表单数据一起发送到服务器。
  3. HTTP请求:浏览器发起一个HTTP POST请求,包含文件数据和其他表单字段。
  4. 服务器接收文件
    • 服务器接收到请求后,解析请求体中的文件数据。
    • 服务器将文件存储在指定的目录中。
  5. 反馈结果:服务器处理完上传后,通常会返回一个响应,告知用户上传是否成功。

文件下载

定义:文件下载是指用户从服务器获取文件并保存到本地计算机的过程。用户通常通过点击链接或按钮来触发下载。

过程:

  1. 用户请求下载:用户在网页上点击下载链接或按钮,触发下载请求。
  2. HTTP请求:浏览器发起一个HTTP GET请求,请求特定的文件。
  3. 服务器处理请求
    • 服务器接收到请求后,查找请求的文件。
    • 服务器将文件内容写入HTTP响应体,并设置适当的响应头(如Content-Disposition)以指示浏览器下载文件而不是直接显示。
  4. 浏览器接收文件:浏览器接收到响应后,开始下载文件并提示用户选择保存位置。
  5. 文件保存:用户选择保存位置后,文件被下载到本地计算机。

文件上传和下载的关键步骤

在文件上传和下载的过程中,涉及以下关键步骤:

  1. 用户界面:提供文件选择和下载的用户界面(HTML表单)。
  2. HTTP请求:使用适当的HTTP方法(POST用于上传,GET用于下载)发送请求。
  3. 请求处理:服务器端代码处理请求,解析文件数据(上传)或查找文件(下载)。
  4. 文件存储:在上传过程中,将文件存储在服务器的指定位置。
  5. 响应返回:服务器返回处理结果(上传成功/失败)或文件内容(下载)。
  6. 错误处理:处理可能出现的错误,如文件大小限制、文件类型验证、文件不存在等。

在SpringMVC中实现一个文件上传和下载的功能

第一步创建我们的文件项目目录结构:

java 复制代码
src
 └── main
     ├── java
     │   └── com
     │       └── example
     │           └── fileupload
     │               ├── FileUploadController.java
     │               └── WebConfig.java
     ├── resources
     │   └── templates
     │       └── upload.html
     └── web.xml

第二步:添加相关依赖

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:

java 复制代码
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 {

    @Bean
    public ViewResolver viewResolver(SpringTemplateEngine templateEngine) {
        ThymeleafViewResolver resolver = new ThymeleafViewResolver();
        resolver.setTemplateEngine(templateEngine);
        resolver.setCharacterEncoding("UTF-8");
        resolver.setOrder(1);
        return resolver;
    }

    @Bean
    public CommonsMultipartResolver multipartResolver() {
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
        multipartResolver.setMaxUploadSize(10485760); // 10MB
        return multipartResolver;
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/uploads/**").addResourceLocations("file:uploads/");
    }
}

创建控制器

FileUploadController.java中实现文件上传和下载的逻辑:

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模板

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文件

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>
properties 复制代码
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

上传成功日志。

下载成功日志:

properties 复制代码
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
相关推荐
不爱学习的YY酱16 分钟前
【操作系统不挂科】<CPU调度(13)>选择题(带答案与解析)
java·linux·前端·算法·操作系统
丁总学Java21 分钟前
Maven项目打包,com.sun.tools.javac.processing
java·maven
kikyo哎哟喂31 分钟前
Java 代理模式详解
java·开发语言·代理模式
Doker 多克34 分钟前
Spring AI 框架使用的核心概念
人工智能·spring·chatgpt
duration~37 分钟前
SpringAOP模拟实现
java·开发语言
小码ssim44 分钟前
IDEA使用tips(LTS✍)
java·ide·intellij-idea
潜洋1 小时前
Spring Boot教程之五:在 IntelliJ IDEA 中运行第一个 Spring Boot 应用程序
java·spring boot·后端
暮志未晚Webgl2 小时前
109. UE5 GAS RPG 实现检查点的存档功能
android·java·ue5
小叶lr2 小时前
idea 配置 leetcode插件 代码模版
java·leetcode·intellij-idea
qq_429856572 小时前
idea启动服务报错Application run failed
java·ide·intellij-idea