在开发接口中,遇到了需要同时接收参数和文件的情况,可以有多种方式实现文件+参数的接收,这里基于spring boot 3 + vue 3 + axios,做一个简单的代码演示。
1 简单参数 + 文件参数
参数较少时,比较方便,直接参数接受即可
1.1 后端接口
@RestController@RequestMapping("/param")@ValidatedpublicclassFileParamControllerextendsBaseController{/**
* 简单参数
*
* @param test1
* @param test2
* @param file
* @return
*/@PostMapping("/file-simple-param")publicMap<String,Object>fileAndSimpleParam(@RequestParam@NotBlankString test1,@RequestParam@NotBlankString test2,@RequestParamMultipartFile file){Map<String,Object> objectMap =newHashMap<>();
objectMap.put("test1", test1);
objectMap.put("test2", test2);
objectMap.put("fileName", file.getOriginalFilename());return objectMap;}}
1.2 前端请求
constfileAndSimpleParamFuc=(methodParam:{ file:string| Blob })=>{let formData =newFormData()
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")@ValidatedpublicclassFileParamControllerextendsBaseController{/**
* 简单参数转JavaBean接收,不支持如:LIst<xxx> 这样的属性
*
* @param bean
* @param file
* @return
*/@PostMapping("/file-simple-bean")publicSimpleBeanfileAndSimpleJavaBean(@ValidatedSimpleBean bean,@RequestParamMultipartFile file){
bean.setFileName(file.getOriginalFilename());return bean;}}
SimpleBean.java
@DatapublicclassSimpleBean{@NotBlankprivateString test1;@NotBlankprivateString test2;@Null(message ="The fileName is not support to be used")privateString fileName;}
2.2 前端请求
constfileAndSimpleJavaBeanFuc=(methodParam:{ file:string| Blob })=>{let formData =newFormData()
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")@ValidatedpublicclassFileParamControllerextendsBaseController{/**
* 参数转字符串接收,支持复杂参数属性,如:List<xxx>
*
* @param bean
* @param file
* @return
*/@PostMapping("/file-and-json")publicSimpleBeanfileAndJsonJavaBean(String bean,@RequestParamMultipartFile file){SimpleBean simpleBean = JSON.parseObject(bean,SimpleBean.class);//自定义参数校验List<String> valid =ValidatorUtils.validFast(simpleBean);if(!valid.isEmpty()){thrownewFailException(String.join(",", valid));}
simpleBean.setFileName(file.getOriginalFilename());return simpleBean;}}
SimpleBean.java
@DatapublicclassSimpleBean{@NotBlankprivateString test1;@NotBlankprivateString test2;privateList<ParamBO> params;@Null(message ="The fileName is not support to be used")privateString fileName;}
ValidatorUtils.java
借助spring的参数校验做自定义调用
publicclassValidatorUtils{privatestaticfinalValidator VALIDATOR_FAST =Validation.byProvider(HibernateValidator.class).configure().failFast(true).buildValidatorFactory().getValidator();privatestaticfinalValidator VALIDATOR_ALL =Validation.byProvider(HibernateValidator.class).configure().failFast(false).buildValidatorFactory().getValidator();privateValidatorUtils(){}/**
* 参数校验,遇到第一个不合法的字段直接返回不合法字段,后续字段不再校验
*
* @param object
* @return
* @param <T>
*/publicstatic<T>List<String>validFast(T object,Class<?>... groups){returnvalid(VALIDATOR_FAST, object, groups);}/**
* 校验所有字段并返回不合法字段
*
* @param object
* @return
* @param <T>
*/publicstatic<T>List<String>validAll(T object,Class<?>... groups){returnvalid(VALIDATOR_ALL, object, groups);}privatestatic<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 前端请求
constfileAndJsonStringToJavaBeanFuc=(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 =newFormData()
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")@ValidatedpublicclassFileParamControllerextendsBaseController{/**
* 文件放入JavaBean一起提交
*
* @param bean
* @return
*/@PostMapping(value ="/file-in-bean")publicStringfileInJavaBean(@ValidatedFileInBeanBO bean){
bean.setFileName(bean.getFile().getOriginalFilename());return bean.getFile().getOriginalFilename();}}
FileInBeanBO.java
@DatapublicclassSimpleBean{@NotBlankprivateString test1;@NotBlankprivateString test2;@Null(message ="The fileName is not support to be used")privateString fileName;privateMultipartFile file;}
4.2 前端请求
此处需要特别注意,需要修改Content-Type
constfileInJavaBeanFuc=(methodParam:{ file:string| Blob })=>{let formData =newFormData()
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")@ValidatedpublicclassFileParamControllerextendsBaseController{/**
* 参数与文件分开接收,支持复杂参数属性,如:List<xxx>
*
* @param bean
* @param file
* @return
*/@PostMapping("/file-and-bean")publicFileBeanBOfileAndJavaBean(@RequestPart@ValidatedFileBeanBO bean,@RequestPartMultipartFile[] file){String collect =Arrays.stream(file).map(MultipartFile::getOriginalFilename).collect(Collectors.joining(","));
bean.setFileName(collect);return bean;}}
FileBeanBO.java
@DatapublicclassSimpleBean{@NotBlankprivateString username;@Valid@NotEmptyprivateList<ParamBO> params;@Null(message ="The fileName is not support to be used")privateString fileName;@DatapublicclassParamBO{privateString username;privateObject data;}}
5.2 前端请求
此处需要特别注意,需要手动指定JavaBean的类型 Content-Type
constfileAndJavaBeanFuc=(methodParam:{ file:string| Blob })=>{let formData =newFormData()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',newBlob([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
exportconstfileAndSimpleParam=(params:any)=>{return axios.post('/param/file-simple-param', params)}exportconstfileAndSimpleJavaBean=(params:any)=>{return axios.post('/param/file-simple-bean', params)}exportconstfileAndJsonStringToJavaBean=(params:any)=>{return axios.post('/param/file-and-json', params)}exportconstfileInJavaBean=(params:any)=>{return axios.post('/param/file-in-bean', params,{
headers:{'Content-Type':'multipart/form-data'}})}exportconstfileAndJavaBean=(params:any)=>{return axios.post('/param/file-and-bean', params)}
7 后记
以上5种方式,都能实现参数与文件同时接受,至于使用哪一种,看具体需求,参数太多的时候,可以优先考虑@RequestPart注解。
版权归原作者 kangaroo. 所有, 如有侵权,请联系我们删除。