Spring MVC文件上传案例

wen java案例 2

本文目录导读:

Spring MVC文件上传案例

  1. 项目依赖配置 (pom.xml)
  2. 配置Spring MVC (web.xml)
  3. Spring MVC配置文件 (spring-mvc.xml)
  4. 文件上传Controller (FileUploadController.java)
  5. 文件上传页面 (upload.jsp)
  6. 上传结果页面 (result.jsp)
  7. 项目结构
  8. 配置文件上传大小限制
  9. 注意事项

我将为您提供一个完整的Spring MVC文件上传案例,包含单文件上传和多文件上传。

项目依赖配置 (pom.xml)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>file-upload-demo</artifactId>
    <version>1.0.0</version>
    <packaging>war</packaging>
    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <!-- Spring MVC -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.20</version>
        </dependency>
        <!-- Servlet API -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>
        <!-- JSP API -->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.3</version>
            <scope>provided</scope>
        </dependency>
        <!-- JSTL -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <!-- 文件上传依赖 -->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.4</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.11.0</version>
        </dependency>
    </dependencies>
    <build>
        <finalName>file-upload-demo</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

配置Spring MVC (web.xml)

<?xml version="1.0" encoding="UTF-8"?>
<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_4_0.xsd"
         version="4.0">
    <display-name>File Upload Demo</display-name>
    <!-- Spring MVC DispatcherServlet -->
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    <!-- 编码过滤器 -->
    <filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

Spring MVC配置文件 (spring-mvc.xml)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!-- 开启注解扫描 -->
    <context:component-scan base-package="com.example.controller"/>
    <!-- 注解驱动 -->
    <mvc:annotation-driven/>
    <!-- 配置视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
    <!-- 配置文件上传解析器 -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 设置上传文件的最大大小,单位字节 -->
        <property name="maxUploadSize" value="10485760"/> <!-- 10MB -->
        <!-- 设置上传文件的最大内存大小 -->
        <property name="maxInMemorySize" value="4096"/>
        <!-- 设置文件编码 -->
        <property name="defaultEncoding" value="UTF-8"/>
    </bean>
    <!-- 静态资源处理 -->
    <mvc:resources mapping="/resources/**" location="/resources/"/>
</beans>

文件上传Controller (FileUploadController.java)

package com.example.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
@Controller
@RequestMapping("/file")
public class FileUploadController {
    // 上传文件保存路径
    private static final String UPLOAD_DIR = "D:/uploads/";
    /**
     * 跳转到文件上传页面
     */
    @GetMapping("/upload")
    public String uploadPage() {
        return "upload";
    }
    /**
     * 单文件上传
     */
    @PostMapping("/upload/single")
    public String singleUpload(@RequestParam("file") MultipartFile file,
                              @RequestParam(value = "description", required = false) String description,
                              Model model) {
        if (file.isEmpty()) {
            model.addAttribute("message", "请选择要上传的文件!");
            return "result";
        }
        try {
            // 获取原始文件名
            String originalFilename = file.getOriginalFilename();
            // 获取文件扩展名
            String extension = "";
            if (originalFilename != null && originalFilename.contains(".")) {
                extension = originalFilename.substring(originalFilename.lastIndexOf("."));
            }
            // 生成新的文件名(使用UUID避免文件名冲突)
            String newFilename = UUID.randomUUID().toString().replace("-", "") + extension;
            // 创建日期文件夹
            String dateDir = new SimpleDateFormat("yyyyMMdd").format(new Date());
            String uploadDirPath = UPLOAD_DIR + dateDir + "/";
            File dir = new File(uploadDirPath);
            if (!dir.exists()) {
                dir.mkdirs();
            }
            // 保存文件
            File destFile = new File(uploadDirPath + newFilename);
            file.transferTo(destFile);
            // 设置返回信息
            model.addAttribute("message", "文件上传成功!");
            model.addAttribute("originalFilename", originalFilename);
            model.addAttribute("newFilename", newFilename);
            model.addAttribute("fileSize", file.getSize() / 1024 + " KB");
            model.addAttribute("filePath", dateDir + "/" + newFilename);
            model.addAttribute("description", description);
        } catch (IOException e) {
            e.printStackTrace();
            model.addAttribute("message", "文件上传失败:" + e.getMessage());
        }
        return "result";
    }
    /**
     * 多文件上传(方式一:使用MultipartHttpServletRequest)
     */
    @PostMapping("/upload/multiple1")
    public String multipleUpload1(MultipartHttpServletRequest request, Model model) {
        List<MultipartFile> files = request.getFiles("files");
        List<String> uploadResults = new ArrayList<>();
        if (files == null || files.isEmpty()) {
            model.addAttribute("message", "请选择要上传的文件!");
            return "result";
        }
        for (MultipartFile file : files) {
            if (!file.isEmpty()) {
                try {
                    String originalFilename = file.getOriginalFilename();
                    String extension = "";
                    if (originalFilename != null && originalFilename.contains(".")) {
                        extension = originalFilename.substring(originalFilename.lastIndexOf("."));
                    }
                    String newFilename = UUID.randomUUID().toString().replace("-", "") + extension;
                    String dateDir = new SimpleDateFormat("yyyyMMdd").format(new Date());
                    String uploadDirPath = UPLOAD_DIR + dateDir + "/";
                    File dir = new File(uploadDirPath);
                    if (!dir.exists()) {
                        dir.mkdirs();
                    }
                    File destFile = new File(uploadDirPath + newFilename);
                    file.transferTo(destFile);
                    uploadResults.add("文件 '" + originalFilename + "' 上传成功");
                } catch (IOException e) {
                    e.printStackTrace();
                    uploadResults.add("文件 '" + file.getOriginalFilename() + "' 上传失败:" + e.getMessage());
                }
            }
        }
        model.addAttribute("message", "多文件上传完成!");
        model.addAttribute("uploadResults", uploadResults);
        return "result";
    }
    /**
     * 多文件上传(方式二:使用数组参数)
     */
    @PostMapping("/upload/multiple2")
    public String multipleUpload2(@RequestParam("files") MultipartFile[] files, Model model) {
        List<String> uploadResults = new ArrayList<>();
        if (files == null || files.length == 0) {
            model.addAttribute("message", "请选择要上传的文件!");
            return "result";
        }
        for (MultipartFile file : files) {
            if (!file.isEmpty()) {
                try {
                    String originalFilename = file.getOriginalFilename();
                    String extension = "";
                    if (originalFilename != null && originalFilename.contains(".")) {
                        extension = originalFilename.substring(originalFilename.lastIndexOf("."));
                    }
                    String newFilename = UUID.randomUUID().toString().replace("-", "") + extension;
                    String dateDir = new SimpleDateFormat("yyyyMMdd").format(new Date());
                    String uploadDirPath = UPLOAD_DIR + dateDir + "/";
                    File dir = new File(uploadDirPath);
                    if (!dir.exists()) {
                        dir.mkdirs();
                    }
                    File destFile = new File(uploadDirPath + newFilename);
                    file.transferTo(destFile);
                    uploadResults.add("文件 '" + originalFilename + "' 上传成功,新文件名:" + newFilename);
                } catch (IOException e) {
                    e.printStackTrace();
                    uploadResults.add("文件 '" + file.getOriginalFilename() + "' 上传失败:" + e.getMessage());
                }
            }
        }
        model.addAttribute("message", "多文件上传完成!");
        model.addAttribute("uploadResults", uploadResults);
        return "result";
    }
    /**
     * AJAX异步文件上传
     */
    @PostMapping("/upload/ajax")
    @ResponseBody
    public String ajaxUpload(@RequestParam("file") MultipartFile file) {
        if (file.isEmpty()) {
            return "{\"success\": false, \"message\": \"文件为空\"}";
        }
        try {
            String originalFilename = file.getOriginalFilename();
            String extension = "";
            if (originalFilename != null && originalFilename.contains(".")) {
                extension = originalFilename.substring(originalFilename.lastIndexOf("."));
            }
            String newFilename = UUID.randomUUID().toString().replace("-", "") + extension;
            String dateDir = new SimpleDateFormat("yyyyMMdd").format(new Date());
            String uploadDirPath = UPLOAD_DIR + dateDir + "/";
            File dir = new File(uploadDirPath);
            if (!dir.exists()) {
                dir.mkdirs();
            }
            File destFile = new File(uploadDirPath + newFilename);
            file.transferTo(destFile);
            return "{\"success\": true, \"message\": \"文件上传成功\", \"filename\": \"" + newFilename + "\"}";
        } catch (IOException e) {
            e.printStackTrace();
            return "{\"success\": false, \"message\": \"文件上传失败: " + e.getMessage() + "\"}";
        }
    }
    /**
     * 上传进度获取(简化版)
     */
    @GetMapping("/upload/progress")
    @ResponseBody
    public String getUploadProgress(HttpServletRequest request) {
        // 这里需要配合实现ProgressListener来获取真实进度
        // 简化示例,返回模拟数据
        return "{\"progress\": 50}";
    }
}

文件上传页面 (upload.jsp)

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">文件上传</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 20px;
        }
        .upload-section {
            background: #f5f5f5;
            padding: 20px;
            margin-bottom: 20px;
            border-radius: 5px;
        }
        .upload-section h3 {
            margin-top: 0;
            color: #333;
        }
        .upload-form {
            margin: 15px 0;
        }
        .btn-upload {
            background: #007bff;
            color: white;
            padding: 8px 16px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            margin-top: 10px;
        }
        .btn-upload:hover {
            background: #0056b3;
        }
        .description-input {
            display: block;
            margin: 10px 0;
            padding: 5px;
            width: 300px;
        }
        .progress-bar {
            margin-top: 10px;
            display: none;
        }
        .progress {
            width: 100%;
            background: #e0e0e0;
            padding: 3px;
        }
        .progress-inner {
            background: #76b852;
            height: 20px;
            width: 0;
            text-align: center;
            white-space: nowrap;
        }
    </style>
</head>
<body>
    <h1>文件上传示例</h1>
    <!-- 单文件上传 -->
    <div class="upload-section">
        <h3>单文件上传</h3>
        <form action="${pageContext.request.contextPath}/file/upload/single" 
              method="post" enctype="multipart/form-data" class="upload-form">
            <input type="text" name="description" placeholder="文件描述(可选)" class="description-input"/>
            <br/>
            <input type="file" name="file" required/>
            <br/>
            <button type="submit" class="btn-upload">上传单个文件</button>
        </form>
    </div>
    <!-- 多文件上传 - 方式一 -->
    <div class="upload-section">
        <h3>多文件上传(方法一)</h3>
        <form action="${pageContext.request.contextPath}/file/upload/multiple1" 
              method="post" enctype="multipart/form-data" class="upload-form">
            <input type="file" name="files" multiple required/>
            <br/>
            <button type="submit" class="btn-upload">上传多个文件</button>
        </form>
    </div>
    <!-- 多文件上传 - 方式二 -->
    <div class="upload-section">
        <h3>多文件上传(方法二 - 使用数组)</h3>
        <form action="${pageContext.request.contextPath}/file/upload/multiple2" 
              method="post" enctype="multipart/form-data" class="upload-form">
            <input type="file" name="files" multiple required/>
            <br/>
            <button type="submit" class="btn-upload">上传多个文件</button>
        </form>
    </div>
    <!-- AJAX上传 -->
    <div class="upload-section">
        <h3>AJAX异步上传</h3>
        <input type="file" id="fileInput" name="file"/>
        <div class="progress-bar">
            <div class="progress">
                <div class="progress-inner" id="progressBar">0%</div>
            </div>
        </div>
        <button class="btn-upload" onclick="ajaxUpload()">AJAX上传文件</button>
    </div>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script>
        function ajaxUpload() {
            var fileInput = document.getElementById('fileInput');
            if (!fileInput.files || !fileInput.files[0]) {
                alert('请选择文件');
                return;
            }
            var formData = new FormData();
            formData.append('file', fileInput.files[0]);
            // 显示进度条
            $('.progress-bar').show();
            $.ajax({
                url: '${pageContext.request.contextPath}/file/upload/ajax',
                type: 'POST',
                data: formData,
                contentType: false,
                processData: false,
                xhr: function() {
                    var xhr = $.ajaxSettings.xhr();
                    if (xhr.upload) {
                        xhr.upload.progress = function(e) {
                            if (e.lengthComputable) {
                                var percent = Math.round((e.loaded / e.total) * 100);
                                $('#progressBar').css('width', percent + '%').text(percent + '%');
                            }
                        };
                    }
                    return xhr;
                },
                success: function(response) {
                    var result = JSON.parse(response);
                    if (result.success) {
                        alert('上传成功!文件名:' + result.filename);
                    } else {
                        alert('上传失败:' + result.message);
                    }
                    setTimeout(function() {
                        $('.progress-bar').hide();
                        $('#progressBar').css('width', '0').text('0%');
                    }, 2000);
                },
                error: function() {
                    alert('请求失败');
                    $('.progress-bar').hide();
                    $('#progressBar').css('width', '0').text('0%');
                }
            });
        }
    </script>
</body>
</html>

上传结果页面 (result.jsp)

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">上传结果</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 20px;
        }
        .result-box {
            background: #f9f9f9;
            border: 1px solid #ddd;
            padding: 20px;
            border-radius: 5px;
        }
        .success {
            color: #28a745;
        }
        .error {
            color: #dc3545;
        }
        .info-item {
            margin: 10px 0;
            padding: 10px;
            background: #fff;
            border-radius: 3px;
            border-left: 4px solid #007bff;
        }
        .info-label {
            font-weight: bold;
            color: #333;
        }
        .info-list {
            list-style: none;
            padding: 0;
        }
        .info-list li {
            margin: 5px 0;
            padding: 5px;
            background: #fff;
            border-radius: 3px;
        }
    </style>
</head>
<body>
    <div class="result-box">
        <h2 class="${message.startsWith('上传成功') ? 'success' : 'error'}">${message}</h2>
        <c:if test="${not empty originalFilename}">
            <div class="info-item">
                <span class="info-label">原始文件名:</span>${originalFilename}
            </div>
        </c:if>
        <c:if test="${not empty newFilename}">
            <div class="info-item">
                <span class="info-label">新文件名:</span>${newFilename}
            </div>
        </c:if>
        <c:if test="${not empty fileSize}">
            <div class="info-item">
                <span class="info-label">文件大小:</span>${fileSize}
            </div>
        </c:if>
        <c:if test="${not empty filePath}">
            <div class="info-item">
                <span class="info-label">保存路径:</span>${filePath}
            </div>
        </c:if>
        <c:if test="${not empty description}">
            <div class="info-item">
                <span class="info-label">文件描述:</span>${description}
            </div>
        </c:if>
        <c:if test="${not empty uploadResults}">
            <div class="info-item">
                <span class="info-label">多文件上传结果:</span>
                <ul class="info-list">
                    <c:forEach items="${uploadResults}" var="result">
                        <li>${result}</li>
                    </c:forEach>
                </ul>
            </div>
        </c:if>
        <p><a href="${pageContext.request.contextPath}/file/upload">返回上传页面</a></p>
    </div>
</body>
</html>

项目结构

file-upload-demo/
├── pom.xml
└── src
    └── main
        ├── java
        │   └── com/example/controller/
        │       └── FileUploadController.java
        ├── resources
        │   └── spring-mvc.xml
        └── webapp
            ├── WEB-INF
            │   ├── views
            │   │   ├── result.jsp
            │   │   └── upload.jsp
            │   └── web.xml
            └── index.jsp

配置文件上传大小限制

如果需要修改上传文件大小限制,可以在spring-mvc.xml中调整maxUploadSize属性,或者在项目的配置文件中配置:

# application.properties 中的配置
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB

注意事项

  1. 目录权限:确保UPLOAD_DIR目录存在且有写入权限
  2. 文件类型校验:生产环境建议添加文件类型校验,防止上传不安全文件
  3. 文件大小限制:根据实际需求调整上传大小限制
  4. 路径安全:使用UUID生成文件名,避免路径穿越攻击
  5. 错误处理:添加全局异常处理器,提供更好的错误提示
  6. 进度监控:对于大文件上传,可以添加进度监控功能

这个案例包含了常见的文件上传场景:单文件上传、多文件上传和AJAX异步上传,您可以根据实际需求进行修改和扩展。

抱歉,评论功能暂时关闭!