乐于分享
好东西不私藏

Spring MVC AJAX文件上传下载

Spring MVC AJAX文件上传下载

点击上方“IT那活儿”公众号–专注于企业全栈运维技术分享,不管IT什么活儿,干就完了!!!

本文档是前后端分离最常用的方案:

前端用 AJAX(axios)异步上传文件,后端 Spring MVC 接收;前端通过 AJAX / 链接下载文件,后端返回文件流。

环境准备

1.1 依赖(Maven)
添加Maven依赖:
<!– 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>
1.2 Spring MVC 配置文件
在 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>
3.2 跳转页面的 Controller 
增加一个页面跳转方法: 
@GetMapping(“/toFilePage”)public String toFilePage() {    return “file”; // 跳转到 file.jsp}

测试步骤

step1 启动项目
step2访问:http://localhost:8080/toFilePage
step3选择文件 → 点击上传 → 提示上传成功
step4自动填充文件名 → 点击下载 → 浏览器自动下载文件
END

本文作者:刘 祥 (上海新炬中北团队)

本文来源:“IT那活儿”公众号