记一次图片前端传后端遇到的各种大坑。
先阐述几个难点 授人以鱼不如授人以渔 有则共勉,重点已加粗 文章最后再附上源码。
- 第一点就是打开电脑窗口 怎么实现按住ctrl可以多选文件: (注) accept : 接收类型; image/* : 所有类型图片; 重点 multiple: 多选
1. <input type=“file” @change=“getImgBase()” name=“file” accept=“image/*” multiple>
js部分:获取window事件 即打开windows窗口 及选中的文件
var event = event || window.event;
var fileList = event.target.files;
2.预览需要转base64 在相应代码处有注释
3.将选中的图片存入数组 再遍历存入到FormData()中 FormData.append(name,file)实现追加,name值可以为固定 不会被覆盖,FormData() 直接console.log 打印出来为空! 所以这就是错觉 formdata().append为空 以为没有成功追加,用FormData.getAll(“file”) 输出就能看到file了 (在文章代码中有体现)
4.同理 后端接收用 MultipartFile[] 也可能为空,需要设置请求头Content-Type:headers: {‘Content-Type’: ‘multipart/form-data’}, 在axios中 直接把这句写进去就可以了
5.通常至此就可以了,除非遇到像我一样的情况,设置请求头还可能为空,思考是不是不应该用MultipartFile[] 可是写HttpServletRequest,request里面也找不到file,那基本可以确定 东西就是没有传过来 和拿什么接收没有关系,因为只要传过来 原生servlet里面一定会有 框架等都是基于servlet封装 , 换句话说 哪怕不是springboot springmvc框架,java后端一样可以取到 ,去request里面取即可 debug看request里面内容。这里有个拓展 也是在完成之后发现的:
//MultipartFile[] file, HttpServletRequest request 两个参数2写1即可,
// MultipartFile就是集成了HttpServletRequest
public JSONObject updatePic(@RequestParam(value = "file",required = false) MultipartFile[] file, HttpServletRequest request)throws Exception{
}
6.言归正传,console.log FormData.getAll(“file”)里面是有东西的,说明是传输过程出错,再次确认, 设置了headers: {‘Content-Type’: ‘multipart/form-data’}, 但是按F12发现content-type 还是application/json,为什么设置无效?
终于发现有个细节:axios (文中代码已封装成this.api 其实是一样的) 里面写的是params:param 需要改成data:param。因为代码中采用的是post方式, params实际是添加到url请求字符串中,而data才是添加到请求体中,即:data对应post,params对应get, 改成data后F12发现content-type改成功了
file及request都有数据 有图有真相 只上传自己亲测有效的代码:
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
/**
* java部分
*/
@RestController
@RequestMapping("/picture")
public class PictureController {
@Autowired
private PictureService pictureService;
@RequestMapping("updatePic")
@Transactional(rollbackFor = Exception.class)
public JSONObject updatePic(@RequestParam(value = "file",required = false) MultipartFile[] file, HttpServletRequest request)throws Exception{
// 逻辑根据自己需要写 至此参数file已经能取到前端的传值
//pictureService.updatePic(file,request);
//return CommonUtil.successJson();
}
}
vue代码: 用的csdn js代码块上传的,识别有误 其实没有被注释 直接复制进vue里面就行了
<template>
<div class="app-container">
<div style="float: right;">
<el-button type="primary" icon="plus" @click="updatePic()">上传
</el-button>
</div>
<div class="image-view">
<el-form>
<el-form-item>
<div class="addbox">
<!-- accept : 接收类型; image/* : 所有类型图片; multiple: 多个 -->
<input type="file" @change="getImgBase()" name="file" accept="image/*" multiple>
<div class="addbtn">+</div>
<div class="texttips"> 添加图片</div>
</div>
</el-form-item>
</el-form>
<div class="view">
<div class="item" v-for="(item, index) in imgfilesPre">
<span class="cancel-btn" @click="delImg(index)">x</span>
<img :src="item">
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
imgfilesPre: [], // 图片预览地址
imgfiles: [], // 图片原文件,上传到后台的数据
}
},
methods: {
//获取图片base64实现预览
getImgBase() {
var _this = this;
var event = event || window.event;
var fileList = event.target.files;
let length = fileList.length;
for (let i = 0; i < length; i++) {
var reader = new FileReader();
_this.imgfiles.push(fileList[i]);
reader.readAsDataURL(fileList[i]);
//转base64 base 64 图片地址形成预览
reader.onload = function (e) {
_this.imgfilesPre.push(e.target.result);
};
}
// 防止不能连续选同一图片
event.target.value = "";
},
//删除图片
delImg(index) {
this.imgfilesPre.splice(index, 1);
},
// 上传图片至服务端
updatePic() {
var param = new FormData();
var length = this.imgfiles.length;
for (let i = 0; i < length; i++) {
let file = this.imgfiles[i];
console.log(file, file['name'])
param.append('file', file, file['name'])
}
console.log(param.getAll("file"))
this.listLoading = true;
this.api({
/*开启withCredentials后,服务器才能拿到cookie 跨域请求时是否需要使用凭证*/
withCredentials: true,
headers: {'Content-Type': 'multipart/form-data'},
url: '/picture/updatePic',
method: 'post',
data: param
})
},
}
}
</script>
<style scoped>
.image-view {
width: auto;
margin: 50px auto;
}
.image-view .addbox {
margin: 0 auto;
position: relative;
height: 100px;
width: 100px;
margin-bottom: 20px;
text-align: center;
}
.image-view .addbox input {
position: absolute;
height: 100px;
width: 100px;
opacity: 0;
text-align: center;
}
.image-view .addbox .addbtn {
height: 100px;
width: 100px;
line-height: 100px;
color: #fff;
font-size: 40px;
background: #ccc;
border-radius: 10px;
text-align: center;
}
.image-view .texttips {
color: #001528;
text-align: center;
}
.image-view .item {
position: relative;
float: left;
height: 100px;
width: 100px;
margin: 10px 10px 0 0;
}
.image-view .item .cancel-btn {
position: absolute;
right: 0;
top: 0;
display: block;
width: 20px;
height: 20px;
color: #fff;
line-height: 20px;
text-align: center;
background: red;
border-radius: 10px;
cursor: pointer;
}
.image-view .item img {
width: 100%;
height: 100%;
}
.image-view .view {
clear: both;
}
</style>