好久好久没写博客了,记一次不留意的惨痛教训,白白浪费一整个下午的时间。
1. 问题描述:
前端是iview+vue写的页面(这个不重要,都一样),然后引入了上传附件的这么一个功能,正常上传附件是可以的,当不选择任何文件的时候,点击保存直接报错,前台没有任何报错,方法也都走了,确定走到了后台但是后台没有任何反应,不仔细看也没有任何反应,经东东同事提醒,发现控制台有1行报错信息,还是正常的文本样色,不注意一定看不到,我就是这么忽略了,导致走了很多弯路。
2. 报错信息:
2020-02-28 19:46:00.383 WARN 1320 --- [nio-9906-exec-9] .m.m.a.ExceptionHandlerExceptionResolver : Resolved exception caused by handler execution: org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'zkdgwhEntity' on field 'kcdgFile': rejected value [[object Object]]; codes [typeMismatch.zkdgwhEntity.kcdgFile,typeMismatch.kcdgFile,typeMismatch.org.springframework.web.multipart.MultipartFile,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [zkdgwhEntity.kcdgFile,kcdgFile]; arguments []; default message [kcdgFile]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'org.springframework.web.multipart.MultipartFile' for property 'kcdgFile'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'org.springframework.web.multipart.MultipartFile' for property 'kcdgFile': no matching editors or conversion strategy found]
3. 走过的弯路:
因为没有看到后台报的错误,就一直在前台找错误,查找netWork的header参数、给js打断点、console输出、json格式化都试过了,数据都没有问题,都可以获取到, 参数也都正确。
在其中发现了另一个问题,就是如果你的表单是上传的附件文件,因为他是byte格式的二进制流数据,所以,表单的提交万万不能使用 json 的数据格式往后台传数据,否则到了后台你接收到了是一个String类型的数据,毫无意义,上传会失败。
4. 本人本次具体原因:
本人因为赶工期,又是刚上手的新框,来不及学习,处处碰钉子,实际具体的原因是因为在实体类里面我建立了跟controller方法参数里面一样的接收参数,导致controller接收的时候接收不到,在entity实体类里面就已经被拦截了还没有走到controller方法的第一行代码,所以实际看上去就是代码走丢了。
实际方法的过程“应该”是这样的:从前端的代码跳往后太的时候,先寻找当前方法,然后注入方法的每个参数对象的具体值。然后在走到controller方法的参数中的实体类的时候,因为实体类里面有 MultipartFile 类型的试题,然后我前台又没有选择文件,而 MultipartFile 默认是不允许为空的,而我在controller方法里面也写了同样的 MultipartFile 类型的参数来接收,导致我漏掉了实体类里面的参数。
这么一个粗心的写法,让我浪费了大半天的时间,实在是,,,
特此记录一下。
5. 解决方式及实例代码:
你要使用 const formdata = new FormData(); 的form表单提交,后台使用post方式接收才可以,
前端代码:
const formdata = new FormData();
formdata.append("dgid",self.saveform.dgid);
if(self.file !== null){
formdata.append("kcdgFile", self.file);
};
$.ajax({
type: "POST",
url: baseUrl + 'zkdgwh/saveZkdgwhObj',
cache: false,
data: formdata,
processData: false,
contentType: false
}).done(function(res) {
if(res.code == 200){
self.$Message.success({
background: true,
duration: 5,
content: "保存成功"
});
setTimeout(function () {
window.location.href=baseUrl + 'zkdgwh/queryZkdgList';
},1600);
}else{
self.$Message.error({
background: true,
duration: 5,
content: "保存失败"
});
}
}).fail(function(res) {
self.$Message.error({
background: true,
duration: 5,
content: "服务器繁忙"
});
});
后端接收代码:
首先删除实体类里面的 MultipartFile 类型的字段值。
post表单方式提交数据:method = RequestMethod.POST
可控制是否必填的附件接收方式:@RequestParam(value="kcdgFile" ,required=false) MultipartFile kcdgFile
@RequestMapping(value = "saveZkdgwhObj" , method = RequestMethod.POST)
public ReturnT<String> saveZkdgwhObj(HttpServletRequest request, ZkdgwhEntity zkdgwhEnt,
@RequestParam(value="kcdgFile" ,required=false) MultipartFile kcdgFile){
try {
return zkdgwhService.saveZkdgwhObj(zkdgwhEnt,kcdgFile);
}catch (Exception e){
e.printStackTrace();
return ReturnT.FAIL;
}
}
一般这样的解决方式就可以解决问题了: