完整示例:Thymeleaf + Spring Boot 文件上传(单文件/多文件),控制器中分别用HttpServletRequest、MultipartFile、Part接收实现


完整示例:Thymeleaf + Spring Boot 文件上传(单文件/多文件)


一、项目结构
src/main/
├── java/
│   └── com.example.demo/
│       ├── controller/FileController.java
│       └── DemoApplication.java
├── resources/
│   └── templates/
│       └── upload.html
│   └── application.properties
└── static/
    └── upload/

二、关键代码实现

1. 表单页面(upload.html)
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>文件上传</title>
</head>
<body>
    <!-- 单文件上传(HttpServletRequest) -->
    <form th:action="@{/upload/request}" method="post" enctype="multipart/form-data">
        <input type="file" name="file" />
        <button type="submit">上传(HttpServletRequest)</button>
    </form>

    <!-- 单文件上传(MultipartFile) -->
    <form th:action="@{/upload/multipart}" method="post" enctype="multipart/form-data">
        <input type="file" name="file" />
        <button type="submit">上传(MultipartFile)</button>
    </form>

    <!-- 单文件上传(Part) -->
    <form th:action="@{/upload/part}" method="post" enctype="multipart/form-data">
        <input type="file" name="file" />
        <button type="submit">上传(Part)</button>
    </form>

    <!-- 多文件上传(MultipartFile) -->
    <form th:action="@{/upload/multi/multipart}" method="post" enctype="multipart/form-data">
        <input type="file" name="files" multiple />
        <button type="submit">上传多文件(MultipartFile)</button>
    </form>
</body>
</html>

2. 控制器(FileController.java)
package com.example.demo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Part;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Controller
public class FileController {

    // 打开文件上传页面
    @GetMapping("/upload/page")
    public String uploadPage() {
        return "upload"; // 对应 templates/upload.html
    }

    // === 使用 HttpServletRequest ===
    @PostMapping("/upload/request")
    @ResponseBody
    public Map<String, Object> uploadRequest(HttpServletRequest request) {
        // 强制转换为 MultipartHttpServletRequest(需Spring支持)
        if (request instanceof MultipartHttpServletRequest mreq) {
            MultipartFile file = mreq.getFile("file");
            if (file != null && !file.isEmpty()) {
                try {
                    file.transferTo(new File(file.getOriginalFilename()));
                    return dealResultMap(true, "上传成功");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return dealResultMap(false, "上传失败");
    }

    // === 使用 MultipartFile(单文件)===
    @PostMapping("/upload/multipart")
    @ResponseBody
    public Map<String, Object> uploadMultipartFile(MultipartFile file) {
        if (!file.isEmpty()) {
            try {
                file.transferTo(new File(file.getOriginalFilename()));
                return dealResultMap(true, "上传成功");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return dealResultMap(false, "上传失败");
    }

    // === 使用 Part(单文件)===
    @PostMapping("/upload/part")
    @ResponseBody
    public Map<String, Object> uploadPart(Part filePart) {
        if (filePart != null && filePart.getSize() > 0) {
            try {
                filePart.write(filePart.getSubmittedFileName());
                return dealResultMap(true, "上传成功");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return dealResultMap(false, "上传失败");
    }

    // === 多文件上传(MultipartFile)===
    @PostMapping("/upload/multi/multipart")
    @ResponseBody
    public Map<String, Object> uploadMultiFiles(@RequestParam("files") MultipartFile[] files) {
        boolean allSuccess = true;
        for (MultipartFile file : files) {
            if (!file.isEmpty()) {
                try {
                    file.transferTo(new File(file.getOriginalFilename()));
                } catch (IOException e) {
                    e.printStackTrace();
                    allSuccess = false;
                }
            }
        }
        return dealResultMap(allSuccess, allSuccess ? "所有文件上传成功" : "部分或全部文件上传失败");
    }

    // === 辅助方法:返回结果 ===
    private Map<String, Object> dealResultMap(boolean success, String msg) {
        Map<String, Object> result = new HashMap<>();
        result.put("success", success);
        result.put("msg", msg);
        return result;
    }
}

3. 配置文件(application.properties)
# 启用文件上传支持
spring.servlet.multipart.enabled=true
# 单文件最大大小(示例:10MB)
spring.servlet.multipart.max-file-size=10MB
# 总请求最大大小(示例:20MB)
spring.servlet.multipart.max-request-size=20MB
# 临时文件存储路径(可选)
spring.servlet.multipart.location=src/main/static/upload/

三、不同参数对比表格
参数类型功能描述依赖性易用性适用场景
HttpServletRequest需强制转换为MultipartHttpServletRequest,通过getFile()操作文件Spring框架 + Servlet API中(需类型转换)兼容旧代码或特殊需求
MultipartFileSpring封装的文件对象,提供丰富的文件操作方法(如getOriginalFilename()Spring框架高(直接绑定参数)推荐使用,开发效率高
PartServlet原生接口,直接操作上传的“部分”数据Servlet 3.0+中(需手动处理流)需严格遵循Servlet标准时

四、关键代码说明
  1. 表单配置

    • 必须设置enctype="multipart/form-data":否则Spring无法解析文件。
    • 单文件:使用<input type="file" name="file" />
    • 多文件:添加multiple属性并使用MultipartFile[]List<Part>接收。
  2. 控制器方法

    • HttpServletRequest:需强制转换为MultipartHttpServletRequest,通过getFile()获取文件。
    • MultipartFile:Spring自动绑定文件,直接通过@RequestParam接收。
    • Part:需通过@RequestParamPart参数直接接收,手动处理流。
  3. 文件保存

    • 使用transferTo()MultipartFile)或write()Part)将文件保存到指定路径。

五、核心差异总结
维度HttpServletRequestMultipartFilePart
依赖框架Spring + Servlet APISpringServlet 3.0+
绑定方式需强制转换为MultipartHttpServletRequest直接通过@RequestParam绑定直接通过@RequestParam绑定
文件操作需手动处理类型转换封装方法丰富(如获取原始文件名)需手动处理流和元数据
推荐场景兼容旧代码或特殊需求新项目开发(简洁易用)需严格遵循Servlet标准时

六、注意事项
  1. 文件大小限制:需在application.properties中调整max-file-sizemax-request-size
  2. 临时目录:默认使用系统临时目录,可通过spring.servlet.multipart.location自定义。
  3. 异常处理:需添加try-catch处理文件读写异常(示例中简化处理)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱的叹息

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值