Spring Boot + Vue 实现文件上传下载

在Web应用开发中,文件上传和下载是非常常见的功能,例如用户头像上传、附件管理、图片展示等。本文将通过一个完整的示例,介绍如何使用Spring Boot 构建后端文件上传下载接口,并结合Vue 3 + Element Plus前端组件实现文件的上传与展示。代码简洁清晰,可直接应用于实际项目。

技术栈

  • 后端:Spring Boot 2.x,文件操作使用java.nio.file

  • 前端:Vue 3 + Element Plus(el-upload、el-image)

  • 构建工具:Maven(后端),Vite(前端)

功能概述

  1. 上传文件:通过POST请求将文件保存到服务器指定目录,并返回该文件的下载URL。

  2. 下载文件:通过GET请求根据文件名返回文件流(支持浏览器直接下载或预览)。

  3. 前端集成:使用Element Plus的上传组件上传头像,上传成功后展示图片。

后端实现

1. 创建Spring Boot项目

pom.xml中添加必要依赖:

XML 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

2. 编写文件上传下载Controller

创建FileController,处理/api/files/upload(上传)和/api/files/download/{fileName}(下载)请求。

java 复制代码
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

@RestController
@RequestMapping("/api/files")
public class FileController {

    // 文件存储目录,实际项目中应配置在application.yml中
    private final String uploadDir = "uploads/";

    public FileController() {
        // 确保上传目录存在
        Path path = Paths.get(uploadDir);
        if (!Files.exists(path)) {
            try {
                Files.createDirectories(path);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 文件上传
     * @param file 上传的文件(参数名必须与前端一致)
     * @return 文件的下载URL
     */
    @PostMapping("/upload")
    public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) {
        try {
            String fileName = file.getOriginalFilename();
            Path path = Paths.get(uploadDir + fileName);
            Files.write(path, file.getBytes());

            // 构建可访问的下载URL
            String fileDownloadUri = ServletUriComponentsBuilder.fromCurrentContextPath()
                    .path("/api/files/download/")
                    .path(fileName)
                    .toUriString();

            return ResponseEntity.ok(fileDownloadUri);
        } catch (IOException e) {
            return ResponseEntity.badRequest().body("文件上传失败: " + e.getMessage());
        }
    }

    /**
     * 文件下载
     * @param fileName 文件名
     * @param response HttpServletResponse
     */
    @GetMapping("/download/{fileName}")
    public void download(@PathVariable String fileName, HttpServletResponse response) throws IOException {
        Path path = Paths.get(uploadDir + fileName);

        if (!Files.exists(path)) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        // 设置响应头
        response.setContentType("application/octet-stream");
        response.setHeader("Content-Disposition", "attachment; filename=" + fileName);

        byte[] bytes = Files.readAllBytes(path);
        ServletOutputStream os = response.getOutputStream();
        os.write(bytes);
        os.flush();
        os.close();
    }
}

关键点说明

  • 上传接口使用MultipartFile接收文件,保存到本地uploads/目录(若目录不存在则自动创建)。

  • 返回的URL是通过ServletUriComponentsBuilder动态生成的绝对路径,确保前端可以直接访问下载接口。

  • 下载接口设置Content-Typeapplication/octet-stream,强制浏览器以附件形式下载;若希望图片直接显示,可改为对应的MIME类型(如image/jpeg),下文会讨论优化方案。

前端实现(Vue 3 + Element Plus)

1. 引入Element Plus

在Vue项目中安装Element Plus并全局引入(或按需引入):

bash 复制代码
npm install element-plus

main.js中:

javascript 复制代码
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'

const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')

2. 表单中使用el-upload上传头像

假设有一个用户表单,包含头像上传项:

XML 复制代码
<template>
  <el-form :model="form" label-width="80px">
    <el-form-item label="头像">
      <el-upload
        action="http://localhost:8080/api/files/upload"
        :on-success="handleFileSuccess"
        list-type="picture"
      >
        <el-button type="primary">上传头像</el-button>
      </el-upload>
    </el-form-item>

    <!-- 其他表单项... -->
  </el-form>
</template>

<script setup>
import { reactive } from 'vue'

const form = reactive({
  avatar: '' // 用于存储头像URL
})

const handleFileSuccess = (response) => {
  // response 是上传成功后后端返回的字符串(即下载URL)
  form.avatar = response
  console.log('头像URL:', response)
}
</script>

说明

  • action指向后台上传接口地址,需与后端实际地址一致(注意端口)。

  • on-success回调在文件上传成功后触发,response参数即为后端返回的字符串(图片下载URL),将其保存到表单字段中。

3. 在表格中展示头像

若需要在表格中展示已上传的头像,可以使用el-image组件,src绑定为保存的URL:

XML 复制代码
<el-table :data="tableData">
  <el-table-column label="头像" width="120">
    <template #default="scope">
      <el-image
        v-if="scope.row.img"
        :src="scope.row.img"
        :preview-src-list="[scope.row.img]"
        :preview-teleported="true"
        style="width: 40px; height: 40px; border-radius: 50%; display: block"
      />
    </template>
  </el-table-column>
  <!-- 其他列 -->
</el-table>
相关推荐
LinXunFeng7 天前
Obsidian - 使用 Share Note 分享笔记并自部署
前端·笔记·github
闪闪发亮的小星星11 天前
高斯光以及高斯光公式解释
笔记
cqbzcsq11 天前
CellFlow虚拟细胞论文阅读
论文阅读·人工智能·笔记·学习·生物信息
阿米亚波11 天前
【Windows】QEMU 启动 openEuler aarch64/arm64 架构系统 + 离线软件源
linux·windows·经验分享·笔记·架构·arm
自传.11 天前
尚硅谷 Vibe Coding|第三章(1) Claude Code深度使用与进阶技巧 学习笔记
笔记·学习·尚硅谷·vibecoding
.千余11 天前
【C++】模板进阶全解:非类型参数|全特化|偏特化|分离编译完全指南
开发语言·c++·笔记·学习·其他
自传.11 天前
尚硅谷 Vibe Coding|第二章 AI编程工具生态 学习笔记
笔记·学习·ai编程·尚硅谷·vibe coding
秋波。未央11 天前
Java Agent 开发 · Day 1 学习笔记(含作业完整标准答案)
java·笔记·学习
中屹指纹浏览器12 天前
2026指纹浏览器字体指纹、字体渲染偏差检测与全维度虚拟字体池搭建方案
经验分享·笔记