基于SpringBoot + Vue实现单个文件上传(带上Token和其它表单信息)的前后端完整过程

简介: 本文介绍了在SpringBoot + Vue项目中实现单个文件上传的同时携带Token和其它表单信息的前后端完整流程,包括后端SpringBoot的文件上传处理和前端Vue使用FormData进行表单数据和文件的上传。

前言

有时遇到这种需求,在上传文件的同时还需要带上token凭据和其它表单信息,那么这个需求前端可以使用FormData数据类型来实现。FormData和JSON一样也是通过body传递的,前者支持字符串和二进制文件,后者只能是字符串,如下图1,图2所示。

图一

图二

一、后端代码

(1)控制层(GameController.java)

@PostMapping(value = "uploadSingleFile")
@ResponseBody
public CommonResponse uploadSingleFile(@RequestHeader("Authorization") String token,
                                       @RequestParam("file") MultipartFile file,
                                       @RequestParam("username") String username) {
   
   
    return gameService.uploadSingleFile(token, file, username);
}

(2)接口层(IGameService.java)

CommonResponse uploadSingleFile(String token, MultipartFile file, String username);

(3)实现层(GameServiceImpl.java)

@Value("${system.upload-file-path}")
private String UploadFilePath;

@Override
public CommonResponse uploadSingleFile(String token, MultipartFile file, String username) {
   
   
    System.out.println(token);
    System.out.println(username);
    try {
   
   
        String uuidStr = UUID.randomUUID().toString();
        String uuid = uuidStr.substring(0, 8) + uuidStr.substring(9, 13) + uuidStr.substring(14, 18) + uuidStr.substring(19, 23) + uuidStr.substring(24);

        String originFileName = file.getOriginalFilename(); // 原文件名,如:HelloWorld.xlsx
        int beginIndex = originFileName.lastIndexOf("."); // 从后匹配"."
        String newFileName = uuid + originFileName.substring(beginIndex); // 新文件名,如:uuid.xlsx
        String destFileName = UploadFilePath + File.separator + newFileName; // 完整文件名 = 存储路径 + 原文件名

        // 复制文件到指定目录
        File destFile = new File(destFileName);
        destFile.getParentFile().mkdirs();
        file.transferTo(destFile);

        // 返回文件名
        return CommonResponse.ok(newFileName);
    } catch (FileNotFoundException e) {
   
   
        e.printStackTrace();
        return CommonResponse.fail(e.getMessage());
    } catch (IOException e) {
   
   
        e.printStackTrace();
        return CommonResponse.fail(e.getMessage());
    }
}

二、前端代码

(1)视图页面(/src/view/Example/UploadFormData/index.vue)

<template>
  <div>
    <el-dialog
      width="400"
      title="导入 Excel"
      class="import-excel-dialog"
      align-center
      destroy-on-close
      draggable
      center
      v-model="importExcelDialog.isVisible"
      :before-close="handleCloseImportExcelDialogClick"
    >
      <div>
        <p style="margin: 0 auto 7px 0; font-size: 13px">请上传Excel文件</p>
        <el-upload
          ref="importExcelUploadRef"
          drag
          action=""
          :limit="1"
          :on-exceed="handleUploadFileExceed"
          :on-change="handleUploadFileChange"
          :auto-upload="false"
        >
          <el-icon class="el-icon--upload"><upload-filled /></el-icon>
          <div class="el-upload__text" style="font-size: 13px">
            拖动文件到此处进行上传 或 <em>点击上传</em>
          </div>
          <template #tip>
            <div class="el-upload__tip">支持格式 : xls/xlsx/xlsm</div>
          </template>
        </el-upload>

        <el-input
          size="small"
          v-model="importExcelDialog.username"
          style="width: 100%; background-color: #eee"
          placeholder="请输入用户"        
        >
        </el-input>
      </div>

      <template #footer>
        <div>
          <el-button size="small" type="primary" @click="handleUploadFileComfirm($event)">
            <el-icon :size="18" style="margin-right: 5px"><Check /></el-icon>
            <small>确定</small>
          </el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>

<script>
export default {
    
    
  data: () => {
    
    
    return {
    
    
      // 导入Excel弹窗
      importExcelDialog: {
    
    
        isVisible: false,
        username: '帅龍之龍',
        uploadFileList: [], // 校验通过的上传文件列表
      },
    }
  },
  created() {
    
    
    // ...
  },
  mounted() {
    
    
    this.handleOpenImportExcelDialogClick()
  },
  methods: {
    
    
    /**
     * 打开导入Excel弹窗事件句柄
     */
    handleOpenImportExcelDialogClick() {
    
    
      this.importExcelDialog.isVisible = true
    },

    /**
     * 文件上传 - 文件超过句柄方法
     */
    async handleUploadFileExceed(files, uploadFiles) {
    
    
      console.log(
        '%c 文件超过句柄方法 %c handleUploadFileExceed',
        'padding: 1px; background-color: #35495e; color: #fff',
        'padding: 1px; background-color: #5e7ce0; color: #fff',
      )
      console.log('%c ∟ %c files %c =>', 'text-indent: 10px', 'padding: 1px; background-color: #41b883; color: #fff', 'color: #000', files)
      console.log('%c ∟ %c uploadFiles %c =>', 'text-indent: 10px', 'padding: 1px; background-color: #41b883; color: #fff', 'color: #000', uploadFiles)

      const refs = await this.$refs
      const importExcelUploadRef = refs.importExcelUploadRef

      const uploadFile = files[0]
      const fileName = uploadFile.name // xxxxxx.xlsx
      const index = fileName.lastIndexOf('.')
      const type = fileName.substring(index) // .xlsx

      if (!(type == '.xls' || type == '.xlsx' || type == '.xlsm')) {
    
    
        this.$message({
    
     message: '文件格式错误,应为 xls/xlsx/xlsm 类型文件', type: 'warning', duration: 3000 })

        // 清空
        importExcelUploadRef.clearFiles()
      } else {
    
    
        // 清空
        importExcelUploadRef.clearFiles()

        // 回显
        const file = files[0]
        importExcelUploadRef.handleStart(file) 

        // 文件上传列表重新赋值
        this.importExcelDialog.uploadFileList = []
        this.importExcelDialog.uploadFileList.push(uploadFile)
      }
    },

    /**
     * 文件上传 - 文件改变句柄方法
     */
    async handleUploadFileChange(uploadFile, uploadFiles) {
    
    
      console.log(
        '%c 文件改变句柄方法 %c handleUploadFileChange',
        'padding: 1px; background-color: #35495e; color: #fff',
        'padding: 1px; background-color: #5e7ce0; color: #fff',
      )
      console.log('%c ∟ %c uploadFile %c =>', 'text-indent: 10px', 'padding: 1px; background-color: #41b883; color: #fff', 'color: #000', uploadFile)
      console.log('%c ∟ %c uploadFiles %c =>', 'text-indent: 10px', 'padding: 1px; background-color: #41b883; color: #fff', 'color: #000', uploadFiles)

      const refs = await this.$refs
      const importExcelUploadRef = refs.importExcelUploadRef

      const fileName = uploadFile.name // xxxxxx.xlsx
      const index = fileName.lastIndexOf('.')
      const type = fileName.substring(index) // .xlsx

      if (!(type == '.xls' || type == '.xlsx' || type == '.xlsm')) {
    
    
        this.$message({
    
     message: '文件格式错误,应为 xls/xlsx/xlsm 类型文件', type: 'warning', duration: 3000 })

        // 清空
        importExcelUploadRef.clearFiles()
      } else {
    
    
        // 文件上传列表重新赋值
        this.importExcelDialog.uploadFileList = []
        this.importExcelDialog.uploadFileList.push(uploadFile)
      }
      console.log('%c ∟ %c uploadFileList %c =>', 'text-indent: 10px', 'padding: 1px; background-color: #41b883; color: #fff', 'color: #000', this.importExcelDialog.uploadFileList)
    },

    /**
     * 文件上传 - 确认上传句柄方法
     */
    async handleUploadFileComfirm(evt) {
    
    
      this.$elementUtil.handleElButtonBlur(evt)

      if (this.importExcelDialog.uploadFileList.length == 0) {
    
    
        this.$message({
    
     message: '请上传文件', type: 'warning', duration: 3000 })
        return
      }

      let formData = new FormData()
      this.importExcelDialog.uploadFileList.map(uploadFile => {
    
    
        formData.append('file', uploadFile.raw)
      })
      formData.append('username', this.importExcelDialog.username.trim())

      this.$axios.post(
        `/api/uploadSingleFile`,
        formData,
        {
    
    
          headers: {
    
    
            'Access-Control-Allow-Origin': '*',
            'Content-Type': 'multipart/form-data',
            'Authorization': 'Bearer token'
          },
        }
      )
      .then((res) => {
    
    
        console.log('get =>', res)
        if (res.status == 200 && res.data) {
    
    
          const result = res.data
          if (result.code == 200 && result.success) {
    
    
            this.$elementUtil.handleAutoCloseMessage(`上传成功,新文件名为:${
      
      result.data}`, 'success', 5, true)
          } else {
    
    
            this.$elementUtil.handleAutoCloseMessage(`上传失败,服务端出错,请联系管理员`, 'error', 5, true)
          }
        }

        setTimeout(() => {
    
     this.importExcelDialog.isVisible = false }, 1000)
      }).catch(err =>{
    
    
        this.$elementUtil.handleAutoCloseMessage(err, 'error', 5, true)
        console.error(err)
      })

      const refs = await this.$refs
      const importExcelUploadRef = refs.importExcelUploadRef

      // 清空
      importExcelUploadRef.clearFiles()

      // 文件上传列表重置
      this.importExcelDialog.uploadFileList = []
    },

    /**
     * 关闭导入Excel弹窗事件句柄
     */
    handleCloseImportExcelDialogClick() {
    
    
      this.importExcelDialog.isVisible = false
    },
  }
}
</script>

<style lang="less" scoped>
  :deep(.import-excel-dialog) {
    
    

    .el-dialog__header {
    
    
      margin-right: 0;
      padding: 25px 20px;
      border-bottom: 1px solid #efefef;

      .el-dialog__title {
    
    
        font-size: 15px;
        word-wrap: break-word;
        word-break: normal
      }

      .el-dialog__headerbtn {
    
    
        top: 15px;
        font-size: 20px;
      }
    }

    .el-dialog__body {
    
    
      padding: calc(var(--el-dialog-padding-primary) + 10px) var(--el-dialog-padding-primary);

      .el-select {
    
    

        .el-input {
    
    

          .el-input__wrapper {
    
    
            background-color: transparent;
          }
        }
      }

      .el-input {
    
    

        .el-input__wrapper {
    
    
          background-color: #eee;
        }
      }
    }

    .el-dialog__footer {
    
    
      padding: var(--el-dialog-padding-primary);
      border-top: 1px solid #efefef;
    }
  }
</style>

三、运行效果

目录
相关文章
|
10天前
|
前端开发 安全 Java
基于springboot+vue开发的会议预约管理系统
一个完整的会议预约管理系统,包含前端用户界面、管理后台和后端API服务。 ### 后端 - **框架**: Spring Boot 2.7.18 - **数据库**: MySQL 5.6+ - **ORM**: MyBatis Plus 3.5.3.1 - **安全**: Spring Security + JWT - **Java版本**: Java 11 ### 前端 - **框架**: Vue 3.3.4 - **UI组件**: Element Plus 2.3.8 - **构建工具**: Vite 4.4.5 - **状态管理**: Pinia 2.1.6 - **HTTP客户端
91 4
基于springboot+vue开发的会议预约管理系统
|
4月前
|
JavaScript 前端开发 Java
制造业ERP源码,工厂ERP管理系统,前端框架:Vue,后端框架:SpringBoot
这是一套基于SpringBoot+Vue技术栈开发的ERP企业管理系统,采用Java语言与vscode工具。系统涵盖采购/销售、出入库、生产、品质管理等功能,整合客户与供应商数据,支持在线协同和业务全流程管控。同时提供主数据管理、权限控制、工作流审批、报表自定义及打印、在线报表开发和自定义表单功能,助力企业实现高效自动化管理,并通过UniAPP实现移动端支持,满足多场景应用需求。
442 1
|
1月前
|
安全 算法 Java
在Spring Boot中应用Jasypt以加密配置信息。
通过以上步骤,可以在Spring Boot应用中有效地利用Jasypt对配置信息进行加密,这样即使配置文件被泄露,其中的敏感信息也不会直接暴露给攻击者。这是一种在不牺牲操作复杂度的情况下提升应用安全性的简便方法。
681 10
|
1月前
|
前端开发 JavaScript Java
基于springboot+vue开发的校园食堂评价系统【源码+sql+可运行】【50809】
本系统基于SpringBoot与Vue3开发,实现校园食堂评价功能。前台支持用户注册登录、食堂浏览、菜品查看及评价发布;后台提供食堂、菜品与评价管理模块,支持权限控制与数据维护。技术栈涵盖SpringBoot、MyBatisPlus、Vue3、ElementUI等,适配响应式布局,提供完整源码与数据库脚本,可直接运行部署。
81 0
基于springboot+vue开发的校园食堂评价系统【源码+sql+可运行】【50809】
|
2月前
|
人工智能 安全 Java
Spring Boot yml 配置敏感信息加密
本文介绍了如何在 Spring Boot 项目中使用 Jasypt 实现配置文件加密,包含添加依赖、配置密钥、生成加密值、在配置中使用加密值及验证步骤,并提供了注意事项,确保敏感信息的安全管理。
775 1
|
3月前
|
监控 数据可视化 JavaScript
springboot + vue的MES系统生产计划管理源码
MES系统(制造执行系统)的生产计划管理功能是其核心模块之一,涵盖生产计划制定与优化、调度排程、进度监控反馈、资源管理调配及可视化报告五大方面。系统基于SpringBoot + Vue-Element-Plus-Admin技术栈开发,支持多端应用(App、小程序、H5、后台)。通过实时数据采集与分析,MES助力企业优化生产流程,适用于现代化智能制造场景。
156 1
|
4月前
|
供应链 JavaScript BI
ERP系统源码,基于SpringBoot+Vue+ElementUI+UniAPP开发
这是一款专为小微企业打造的 SaaS ERP 管理系统,基于 SpringBoot+Vue+ElementUI+UniAPP 技术栈开发,帮助企业轻松上云。系统覆盖进销存、采购、销售、生产、财务、品质、OA 办公及 CRM 等核心功能,业务流程清晰且操作简便。支持二次开发与商用,提供自定义界面、审批流配置及灵活报表设计,助力企业高效管理与数字化转型。
446 2
ERP系统源码,基于SpringBoot+Vue+ElementUI+UniAPP开发
|
5月前
|
前端开发 Java 关系型数据库
基于Java+Springboot+Vue开发的鲜花商城管理系统源码+运行
基于Java+Springboot+Vue开发的鲜花商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的鲜花商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。技术学习共同进步
420 7
|
8月前
|
JavaScript Java 测试技术
基于SpringBoot+Vue实现的留守儿童爱心网站设计与实现(计算机毕设项目实战+源码+文档)
博主是一位全网粉丝超过100万的CSDN特邀作者、博客专家,专注于Java、Python、PHP等技术领域。提供SpringBoot、Vue、HTML、Uniapp、PHP、Python、NodeJS、爬虫、数据可视化等技术服务,涵盖免费选题、功能设计、开题报告、论文辅导、答辩PPT等。系统采用SpringBoot后端框架和Vue前端框架,确保高效开发与良好用户体验。所有代码由博主亲自开发,并提供全程录音录屏讲解服务,保障学习效果。欢迎点赞、收藏、关注、评论,获取更多精品案例源码。
|
8月前
|
JavaScript Java 测试技术
基于SpringBoot+Vue实现的家政服务管理平台设计与实现(计算机毕设项目实战+源码+文档)
面向大学生毕业选题、开题、任务书、程序设计开发、论文辅导提供一站式服务。主要服务:程序设计开发、代码修改、成品部署、支持定制、论文辅导,助力毕设!