Spring MVC AJAX文件上传下载
点击上方“IT那活儿”公众号–专注于企业全栈运维技术分享,不管IT什么活儿,干就完了!!!
本文档是前后端分离最常用的方案:
前端用 AJAX(axios)异步上传文件,后端 Spring MVC 接收;前端通过 AJAX / 链接下载文件,后端返回文件流。
环境准备
<!– Spring MVC核心 –><dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.20</version></dependency><!– 文件上传解析器 –><dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.4</version></dependency><!– JSON 工具 –><dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.13.4</version></dependency><!– Servlet API –><dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope></dependency>
在 spring-mvc.xml 中注册文件上传解析器(必须叫 multipartResolver):
<?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:mvc=”http://www.springframework.org/schema/mvc” xmlns:context=”http://www.springframework.org/schema/context” xsi:schemaLocation=” http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd”> <!– 扫描控制器 –> <context:component-scan base-package=”com.controller”/> <!– 开启注解驱动 –> <mvc:annotation-driven/> <!– 文件上传配置:id必须是multipartResolver –> <bean id=”multipartResolver” class=”org.springframework.web.multipart.commons.CommonsMultipartResolver”> <!– 最大上传大小 10MB –> <property name=”maxUploadSize” value=”10485760″/> <!– 编码格式 –> <property name=”defaultEncoding” value=”UTF-8″/> </bean> <!– 视图解析器 –> <mvc:view-resolvers> <mvc:jsp prefix=”/WEB-INF/views/” suffix=”.jsp”/> </mvc:view-resolvers></beans>
后端控制器(Controller)
创建 FileController.java,同时实现上传 + 下载:
package com.controller;import org.springframework.http.HttpHeaders;import org.springframework.http.HttpStatus;import org.springframework.http.ResponseEntity;import org.springframework.stereotype.Controller;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.bind.annotation.ResponseBody;import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletRequest;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.net.URLEncoder;import java.nio.charset.StandardCharsets;import java.util.HashMap;import java.util.Map;import java.util.UUID;@Controllerpublic class FileController { // ====================== 1. 文件上传 ====================== @PostMapping(“/upload”) @ResponseBody // 返回JSON public Map<String, Object> upload( @RequestParam(“file”) MultipartFile file, // 接收上传文件 HttpServletRequest request ) { Map<String, Object> result = new HashMap<>(); // 判断是否上传了文件 if (file.isEmpty()) { result.put(“code”, 0); result.put(“msg”, “请选择文件”); return result; } try { // 1. 获取上传目录(项目部署路径下的 upload 文件夹) String uploadPath = request.getServletContext().getRealPath(“/upload”); File path = new File(uploadPath); if (!path.exists()) path.mkdirs(); // 不存在则创建 // 2. 生成唯一文件名,防止重名 String originalFilename = file.getOriginalFilename(); String suffix = originalFilename.substring(originalFilename.lastIndexOf(“.”)); String newFileName = UUID.randomUUID() + suffix; // 3. 写入文件 File targetFile = new File(path, newFileName); file.transferTo(targetFile); // 4. 返回成功信息 result.put(“code”, 1); result.put(“msg”, “上传成功”); result.put(“fileName”, newFileName); // 存储的文件名 return result; } catch (IOException e) { e.printStackTrace(); result.put(“code”, 0); result.put(“msg”, “上传失败:” + e.getMessage()); return result; } } // ====================== 2. 文件下载 ====================== @GetMapping(“/download”) public ResponseEntity<byte[]> download( @RequestParam(“fileName”) String fileName, // 要下载的文件名 HttpServletRequest request ) throws IOException { // 1. 获取文件路径 String uploadPath = request.getServletContext().getRealPath(“/upload”); File file = new File(uploadPath, fileName); // 2. 读取文件为字节数组 FileInputStream fis = new FileInputStream(file); byte[] bytes = new byte[fis.available()]; fis.read(bytes); fis.close(); // 3. 设置响应头(解决中文文件名乱码) HttpHeaders headers = new HttpHeaders(); String downloadName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name()); headers.add(“Content-Disposition”, “attachment;filename=” + downloadName); // 4. 返回文件流 return new ResponseEntity<>(bytes, headers, HttpStatus.OK); }}
前端实现页面(HTML)
3.1 创建 /WEB-INF/views/file.jsp
使用axios实现 AJAX(也可以用原生 AJAX /jQuery):
<%@ page contentType=”text/html;charset=UTF-8″ language=”java” %> <html> <head> <title>文件上传下载</title> <!– 引入axios –> <script src=”https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js”></script> </head> <body> <h2>Spring MVC + AJAX 文件上传下载</h2> <!– 上传区域 –> <div style=”margin: 20px 0;”> <h3>文件上传</h3> <input type=”file” id=”uploadFile”> <button onclick=”uploadFile()”>上传</button> <p id=”uploadMsg”></p> </div> <hr> <!– 下载区域 –> <div> <h3>文件下载</h3> <input type=”text” id=”downloadFileName” placeholder=”输入上传后的文件名”> <button onclick=”downloadFile()”>下载</button> </div> <script> // ====================== 1. AJAX 上传文件 ====================== function uploadFile() { let file = document.getElementById(“uploadFile”).files[0]; if (!file) { document.getElementById(“uploadMsg”).innerText = “请选择文件”; return; } // 创建FormData(必须用这个包装文件) let formData = new FormData(); formData.append(“file”, file); // key和后端@RequestParam一致 // 发送AJAX axios.post(“/upload”, formData, { headers: {“Content-Type”: “multipart/form-data”} }).then(res => { document.getElementById(“uploadMsg”).innerText = res.data.msg; // 自动把文件名填入下载框 if (res.data.code === 1) { document.getElementById(“downloadFileName”).value = res.data.fileName; } }).catch(err => { document.getElementById(“uploadMsg”).innerText = “上传异常”; console.error(err); }); } // ====================== 2. AJAX 下载文件 ====================== function downloadFile() { let fileName = document.getElementById(“downloadFileName”).value; if (!fileName) { alert(“请输入文件名”); return; } // 发送请求,设置responseType为blob(接收二进制文件) axios.get(“/download”, { params: {fileName: fileName}, responseType: “blob” }).then(res => { // 创建下载链接 let url = window.URL.createObjectURL(new Blob([res.data])); let a = document.createElement(“a”); a.href = url; a.download = fileName; // 下载后的文件名 document.body.appendChild(a); a.click(); a.remove(); window.URL.revokeObjectURL(url); }).catch(err => { alert(“文件不存在或下载失败”); console.error(err); }); } </script> </body> </html>
@GetMapping(“/toFilePage”)public String toFilePage() { return “file”; // 跳转到 file.jsp}
测试步骤
step2访问:http://localhost:8080/toFilePage
step3选择文件 → 点击上传 → 提示上传成功
step4自动填充文件名 → 点击下载 → 浏览器自动下载文件