一、问题背景
最近在进行某实训,我们的选题涉及到了上传文件的问题,并且在上传文件的同时还要携带其他相关的参数。以我们所做的系统为例:某公司购入一台新车,该车在录入系统时,我们需要向后端上传车辆的图片,同时还需要传递车牌号、车型、座位数这些参数。那么我们如何将文件参数以及其他参数一同传递给后端。经过查阅,作者找到了一种解决办法。
二、问题解决
1.前端如何将用户上传的图片作为参数传递给后端?
此处我使用的是ElementUI中的上传文件组件Upload,该组件的原始代码如下:
<el-upload
class="avatar-uploader"
action="https://jsonplaceholder.typicode.com/posts/"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload">
<img v-if="imageUrl" :src="imageUrl" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
可以看到这其中有一些事件处理函数,如on-success、before-upload,而我这里没有使用这些函数,而是在其中添加了一个on-change的事件处理函数,这个函数会在用户选择文件或上传文件时被调用,传递相关参数和数据,允许你在处理上传文件的过程中执行一些自定义逻辑。我为其绑定了一个名为handleAddCarChange的函数,修改后的Upload组件代码如下:
<el-upload
:show-file-list="false"
:on-change = "handleAddCarChange"//on-change事件处理函数
:auto-upload="false"
<img v-if="carManagementData.addCarInfoForm.photoPath"
:src="carManagementData.addCarInfoForm.photoPath"
:fit="scale-down" style="width:200px;height:200px;">
<i v-else class="el-icon-plus avatar-uploader-icon" ></i>
</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注解来接收前端传过来的对象参数,这样就能够成功接收了。具体代码如下:
@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();
}
三、总结
在实训期间,我也是被这个问题困扰了一段时间,希望以上解决方案能够帮到大家,当然,如果有更不错的方法,也请批评指正!
本文转载自: https://blog.csdn.net/qq_64805688/article/details/135930916
版权归原作者 Untilseeu. 所有, 如有侵权,请联系我们删除。
版权归原作者 Untilseeu. 所有, 如有侵权,请联系我们删除。