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
相关推荐
The丶Closer9 分钟前
10. 排序
java·数据结构·算法·排序算法
java_heartLake20 分钟前
设计模式之策略模式
java·设计模式·策略模式
闲人一枚(学习中)21 分钟前
Maven-一、分模块开发
java·maven
孟林洁32 分钟前
Jenkins入门:从搭建到部署第一个Springboot项目(踩坑记录)
java·运维·jenkins
夜月行者44 分钟前
如何使用ssm实现航空信息管理系统+vue
java·后端·ssm
liuyang-neu1 小时前
力扣 简单 104.二叉树的最大深度
java·数据结构·算法·leetcode
小菜yh1 小时前
后端人需知
java·前端·javascript·vue.js·设计模式
stormsha1 小时前
Java中使用接口实现回调函数的详解与示例
java·开发语言·python
Xinan_____1 小时前
Linux——k8s组件
java·linux·kubernetes
什码情况1 小时前
报数游戏 - 华为OD统一考试(E卷)
java·python·算法·游戏·华为od·笔试·华为od机试