【Vue】参数传递:如何同时传递 DTO 和 file 文件

news2024/11/18 10:36:46

日常开发时,如果遇到较为复杂的 DTO 对象的参数传递时,通常前端使用的请求头为:application/json(JSON 格式的数据);而后端可以使用 @RequestBody 接收一个 DTO 对象。但当需要在一个界面上同时传递 DTO 和附件文件时,这种方式就不行了。因为传递文件时请求头必须为:multipart/form-data,而后端就无法使用 @RequestBody 注解了。

我准备了如下格式的数据:

{
	name: "名称",
	vo: {
		name: "名称",
		remark: "备注"
	},
	voList: [
		{
			name: "名称1",
			remark: "备注1"
		},
		{
			name: "名称2",
			remark: "备注2"
		}
	]
}

上面的数据如果和文件同时传递,需要使用 multipart/form-data 请求头传递,并且得使用 FormDataappend 方法组装为下面的格式(下面内容是在 Chrome 的控制台中看到的格式):

name: 名称
vo.name: 名称
vo.remark: 备注
voList[0].name: 名称1
voList[0].remark: 备注1
voList[1].name: 名称2,
voList[1].remark: 备注2

axios 的处理

axios 的 create 方法中有一个 transformRequest 的属性,可以做参数请求前的处理:

import Axios from 'axios'

Axios.create({
    baseURL: '/api',
    headers: {
    	// 默认使用这个请求头
        'Content-Type': 'application/x-www-form-urlencoded'
    },
    transformRequest: [
        function (data: any, headers: any): any {
            if (headers[ 'Content-Type' ] === 'multipart/form-data') {
                // 这里需要处理数据
                if (data instanceof FormData) {
                    // FormData 的不需要处理
                    return data;
                } else {
                    // 将file对象之外的处理为 key=value的形式
                    const form = new FormData()
                    for (let key in data) {
                        if (data.hasOwnProperty(key)) {
                            handleValue(form, key, data);
                        }
                    }
                    return form
                }
            } else {
                return Qs.stringify(data, {
                    arrayFormat: 'comma'
                })
            }
        }
    ]
})

function handleValue(form: any, key: string | number, data: any, formKey?: string | number): void {
    let obj = data[key]
    if (obj === undefined) {
        return
    }
    if (typeof obj === 'object') {
        if (obj instanceof File) {
            // 如果是文件的话直接加到form中
            formKey = formKey ? formKey : key
            form.append(formKey, obj)
        } else if (obj.length !== undefined && obj.length > 0) {
            // 是一个数组
            // 继续循环处理for
            let length = obj.length
            for (let i = 0; i < length; i++) {
                handleValue(form, i, obj, key)
            }
        } else {
            // 是一个对象了
            formKey = formKey ? formKey + '[' + key + '].' : key + '.'
            for (let k in obj) {
                if (obj.hasOwnProperty(k)) {
                    form.append(formKey + k, obj[k])
                }
            }
        }
    } else {
        form.append(key, obj);
    }
}

SpringBoot Controller 类

这里就没有需要注意的地方了:

@PostMapping("upload_test")
public String test(DTO dto, MultipartFile[] files) {
	// 其他处理
	return "success";
}

配合使用

如何上面的前后端配合使用的话,前端调用 axios 的 post 方法时,按照如下使用即可:

<template>
    <div class="home">
        <input type="file" id="file"/>
        <br/><br/>
        <input type="button" value="上传" @click="click"/>
    </div>
</template>

<script lang="ts">
    import {defineComponent} from 'vue'
    import http from '../api/http'

    const data = {
        vo: {
            name: '名称',
            remark: '备注'
        },
        voList: [
            {
                name: '名称1',
                remark: '备注1'
            },
            {
                name: '名称2',
                remark: '备注2'
            }
        ]
    }

    export default defineComponent({
        name: 'HomeView',
        setup() {
            const click = () => {
                Object.assign(data, {
                    files: [
                        (document.getElementById('file') as HTMLInputElement)?.value,
                        (document.getElementById('file') as HTMLInputElement)?.value
                    ]
                })
                // ******************** 重点关注这里  ********************
                http.post('/test/upload_test', data, {
                    headers: {
                        'Content-Type': 'multipart/form-data'
                    }
                }).then(res => alert(res))
            }

            return {
                click
            }
        }
    });
</script>

效果图

放一张 gif 的效果图:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/338635.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java集合中的Map

MapMap接口键 值 对存储键不能重复&#xff0c;值可以重复Map三个实现类的存储结构HashMap&#xff1a;Hash表链表红黑树结构 线程不安全TreeMap&#xff1a; 底层红黑树实现HashTable&#xff1a;hash表链表红黑树 线程安全HashMapHashMap常用方法HashMap<String,String>…

[测开篇]设计测试用例的方法如何正确描述Bug

​ 文章目录为什么测试人员要写测试用例&#xff1f;怎样设计测试用例&#xff1f;&#xff08;总的方面&#xff09;1.基于需求设计测试用例&#xff08;总的方面&#xff09; 2.页面&#xff08;总的方面&#xff09; 3.非功能性测试&#xff08;具体方面&#xff09; 4.1 等…

「Python|环境安装|Windows」如何在Windows上安装Python环境?

本文主要介绍如何在Windows上安装Python&#xff0c;帮助初学者或者非程序员伙伴快速搭建可以运行python代码的环境。 文章目录安装python做一点小配置验证python如何安装指定版本的python编程语言的环境搭建一直是学习编程的第一道门槛。 对于如何在Linux系统上安装指定版本的…

谷歌蜘蛛池怎么搭建?Google蜘蛛池可以帮助谷歌排名吗?

本文主要分享关于谷歌蜘蛛池的搭建疑问&#xff0c;以及Google对谷歌排名的影响到底有多大。 本文由光算创作&#xff0c;有可能会被剽窃和修改&#xff0c;我们佛系对待这种行为吧。 谷歌蜘蛛池怎么搭建&#xff1f; 答案是&#xff1a;需要一个内链外链体系复杂的站群系统…

154、【动态规划】leetcode ——494. 目标和:回溯法+动态规划(C++版本)

题目描述 原题链接&#xff1a;494. 目标和 解题思路 &#xff08;1&#xff09;回溯法 本题的特点是nums中每个元素只能使用一次&#xff0c;分别试探加上nums[index]和减去nums[index]&#xff0c;然后递归的遍历下一个元素index 1。 class Solution { public:int res …

java中flatMap用法

java中map是把集合每个元素重新映射&#xff0c;元素个数不变&#xff0c;但是元素值发生了变化。而flatMap从字面上来说是压平这个映射&#xff0c;实际作用就是将每个元素进行一个一对多的拆分&#xff0c;细分成更小的单元&#xff0c;返回一个新的Stream流&#xff0c;新的…

1629_MIT_6.828_xv6_chapter1操作系统的组织

全部学习汇总&#xff1a;GreyZhang/g_unix: some basic learning about unix operating system. (github.com) 这一次整理一下操作系统组织相关的知识&#xff0c;主要还是xv6教学操作系统相关的知识。当然&#xff0c;很多知识在这类技术领域是通用的。 1. 操作系统的主要功能…

SAP ABAP Odata

GetEntity和GetEntitys GetEntitys 创建Odata Project 导入结构 选择需要的字段 设定Key 勾选字段的creatable、updatable、sortable、nullable、filterable属性值。 再依上述步骤创建ZPOITEM结构和实体集 3. 创建ZPOHEADER和ZPOITEM的Association 两个实体集的关联字段&…

RocketMQ-消息消费模式 顺序消费

RocketMQ-消息消费模式 顺序消费RocketMQ-消息消费模式集群模式集群模式的演示(本身就默认)Rocketmq存储队列广播模式顺序消费如何改实现顺序消费RocketMQ-消息消费模式 集群模式 在消费模式为集群的情况下,如果机器是集群的,消息只会给集群中的其中一台机器消费到 集群模…

【数据结构】双向链表的模拟实现(无头)

目录 前言&#xff1a; 1、认识双向链表中的结点 2、认识并创建无头双向链表 3、实现双向链表当中的一些方法 3.1、遍历输出方法&#xff08;display&#xff09; 3.2、得到链表的长度&#xff08;size&#xff09; 3.3、查找关键字key是否包含在双链表中(contains) 3.…

基于I2S通讯MAX98357模块的JetsonNano声音外放

前言有很多方法可以为 Jetson 设备添加音频功能。USB 扬声器和USB 麦克风是一种简单的解决方案&#xff0c;但它们确实占用了宝贵的 USB 插槽&#xff0c;这些插槽可能更适合用于键盘、蓝牙功能、Internet Keys 和其他配件。在 Jetson 设备上&#xff0c;NVIDIA 通过 40 针 GPI…

微软发布会精华回顾:“台式电脑”抢了风头

Lightbot北京时间2016年10月26日晚10点&#xff0c;微软在纽约发布了名为 Surface Studio 的一体机、名为 Surface Dial 的配件以及外观未变的顶配版 Surface Book。同时&#xff0c;微软宣布了 Windows 10 下一个重要版本——“Creators Update”的数项新功能&#xff0c;包括…

【Linux】冯诺依曼体系结构和操作系统概念

文章目录&#x1f3aa; 冯诺依曼体系结构&#x1f680;1.体系概述&#x1f680;2.CPU和内存的数据交换&#x1f680;3.体系结构中数据的流动&#x1f3aa; 操作系统概念理解&#x1f680;1.简述&#x1f680;2.设计目的&#x1f680;3.定位&#x1f680;4.理解&#x1f680;5.管…

AOP面向切面编程思想。

目录 一、AOP工作流程 1、基本概念 2、AOP工作流程 二、AOP核心配置 1、AOP切入点表达式 2、AOP通知类型 三、AOP通知获取数据 1、获取参数 2、获取返回值 3、获取异常 四、AOP事务管理 1、Spring事务简介 2、Spring事务角色 3、事务属性 一、AOP工作流程 1、…

Linux内核启动(理论,0.11版本)分段与分页

为什么要虚拟内存 我们知道&#xff0c;在之前上微机原理时&#xff0c;我们的程序是可以直接访问内存的&#xff0c;而且访问的是直接的物理内存&#xff0c;在实模式下&#xff0c;寄存器是16位的&#xff0c;数组总线&#xff08;data bus&#xff09;是16位的&#xff0c;…

设计模式-值类型与引用类型、深拷贝与浅拷贝、原型模式详解

一. 值类型和引用类型 1. 前言 (1). 分类 值类型包括&#xff1a;布尔类型、浮点类型(float、double、decimal、byte)、字符类型(char)、整型&#xff08;int、long、short等&#xff09;、枚举(entum)、结构体(struct)。 引用类型&#xff1a;数组、字符串(string)、类、接口…

DamiCMS SQL注入分析

2023年将会持续于B站、CSDN等各大平台更新&#xff0c;可加入粉丝群与博主交流:838681355&#xff0c;为了老板大G共同努力。 一、入口文件(单入口文件模式) 看一下Index.php文件代码&#xff1a;引入了php_safe.php文件 查看一下php_safe.php防御文件&#xff1a; 对变量e…

2019_41 考研408

2019年(单链表)41.(13分)设线性表采用带头结点的单链表保存&#xff0c;链表中的结点定义如下:typedef struct node {int data;struct node* next;}NODE;请设计一个空间复杂度为O(1)且时间上尽可能高效的算法&#xff0c;重新排列L中的各结点&#xff0c;得到线性表L(q,a,,a,an…

【正则表达式】获取html代码文本内所有<script>标签内容

文章目录一. 背景二. 思路与过程1. 正则表达式中需要限定<script>开头与结尾2. 增加标签格式的限定3. 不限制<script>首尾的内部内容4. 中间的内容不能出现闭合的情况三. 结果与代码四. 正则辅助工具一. 背景 之前要对学生提交的html代码进行检查&#xff0c;在获…

牛客小白月赛66

牛客小白月赛66_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ (nowcoder.com)冒着期末挂科的风险打了打&#xff0c;缓解了一下网瘾&#xff0c;感觉还行最近为了期末鸽了很多期的div3&#xff0c;一学期末就手痒想训&#xff0c;感觉再不打人要没了&#xff0c;结果…