【前后端】前端向后端传递文件参数并携带其他参数

Untilseeu. 2024-08-27 10:03:04 阅读 91

一、问题背景

       最近在进行某实训,我们的选题涉及到了上传文件的问题,并且在上传文件的同时还要携带其他相关的参数。以我们所做的系统为例:某公司购入一台新车,该车在录入系统时,我们需要向后端上传车辆的图片,同时还需要传递车牌号、车型、座位数这些参数。那么我们如何将文件参数以及其他参数一同传递给后端。经过查阅,作者找到了一种解决办法。

二、问题解决

1.前端如何将用户上传的图片作为参数传递给后端?

       此处我使用的是ElementUI中的上传文件组件Upload,该组件的原始代码如下:

<code><el-upload

class="avatar-uploader"code>

action="https://jsonplaceholder.typicode.com/posts/"code>

:show-file-list="false"code>

:on-success="handleAvatarSuccess"code>

:before-upload="beforeAvatarUpload">code>

<img v-if="imageUrl" :src="imageUrl" class="avatar">code>

<i v-else class="el-icon-plus avatar-uploader-icon"></i>code>

</el-upload>

       可以看到这其中有一些事件处理函数,如on-success、before-upload,而我这里没有使用这些函数,而是在其中添加了一个on-change的事件处理函数,这个函数会在用户选择文件或上传文件时被调用,传递相关参数和数据,允许你在处理上传文件的过程中执行一些自定义逻辑。我为其绑定了一个名为handleAddCarChange的函数,修改后的Upload组件代码如下:

<el-upload

:show-file-list="false"code>

:on-change = "handleAddCarChange"//on-change事件处理函数

:auto-upload="false"code>

<img v-if="carManagementData.addCarInfoForm.photoPath" code>

:src="carManagementData.addCarInfoForm.photoPath" code>

:fit="scale-down" style="width:200px;height:200px;">code>

<i v-else class="el-icon-plus avatar-uploader-icon" ></i>code>

</el-upload>

       当我们上传文件后,就会触发其中的handleAddCarChange函数,在handleAddCarChange函数的参数列表中,我们添加一个file参数,这个参数就是我们上传文件后的文件参数。handleAddCa rChange函数如下:

handleAddCarChange(file) {

this.carManagementData.addCarInfoForm.photoPath = URL.createObjectURL(file.raw);//赋值图片的url,用于图片回显功能

this.carManagementData.addCarInfoForm.photoFile = file;//将file赋值给我们之前定义的某一个对象

return true;

}

       在这个函数中,我们首先将上传的图片文件进行了回显,然后将file赋值给我们之前已经定义过的一个变量,这样我们就获得了这个文件参数,后续就可以将file作为参数传递给后端。 

2.前端以什么形式将文件参数传递给后端?

       以Axios为例,如果我们使用一般的对象或者参数形式是无法实现文件传递的,必须使用FormData的形式来实现。FormData 是一个用于在 JavaScript 中创建和管理表单数据的 API。它提供了一种方便的方式来构建、序列化和发送包含文件和键值对的表单数据。使用 FormData,我们可以通过一些内置方法来添加键值对或文件数据,最终将整个FormData传递给后端。

       在上一节中,我们已经得到了文件参数file,这里我们首先判断file是否为空,如果不为空,则将this.file.raw添加到formdata中,并将键命名为file。这里有几点需要注意:

(1)一定要使用this.xxx。这是易错点。

(2)一定要使用file.raw,因为file.raw中才是真正的文件参数。

(3)键值对中的键的命名取决于你后端接收这个文件参数时使用的名字。

       相关代码如下:

let formdata = new FormData();

if(this.carManagementData.editCarInfoForm.photoFile != null){

formdata.append("file", this.file.raw);

}

        如果我们还需要传递其他参数怎么办?

        为了方便传参以及后端接收参数,我将其他参数封装成一个对象。首先创建一个新对象,将我们需要像后端传递的参数都放在这个对象中。例如:

const uploadForm = {

data: {

plateNumber:this.carManagementData.editCarInfoForm.plateNumber,

model:this.carManagementData.editCarInfoForm.carType,

fuel:this.carManagementData.editCarInfoForm.fuel,

seatNumber:this.carManagementData.editCarInfoForm.seatNumber,

}

}

       这里我把我需要传给后端的参数都放在了uploadForm这个对象中了。但是现在,我们不能直接将此对象放在FormData中,而是先需要进行一番如下的转换,然后再将其添加到前面的formdata中:

const jsonStr = JSON.stringify(uploadForm.data);

const blob = new Blob([jsonStr],{

type: 'application/json'

});

formdata.append("addCarInfoForm",blob);

       首先,通过 JSON.stringify(uploadForm.data) 将 uploadForm.data 这个 JSON 对象转换为 JSON 字符串。这个 JSON 字符串表示了一个包含表单数据的对象。

       然后,通过 new Blob([jsonStr], { type: 'application/json' }) 创建一个 Blob 对象。Blob 是二进制数据的容器,它可以包含不同类型的数据,并且通过设置 type 属性指定了这个 Blob 对象的 MIME 类型,这里类型为 application/json。

       最后,通过 formdata.append("addCarInfoForm", blob) 将这个 Blob 对象添加到 FormData 中。

完成上述步骤之后,我们就可以使用Axios发送请求了,如下图所示:

 3.后端如何来接收?

       后端可以使用@RequestParam注解来接收文件参数。但是,如果我们使用@RequestBody注解来接收我们传递的对象参数时,发现其传过来的值输出后都为null,但是我们验证之后发现前端确实成功传递了这个对象参数。因此,这里我们要使用@RequestPart注解来接收前端传过来的对象参数,这样就能够成功接收了。具体代码如下:

<code>@PostMapping(value = "/addCar")

public Result addCar(HttpServletRequest request, @RequestParam(value = "file",required = false)MultipartFile multipartFile, @RequestPart AddCarInfoForm addCarInfoForm) {

if (addCarInfoForm == null)

{//缺少参数

throw MyException.MissParamsError();//抛出异常

}

carInfoService.addCarService(addCarInfoForm,multipartFile);//调用服务层

return Result.success();

}

三、总结

      在实训期间,我也是被这个问题困扰了一段时间,希望以上解决方案能够帮到大家,当然,如果有更不错的方法,也请批评指正!



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。