spring boot项目同时传递参数和文件的多种方式

2023-11-18

在开发接口中,遇到了需要同时接收参数和文件的情况,可以有多种方式实现文件+参数的接收,这里基于spring boot 3 + vue 3 + axios,做一个简单的代码演示。

1 简单参数 + 文件参数

参数较少时,比较方便,直接参数接受即可

1.1 后端接口

@RestController
@RequestMapping("/param")
@Validated
public class FileParamController extends BaseController {
    /**
     * 简单参数
     *
     * @param test1
     * @param test2
     * @param file
     * @return
     */
    @PostMapping("/file-simple-param")
    public Map<String, Object> fileAndSimpleParam(@RequestParam @NotBlank String test1,
                                                  @RequestParam @NotBlank String test2,
                                                  @RequestParam MultipartFile file) {
        Map<String, Object> objectMap = new HashMap<>();
        objectMap.put("test1", test1);
        objectMap.put("test2", test2);
        objectMap.put("fileName", file.getOriginalFilename());
        return objectMap;
    }
}

1.2 前端请求

const fileAndSimpleParamFuc = (methodParam: { file: string | Blob }) => {
	let formData = new FormData()
	formData.append('test1', 'test1')
	formData.append('test2', 'test2')
	formData.append('file', methodParam.file)
	fileAndSimpleParam(formData).then(resp => {
		console.log(resp)
	})
}

fileAndSimpleParam 为封装的api请求方法,可查看下文的 param.ts

2 简单参数转JavaBean + 文件参数

将各个参数封装到一个JavaBean中接收,同时接收文件参数,此时JavaBean参数不加任何注解,不支持接收List参数

2.1 后端接口

@RestController
@RequestMapping("/param")
@Validated
public class FileParamController extends BaseController {
    /**
     * 简单参数转JavaBean接收,不支持如:LIst<xxx> 这样的属性
     *
     * @param bean
     * @param file
     * @return
     */
    @PostMapping("/file-simple-bean")
    public SimpleBean fileAndSimpleJavaBean(@Validated SimpleBean bean, @RequestParam MultipartFile file) {
        bean.setFileName(file.getOriginalFilename());
        return bean;
    }
}

SimpleBean.java

@Data
public class SimpleBean {
    @NotBlank
    private String test1;

    @NotBlank
    private String test2;
    
    @Null(message = "The fileName is not support to be used")
    private String fileName;
}

2.2 前端请求

const fileAndSimpleJavaBeanFuc = (methodParam: { file: string | Blob }) => {
	let formData = new FormData()
	formData.append('test1', 'test1')
	formData.append('test2', 'test2')
	formData.append('file', methodParam.file)
	fileAndSimpleJavaBean(formData).then(resp => {
		console.log(resp)
	})
}

fileAndSimpleJavaBean 为封装的api请求方法,可查看下文的 param.ts

3 简单参数转String + 文件参数

在这种接收方式中,使用String来接收参数,在使用工具(如fastjson)手动转为JavaBean,支持接收List参数,但是需要自行校验参数是否满足要求

3.1 后端接口

@RestController
@RequestMapping("/param")
@Validated
public class FileParamController extends BaseController {
    /**
     * 参数转字符串接收,支持复杂参数属性,如:List<xxx>
     *
     * @param bean
     * @param file
     * @return
     */
    @PostMapping("/file-and-json")
    public SimpleBean fileAndJsonJavaBean(String bean, @RequestParam MultipartFile file) {
        SimpleBean simpleBean = JSON.parseObject(bean, SimpleBean.class);
        //自定义参数校验
        List<String> valid = ValidatorUtils.validFast(simpleBean);
        if (!valid.isEmpty()) {
            throw new FailException(String.join(",", valid));
        }
        simpleBean.setFileName(file.getOriginalFilename());
        return simpleBean;
    }
}

SimpleBean.java

@Data
public class SimpleBean {
    @NotBlank
    private String test1;

    @NotBlank
    private String test2;

    private List<ParamBO> params;

    @Null(message = "The fileName is not support to be used")
    private String fileName;
}

ValidatorUtils.java

借助spring的参数校验做自定义调用

public class ValidatorUtils {
    private static final Validator VALIDATOR_FAST = Validation.byProvider(HibernateValidator.class).configure().failFast(true).buildValidatorFactory().getValidator();
    private static final Validator VALIDATOR_ALL = Validation.byProvider(HibernateValidator.class).configure().failFast(false).buildValidatorFactory().getValidator();

    private ValidatorUtils(){}

    /**
     * 参数校验,遇到第一个不合法的字段直接返回不合法字段,后续字段不再校验
     *
     * @param object
     * @return
     * @param <T>
     */
    public static <T> List<String> validFast(T object, Class<?>... groups){
        return valid(VALIDATOR_FAST, object, groups);
    }

    /**
     * 校验所有字段并返回不合法字段
     *
     * @param object
     * @return
     * @param <T>
     */
    public static <T> List<String> validAll(T object, Class<?>... groups){
        return valid(VALIDATOR_ALL, object, groups);
    }

    private static <T> List<String> valid(Validator validator, T object, Class<?>... groups){
        Set<ConstraintViolation<T>> errors = validator.validate(object, groups);
        return errors.stream().map(ConstraintViolation::getMessage).toList();
    }
}

3.2 前端请求

const fileAndJsonStringToJavaBeanFuc = (methodParam: { file: string | Blob }) => {
	let paramList = []
	for (let i = 0; i < 3; i++) {
		let param = { username: '参数' + i, data: '参数值' + i }
		paramList.push(param)
	}
	let data = {
		test1: 'test1',
		test2: 'test2',
		params: paramList
	}
	let formData = new FormData()
	formData.append('bean', JSON.stringify(data))
	formData.append('file', methodParam.file)
	fileAndJsonStringToJavaBean(formData).then(resp => {
		console.log(resp)
	})
}

fileAndJsonStringToJavaBean 为封装的api请求方法,可查看下文的 param.ts

4 文件放入JavaBean接收

将文件作为JavaBean的属性,随参数一起接收

4.1 后端接口

@RestController
@RequestMapping("/param")
@Validated
public class FileParamController extends BaseController {
    /**
     * 文件放入JavaBean一起提交
     *
     * @param bean
     * @return
     */
    @PostMapping(value = "/file-in-bean")
    public String fileInJavaBean(@Validated FileInBeanBO bean) {
        bean.setFileName(bean.getFile().getOriginalFilename());
        return bean.getFile().getOriginalFilename();
    }
}

FileInBeanBO.java

@Data
public class SimpleBean {
    @NotBlank
    private String test1;

    @NotBlank
    private String test2;

    @Null(message = "The fileName is not support to be used")
    private String fileName;

    private MultipartFile file;
}

4.2 前端请求

此处需要特别注意,需要修改Content-Type

const fileInJavaBeanFuc = (methodParam: { file: string | Blob }) => {
	let formData = new FormData()
	formData.append('test1', 'test1')
	formData.append('test2', 'test2')
	formData.append('file', methodParam.file)
	fileInJavaBean(formData).then(resp => {
		console.log(resp)
	})
}

fileInJavaBean 为封装的api请求方法,可查看下文的 param.ts

5 文件和参数分别接收,@RequestPart注解

使用@RequestPart注解,实现参数与文件分别接收,应该来说是最优解,优先推荐

5.1 后端接口

@RestController
@RequestMapping("/param")
@Validated
public class FileParamController extends BaseController {
    /**
     * 参数与文件分开接收,支持复杂参数属性,如:List<xxx>
     *
     * @param bean
     * @param file
     * @return
     */
    @PostMapping("/file-and-bean")
    public FileBeanBO fileAndJavaBean(@RequestPart @Validated FileBeanBO bean, @RequestPart MultipartFile[] file) {
        String collect = Arrays.stream(file).map(MultipartFile::getOriginalFilename).collect(Collectors.joining(","));
        bean.setFileName(collect);
        return bean;
    }
}

FileBeanBO.java

@Data
public class SimpleBean {
    @NotBlank
    private String username;

    @Valid
    @NotEmpty
    private List<ParamBO> params;

    @Null(message = "The fileName is not support to be used")
    private String fileName;
    
    @Data
    public class ParamBO {
        private String username;
        private Object data;
    }
}

5.2 前端请求

此处需要特别注意,需要手动指定JavaBean的类型 Content-Type

const fileAndJavaBeanFuc = (methodParam: { file: string | Blob }) => {
	let formData = new FormData()
	let paramList = []
	for (let i = 0; i < 3; i++) {
		let param = { username: '参数' + i, data: '参数值' + i }
		paramList.push(param)
	}
	let data = {
		username: '张三',
		params: paramList
	}
	formData.append('bean', new Blob([JSON.stringify(data)], { type: 'application/json' }))
	formData.append('file', methodParam.file)
	fileAndJavaBean(formData).then(resp => {
		console.log(resp)
	})
}

fileAndJavaBean 为封装的api请求方法,可查看下文的 param.ts

6 前端封装 param.ts

export const fileAndSimpleParam = (params: any) => {
	return axios.post('/param/file-simple-param', params)
}

export const fileAndSimpleJavaBean = (params: any) => {
	return axios.post('/param/file-simple-bean', params)
}

export const fileAndJsonStringToJavaBean = (params: any) => {
	return axios.post('/param/file-and-json', params)
}

export const fileInJavaBean = (params: any) => {
	return axios.post('/param/file-in-bean', params, {
		headers: {
			'Content-Type': 'multipart/form-data'
		}
	})
}

export const fileAndJavaBean = (params: any) => {
	return axios.post('/param/file-and-bean', params)
}

7 后记

以上5种方式,都能实现参数与文件同时接受,至于使用哪一种,看具体需求,参数太多的时候,可以优先考虑@RequestPart注解。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

spring boot项目同时传递参数和文件的多种方式 的相关文章

  • 38个MySQL数据库的小技巧

    1 如何快速掌握MySQL 培养兴趣 兴趣是最好的老师 不论学习什么知识 兴趣都可以极大地提高学习效率 当然学习MySQL 5 6也不例外 夯实基础 计算机领域的技术非常强调基础 刚开始学习可能还认识不到这一点 随着技术应用的深 入 只有有
  • java之MySQL数据库

    MySQL数据库 1 什么是数据库 答 数据库是以一定方式存储在一起 能予多个用户共享 具有尽可能小的冗余度 与应用程序彼此独立的数据集合 2 数据库的分类 具体含义 常见的数据库 答 关系型数据库和非关系型数据库 关系数据库 是建立在关系
  • springCloud - 第10篇 - 服务间调用追踪 (zipkin 的使用)

    前些天发现了一个巨牛的人工智能学习网站 通俗易懂 风趣幽默 忍不住分享一下给大家 点击跳转到教程 一 在微服务系统中 不同应用服务可能会有各种不同的相互调用 springcloud 集成了 zipkin 来实现对于不同服务调用的追踪和统计

随机推荐

  • LIBSVM 使用

    预备 NTU TW Chih Chung Chang and Chih Jen Lin LIBSVM LIBSVM Data Classification Regression and Multi label 正文 a 编译libsvm u
  • 【机器学习】决策树 No.3

    1 决策树之信息论基础 决策树思想来源非常朴素 程序设计中的条件分支结构 if else 最早的决策树就是利用这类结构分割数据的一种分类学习方法 例 银行贷款例子 使用决策树划分是否贷款 此处特征为两个 房子 工作 香农 信息论创始人 19
  • 一文带你了解ES6迭代器(iterator)

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 一 迭代器 iterator 是什么 二 工作原理 总结 一 迭代器 iterator 是什么 迭代器 iterator 是一种接口 为各种不同的数据结构提供统一的
  • SkipList(跳表)

    跳表简介 跳表是基于有序链表实现的搜索结构 是一种动态的搜索结构 即支持动态插入和删除操作 且跳表查找和删除的平均时间复杂度是Olog n 因此跳表是一种时间复杂度相对较小的搜索结构 我们知道对一个数据集合的查找 最差的时间复杂度是O n
  • Switch / Xbox / PS / PSV / PSP 游戏指南

    1 Switch Xbox PS PSV PSP 对比分析 table 1 PSV2000 1000 比较分析 PSV2000 相对 PSV1000 具体变更点 薄了20 轻了15 屏幕改为液晶屏 PS键 开始键和选择键变成球形更方便按 内
  • 2,一个人体姿态识别的项目实现

    学习opencv的例子 1 认识 2 start 直接干货 例子1 例子2 例子3 例子4 例子5 固定阈值 自适应阈值 文档说明 参考链接 http codec wang opencv start 02 basic element ima
  • git仓库创建及上传

    如何创建一个git仓库并上传代码 1 在此之前我们需要安装git和注册gitee账号 1 打开git官网下载安装程序 然后按照指令进行安装即可 2 搜索gitee进行注册和绑定邮箱即可 上传代码时需要登录gitee账号 安装成功之后告诉本地
  • Android apk 反编译解析

    学习android开发 有必要对android的反编译有所了解 当然学习android反编译并不是为了破解别人的软件 完全是一种学习的方法 了解别人写程序的思想是一件很有趣的事情 工具下载地址 http code google com p
  • androidstudio开发!花三分钟看完这篇文章你就懂了!技术详细介绍

    阿里面试 自我介绍 首先要介绍自己的项目经验和个人的擅长点 因为面试官主要考察你的表达能力和语言精简能力 简历的编写其实这里可能需要注意几点 1 标题的直接按照姓名 几年工作经验 应聘岗位格式来填写 例如 黄铭 四年工作经验 Android
  • STP与RSTP区别

    STP 不能快速迁移 即使是在点对点链路或边缘端口 边缘端口指的是该端口直接与用户终端相连 而没有连接到其它设备或共享网段上 也必须等待2 倍的ForwardDelay 的时间延迟 端口才能迁移到转发状态 RSTP Rapid Spanni
  • Python 异步: 异步上下文管理器(17)

    动动发财的小手 点个赞吧 上下文管理器是一种 Python 构造 它提供了一个类似 try finally 的环境 具有一致的接口和方便的语法 例如通过 with 表达 它通常与资源一起使用 确保在我们完成资源后始终关闭或释放资源 无论资源
  • VC++ OpenCV+ZBar二维码识别

    利用OpenCV处理图像的优势 结合ZBar提高二维码识别结果 接口定义 include
  • SpringSecurity配置类--常用配置

    SpringSecurity配置类 在学习这门课的时候 实现各种功能时进行了各种配置 我想将各种配置综合讲述一下 首先自定义配置类 需要继承WebSecurityConfigurerAdapter这个类 在这个类里面做了一些默认配置 Con
  • linux grpc,grpc linux下的编译使用-Go语言中文社区

    1 一些工具安装 apt get install build essential autoconf libtool pkg config apt get install libgflags dev libgtest dev apt get
  • [转]IDEA 撤销 merge 操作(详解)

    目录 一 前言 二 解决方案 通过 Git Bash 命令行解决 1 合并过程中未发生冲突 2 合并过程中发生冲突 三 解决方案 通过 IDEA 解决 附带详细的操作图 1 合并过程中未发生冲突 2 合并过程中发生冲突 四 最后 作为一个开
  • 自己制作的 macOS Mojave 10.15.3 iso 文件,亲测可用(附 VMware15 安装 macOS Catalina 图文教程与 macO Catalina.iso 镜像下载地址)

    注 如果需要分享此资源 请注明原作者 不要把别人的东西当做自己的成果 也不要把别人免费分享出来的东西以有偿的方式去分享 自己制作的 macOS Mojave 10 15 3 iso 文件 亲测可用 已在 VMware 15 5 Player
  • AOSP 预置APP安装 以MicroG GmsCore.apk安装为例

    AOSP 预置APP 以MicroG为例 MicroG 无root安装教程 通过源码修改打开签名欺骗 预置不带源码的APP 其他 AOSP 安装谷歌三件套失败 开始寻找代替方案 尝试使用MicroG项目代替谷歌服务 目前情况 已成功安装 所
  • 第十八节 多核异构核间通信–ipcc

    由于MP157 是一款多核异构的芯片 其中既包含的高性能的A7 核及实时性强的M4 内核 那么这两种处理器在工作时 怎么互相协调配合呢 这就涉及到了核间通信的概念了 IPCC inter processor communication co
  • 【医学影像数据处理】2D/3D patch的crop和merge操作汇总

    在做3D分割任务中 多数的方法多采用整体缩放 或裁剪成一个个小的patch操作 这样做的一个主要原因是内存问题 相较于整体缩放 采用裁剪成patch的方法 对于小目标会更加的鲁棒 这也是大多数3D分割任务中常选取的方式 尤其是针对医学影像的
  • spring boot项目同时传递参数和文件的多种方式

    在开发接口中 遇到了需要同时接收参数和文件的情况 可以有多种方式实现文件 参数的接收 这里基于spring boot 3 vue 3 axios 做一个简单的代码演示 1 简单参数 文件参数 参数较少时 比较方便 直接参数接受即可 1 1